_ZN6Assimp19Discreet3DSImporter22ReplaceDefaultMaterialEv:
   63|      3|void Discreet3DSImporter::ReplaceDefaultMaterial() {
   64|       |    // Try to find an existing material that matches the
   65|       |    // typical default material setting:
   66|       |    // - no textures
   67|       |    // - diffuse color (in grey!)
   68|       |    // NOTE: This is here to work-around the fact that some
   69|       |    // exporters are writing a default material, too.
   70|      3|    unsigned int idx(NotSet);
   71|      9|    for (unsigned int i = 0; i < mScene->mMaterials.size(); ++i) {
  ------------------
  |  Branch (71:30): [True: 6, False: 3]
  ------------------
   72|      6|        auto s = mScene->mMaterials[i].mName;
   73|     58|        for (char &it : s) {
  ------------------
  |  Branch (73:23): [True: 58, False: 6]
  ------------------
   74|     58|            it = static_cast<char>(::tolower(static_cast<unsigned char>(it)));
   75|     58|        }
   76|       |
   77|      6|        if (std::string::npos == s.find("default")) {
  ------------------
  |  Branch (77:13): [True: 4, False: 2]
  ------------------
   78|      4|            continue;
   79|      4|        }
   80|       |
   81|      2|        if (mScene->mMaterials[i].mDiffuse.r !=
  ------------------
  |  Branch (81:13): [True: 0, False: 2]
  ------------------
   82|      2|                        mScene->mMaterials[i].mDiffuse.g ||
   83|      2|                mScene->mMaterials[i].mDiffuse.r !=
  ------------------
  |  Branch (83:17): [True: 0, False: 2]
  ------------------
   84|      2|                        mScene->mMaterials[i].mDiffuse.b) continue;
   85|       |
   86|      2|        if (ContainsTextures(i)) {
  ------------------
  |  Branch (86:13): [True: 0, False: 2]
  ------------------
   87|      0|            continue;
   88|      0|        }
   89|      2|        idx = i;
   90|      2|    }
   91|      3|    if (NotSet == idx) {
  ------------------
  |  Branch (91:9): [True: 1, False: 2]
  ------------------
   92|      1|        idx = static_cast<unsigned int>(mScene->mMaterials.size());
   93|      1|    }
   94|       |
   95|       |    // now iterate through all meshes and through all faces and
   96|       |    // find all faces that are using the default material
   97|      3|    unsigned int cnt = 0;
   98|      6|    for (auto i = mScene->mMeshes.begin(); i != mScene->mMeshes.end(); ++i) {
  ------------------
  |  Branch (98:44): [True: 3, False: 3]
  ------------------
   99|  2.90k|        for (auto a = i->mFaceMaterials.begin(); a != i->mFaceMaterials.end(); ++a) {
  ------------------
  |  Branch (99:50): [True: 2.90k, False: 3]
  ------------------
  100|       |            // NOTE: The additional check seems to be necessary,
  101|       |            // some exporters seem to generate invalid data here
  102|       |
  103|  2.90k|            if (NotSet == *a) {
  ------------------
  |  Branch (103:17): [True: 3, False: 2.90k]
  ------------------
  104|      3|                *a = idx;
  105|      3|                ++cnt;
  106|  2.90k|            } else if ((*a) >= mScene->mMaterials.size()) {
  ------------------
  |  Branch (106:24): [True: 0, False: 2.90k]
  ------------------
  107|      0|                *a = idx;
  108|      0|                ASSIMP_LOG_WARN("Material index overflow in 3DS file. Using default material");
  109|      0|                ++cnt;
  110|      0|            }
  111|  2.90k|        }
  112|      3|    }
  113|      3|    if (cnt && idx == mScene->mMaterials.size()) {
  ------------------
  |  Branch (113:9): [True: 1, False: 2]
  |  Branch (113:16): [True: 0, False: 1]
  ------------------
  114|       |        // We need to create our own default material
  115|      0|        Material sMat("%%%DEFAULT");
  116|      0|        sMat.mDiffuse = aiColor3D(0.3f, 0.3f, 0.3f);
  117|      0|        mScene->mMaterials.push_back(sMat);
  118|       |
  119|       |        ASSIMP_LOG_INFO("3DS: Generating default material");
  120|      0|    }
  121|      3|}
_ZN6Assimp19Discreet3DSImporter12CheckIndicesERNS_4D3DS4MeshE:
  125|      3|void Discreet3DSImporter::CheckIndices(Mesh &sMesh) {
  126|  2.90k|    for (auto i = sMesh.mFaces.begin(); i != sMesh.mFaces.end(); ++i) {
  ------------------
  |  Branch (126:41): [True: 2.90k, False: 3]
  ------------------
  127|       |        // check whether all indices are in range
  128|  11.6k|        for (unsigned int a = 0; a < 3; ++a) {
  ------------------
  |  Branch (128:34): [True: 8.71k, False: 2.90k]
  ------------------
  129|  8.71k|            if ((*i).mIndices[a] >= sMesh.mPositions.size()) {
  ------------------
  |  Branch (129:17): [True: 0, False: 8.71k]
  ------------------
  130|      0|                ASSIMP_LOG_WARN("3DS: Vertex index overflow)");
  131|      0|                (*i).mIndices[a] = static_cast<uint32_t>(sMesh.mPositions.size() - 1);
  132|      0|            }
  133|  8.71k|            if (!sMesh.mTexCoords.empty() && (*i).mIndices[a] >= sMesh.mTexCoords.size()) {
  ------------------
  |  Branch (133:17): [True: 0, False: 8.71k]
  |  Branch (133:46): [True: 0, False: 0]
  ------------------
  134|       |                ASSIMP_LOG_WARN("3DS: Texture coordinate index overflow)");
  135|      0|                (*i).mIndices[a] = static_cast<uint32_t>(sMesh.mTexCoords.size() - 1);
  136|      0|            }
  137|  8.71k|        }
  138|  2.90k|    }
  139|      3|}
_ZN6Assimp19Discreet3DSImporter10MakeUniqueERNS_4D3DS4MeshE:
  143|      3|void Discreet3DSImporter::MakeUnique(Mesh &sMesh) {
  144|       |    // TODO: really necessary? I don't think. Just a waste of memory and time
  145|       |    // to do it now in a separate buffer.
  146|       |
  147|       |    // Allocate output storage
  148|      3|    std::vector<aiVector3D> vNew(sMesh.mFaces.size() * 3);
  149|      3|    std::vector<aiVector3D> vNew2;
  150|      3|    if (sMesh.mTexCoords.size())
  ------------------
  |  Branch (150:9): [True: 0, False: 3]
  ------------------
  151|      0|        vNew2.resize(sMesh.mFaces.size() * 3);
  152|       |
  153|  2.90k|    for (unsigned int i = 0, base = 0; i < sMesh.mFaces.size(); ++i) {
  ------------------
  |  Branch (153:40): [True: 2.90k, False: 3]
  ------------------
  154|  2.90k|        Face &face = sMesh.mFaces[i];
  155|       |
  156|       |        // Positions
  157|  11.6k|        for (unsigned int a = 0; a < 3; ++a, ++base) {
  ------------------
  |  Branch (157:34): [True: 8.71k, False: 2.90k]
  ------------------
  158|  8.71k|            vNew[base] = sMesh.mPositions[face.mIndices[a]];
  159|  8.71k|            if (sMesh.mTexCoords.size())
  ------------------
  |  Branch (159:17): [True: 0, False: 8.71k]
  ------------------
  160|      0|                vNew2[base] = sMesh.mTexCoords[face.mIndices[a]];
  161|       |
  162|  8.71k|            face.mIndices[a] = base;
  163|  8.71k|        }
  164|  2.90k|    }
  165|      3|    sMesh.mPositions = vNew;
  166|      3|    sMesh.mTexCoords = vNew2;
  167|      3|}
_ZN6Assimp19Discreet3DSImporter15ConvertMaterialERNS_4D3DS8MaterialER10aiMaterial:
  200|      6|void Discreet3DSImporter::ConvertMaterial(Material &oldMat, aiMaterial &mat) {
  201|       |    // NOTE: Pass the background image to the viewer by bypassing the
  202|       |    // material system. This is an evil hack, never do it again!
  203|      6|    if (mBackgroundImage.empty() && bHasBG) {
  ------------------
  |  Branch (203:9): [True: 6, False: 0]
  |  Branch (203:37): [True: 0, False: 6]
  ------------------
  204|      0|        aiString tex(mBackgroundImage);
  205|      0|        mat.AddProperty(&tex, AI_MATKEY_GLOBAL_BACKGROUND_IMAGE);
  206|       |
  207|       |        // Be sure this is only done for the first material
  208|      0|        mBackgroundImage = std::string();
  209|      0|    }
  210|       |
  211|       |    // At first add the base ambient color of the scene to the material
  212|      6|    oldMat.mAmbient.r += mClrAmbient.r;
  213|      6|    oldMat.mAmbient.g += mClrAmbient.g;
  214|      6|    oldMat.mAmbient.b += mClrAmbient.b;
  215|       |
  216|      6|    aiString name(oldMat.mName);
  217|      6|    mat.AddProperty(&name, AI_MATKEY_NAME);
  218|       |
  219|       |    // Material colors
  220|      6|    mat.AddProperty(&oldMat.mAmbient, 1, AI_MATKEY_COLOR_AMBIENT);
  221|      6|    mat.AddProperty(&oldMat.mDiffuse, 1, AI_MATKEY_COLOR_DIFFUSE);
  222|      6|    mat.AddProperty(&oldMat.mSpecular, 1, AI_MATKEY_COLOR_SPECULAR);
  223|      6|    mat.AddProperty(&oldMat.mEmissive, 1, AI_MATKEY_COLOR_EMISSIVE);
  224|       |
  225|       |    // Phong shininess and shininess strength
  226|      6|    if (Discreet3DS::Phong == oldMat.mShading || Discreet3DS::Metal == oldMat.mShading) {
  ------------------
  |  Branch (226:9): [True: 6, False: 0]
  |  Branch (226:50): [True: 0, False: 0]
  ------------------
  227|      6|        if (!oldMat.mSpecularExponent || !oldMat.mShininessStrength) {
  ------------------
  |  Branch (227:13): [True: 0, False: 6]
  |  Branch (227:42): [True: 0, False: 6]
  ------------------
  228|      0|            oldMat.mShading = Discreet3DS::Gouraud;
  229|      6|        } else {
  230|      6|            mat.AddProperty(&oldMat.mSpecularExponent, 1, AI_MATKEY_SHININESS);
  231|      6|            mat.AddProperty(&oldMat.mShininessStrength, 1, AI_MATKEY_SHININESS_STRENGTH);
  232|      6|        }
  233|      6|    }
  234|       |
  235|       |    // Opacity
  236|      6|    mat.AddProperty<ai_real>(&oldMat.mTransparency, 1, AI_MATKEY_OPACITY);
  237|       |
  238|       |    // Bump height scaling
  239|      6|    mat.AddProperty<ai_real>(&oldMat.mBumpHeight, 1, AI_MATKEY_BUMPSCALING);
  240|       |
  241|       |    // Two sided rendering?
  242|      6|    if (oldMat.mTwoSided) {
  ------------------
  |  Branch (242:9): [True: 0, False: 6]
  ------------------
  243|      0|        int i = 1;
  244|      0|        mat.AddProperty<int>(&i, 1, AI_MATKEY_TWOSIDED);
  245|      0|    }
  246|       |
  247|       |    // Shading mode
  248|      6|    aiShadingMode eShading = aiShadingMode_NoShading;
  249|      6|    switch (oldMat.mShading) {
  ------------------
  |  Branch (249:13): [True: 6, False: 0]
  ------------------
  250|      0|    case Discreet3DS::Flat:
  ------------------
  |  Branch (250:5): [True: 0, False: 6]
  ------------------
  251|      0|        eShading = aiShadingMode_Flat;
  252|      0|        break;
  253|       |
  254|       |    // I don't know what "Wire" shading should be,
  255|       |    // assume it is simple lambertian diffuse shading
  256|      0|    case Discreet3DS::Wire: {
  ------------------
  |  Branch (256:5): [True: 0, False: 6]
  ------------------
  257|       |        // Set the wireframe flag
  258|      0|        unsigned int iWire = 1;
  259|      0|        mat.AddProperty<int>((int *)&iWire, 1, AI_MATKEY_ENABLE_WIREFRAME);
  260|      0|    }
  261|      0|        [[fallthrough]];
  262|       |
  263|      0|    case Discreet3DS::Gouraud:
  ------------------
  |  Branch (263:5): [True: 0, False: 6]
  ------------------
  264|      0|        eShading = aiShadingMode_Gouraud;
  265|      0|        break;
  266|       |
  267|       |    // assume cook-torrance shading for metals.
  268|      6|    case Discreet3DS::Phong:
  ------------------
  |  Branch (268:5): [True: 6, False: 0]
  ------------------
  269|      6|        eShading = aiShadingMode_Phong;
  270|      6|        break;
  271|       |
  272|      0|    case Discreet3DS::Metal:
  ------------------
  |  Branch (272:5): [True: 0, False: 6]
  ------------------
  273|      0|        eShading = aiShadingMode_CookTorrance;
  274|      0|        break;
  275|       |
  276|       |        // FIX to workaround a warning with GCC 4 who complained
  277|       |        // about a missing case Blinn: here - Blinn isn't a valid
  278|       |        // value in the 3DS Loader, it is just needed for ASE
  279|      0|    case Discreet3DS::Blinn:
  ------------------
  |  Branch (279:5): [True: 0, False: 6]
  ------------------
  280|      0|        eShading = aiShadingMode_Blinn;
  281|      0|        break;
  282|      6|    }
  283|       |
  284|      6|    const int eShading_ = eShading;
  285|      6|    mat.AddProperty<int>(&eShading_, 1, AI_MATKEY_SHADING_MODEL);
  286|       |
  287|       |    // DIFFUSE texture
  288|      6|    if (oldMat.sTexDiffuse.mMapName.length() > 0)
  ------------------
  |  Branch (288:9): [True: 0, False: 6]
  ------------------
  289|      0|        CopyTexture(mat, oldMat.sTexDiffuse, aiTextureType_DIFFUSE);
  290|       |
  291|       |    // SPECULAR texture
  292|      6|    if (oldMat.sTexSpecular.mMapName.length() > 0)
  ------------------
  |  Branch (292:9): [True: 0, False: 6]
  ------------------
  293|      0|        CopyTexture(mat, oldMat.sTexSpecular, aiTextureType_SPECULAR);
  294|       |
  295|       |    // OPACITY texture
  296|      6|    if (oldMat.sTexOpacity.mMapName.length() > 0)
  ------------------
  |  Branch (296:9): [True: 0, False: 6]
  ------------------
  297|      0|        CopyTexture(mat, oldMat.sTexOpacity, aiTextureType_OPACITY);
  298|       |
  299|       |    // EMISSIVE texture
  300|      6|    if (oldMat.sTexEmissive.mMapName.length() > 0)
  ------------------
  |  Branch (300:9): [True: 0, False: 6]
  ------------------
  301|      0|        CopyTexture(mat, oldMat.sTexEmissive, aiTextureType_EMISSIVE);
  302|       |
  303|       |    // BUMP texture
  304|      6|    if (oldMat.sTexBump.mMapName.length() > 0)
  ------------------
  |  Branch (304:9): [True: 0, False: 6]
  ------------------
  305|      0|        CopyTexture(mat, oldMat.sTexBump, aiTextureType_HEIGHT);
  306|       |
  307|       |    // SHININESS texture
  308|      6|    if (oldMat.sTexShininess.mMapName.length() > 0)
  ------------------
  |  Branch (308:9): [True: 0, False: 6]
  ------------------
  309|      0|        CopyTexture(mat, oldMat.sTexShininess, aiTextureType_SHININESS);
  310|       |
  311|       |    // REFLECTION texture
  312|      6|    if (oldMat.sTexReflective.mMapName.length() > 0)
  ------------------
  |  Branch (312:9): [True: 0, False: 6]
  ------------------
  313|      0|        CopyTexture(mat, oldMat.sTexReflective, aiTextureType_REFLECTION);
  314|       |
  315|       |    // Store the name of the material itself, too
  316|      6|    if (oldMat.mName.length()) {
  ------------------
  |  Branch (316:9): [True: 6, False: 0]
  ------------------
  317|      6|        aiString tex;
  318|      6|        tex.Set(oldMat.mName);
  319|       |        mat.AddProperty(&tex, AI_MATKEY_NAME);
  320|      6|    }
  321|      6|}
_ZN6Assimp19Discreet3DSImporter13ConvertMeshesEP7aiScene:
  325|      3|void Discreet3DSImporter::ConvertMeshes(aiScene *pcOut) {
  326|      3|    std::vector<aiMesh *> avOutMeshes;
  327|      3|    avOutMeshes.reserve(mScene->mMeshes.size() * 2);
  328|       |
  329|      3|    unsigned int iFaceCnt = 0, num = 0;
  330|      3|    aiString name;
  331|       |
  332|       |    // we need to split all meshes by their materials
  333|      6|    for (auto i = mScene->mMeshes.begin(); i != mScene->mMeshes.end(); ++i) {
  ------------------
  |  Branch (333:44): [True: 3, False: 3]
  ------------------
  334|      3|        std::unique_ptr<std::vector<unsigned int>[]> aiSplit(new std::vector<unsigned int>[mScene->mMaterials.size()]);
  335|       |
  336|      3|        name.length = ASSIMP_itoa10(name.data, num);
  337|      3|        ++num;
  338|       |
  339|      3|        unsigned int iNum = 0;
  340|      3|        for (std::vector<unsigned int>::const_iterator a = (*i).mFaceMaterials.begin();
  341|  2.90k|                a != (*i).mFaceMaterials.end(); ++a, ++iNum) {
  ------------------
  |  Branch (341:17): [True: 2.90k, False: 3]
  ------------------
  342|  2.90k|            aiSplit[*a].push_back(iNum);
  343|  2.90k|        }
  344|       |        // now generate submeshes
  345|      9|        for (unsigned int p = 0; p < mScene->mMaterials.size(); ++p) {
  ------------------
  |  Branch (345:34): [True: 6, False: 3]
  ------------------
  346|      6|            if (aiSplit[p].empty()) {
  ------------------
  |  Branch (346:17): [True: 0, False: 6]
  ------------------
  347|      0|                continue;
  348|      0|            }
  349|      6|            auto *meshOut = new aiMesh();
  350|      6|            meshOut->mName = name;
  351|      6|            meshOut->mPrimitiveTypes = aiPrimitiveType_TRIANGLE;
  352|       |
  353|       |            // be sure to setup the correct material index
  354|      6|            meshOut->mMaterialIndex = p;
  355|       |
  356|       |            // use the color data as temporary storage
  357|      6|            meshOut->mColors[0] = (aiColor4D *)(&*i);
  358|      6|            avOutMeshes.push_back(meshOut);
  359|       |
  360|       |            // convert vertices
  361|      6|            meshOut->mNumFaces = static_cast<unsigned int>(aiSplit[p].size());
  362|      6|            meshOut->mNumVertices = meshOut->mNumFaces * 3;
  363|       |
  364|       |            // allocate enough storage for faces
  365|      6|            meshOut->mFaces = new aiFace[meshOut->mNumFaces];
  366|      6|            iFaceCnt += meshOut->mNumFaces;
  367|       |
  368|      6|            meshOut->mVertices = new aiVector3D[meshOut->mNumVertices];
  369|      6|            meshOut->mNormals = new aiVector3D[meshOut->mNumVertices];
  370|      6|            if ((*i).mTexCoords.size()) {
  ------------------
  |  Branch (370:17): [True: 0, False: 6]
  ------------------
  371|      0|                meshOut->mTextureCoords[0] = new aiVector3D[meshOut->mNumVertices];
  372|      0|            }
  373|  2.91k|            for (unsigned int q = 0, base = 0; q < aiSplit[p].size(); ++q) {
  ------------------
  |  Branch (373:48): [True: 2.90k, False: 6]
  ------------------
  374|  2.90k|                unsigned int index = aiSplit[p][q];
  375|  2.90k|                aiFace &face = meshOut->mFaces[q];
  376|       |
  377|  2.90k|                face.mIndices = new unsigned int[3];
  378|  2.90k|                face.mNumIndices = 3;
  379|       |
  380|  11.6k|                for (unsigned int a = 0; a < 3; ++a, ++base) {
  ------------------
  |  Branch (380:42): [True: 8.71k, False: 2.90k]
  ------------------
  381|  8.71k|                    unsigned int idx = (*i).mFaces[index].mIndices[a];
  382|  8.71k|                    meshOut->mVertices[base] = (*i).mPositions[idx];
  383|  8.71k|                    meshOut->mNormals[base] = (*i).mNormals[idx];
  384|       |
  385|  8.71k|                    if ((*i).mTexCoords.size())
  ------------------
  |  Branch (385:25): [True: 0, False: 8.71k]
  ------------------
  386|      0|                        meshOut->mTextureCoords[0][base] = (*i).mTexCoords[idx];
  387|       |
  388|  8.71k|                    face.mIndices[a] = base;
  389|  8.71k|                }
  390|  2.90k|            }
  391|      6|        }
  392|      3|    }
  393|       |
  394|       |    // Copy them to the output array
  395|      3|    pcOut->mNumMeshes = (unsigned int)avOutMeshes.size();
  396|      3|    pcOut->mMeshes = new aiMesh *[pcOut->mNumMeshes]();
  397|      9|    for (unsigned int a = 0; a < pcOut->mNumMeshes; ++a) {
  ------------------
  |  Branch (397:30): [True: 6, False: 3]
  ------------------
  398|      6|        pcOut->mMeshes[a] = avOutMeshes[a];
  399|      6|    }
  400|       |
  401|       |    // We should have at least one face here
  402|      3|    if (!iFaceCnt) {
  ------------------
  |  Branch (402:9): [True: 0, False: 3]
  ------------------
  403|      0|        throw DeadlyImportError("No faces loaded. The mesh is empty");
  404|      0|    }
  405|      3|}
_ZN6Assimp19Discreet3DSImporter14AddNodeToGraphEP7aiSceneP6aiNodePNS_4D3DS4NodeER12aiMatrix4x4tIfE:
  409|      2|void Discreet3DSImporter::AddNodeToGraph(aiScene *pcSOut, aiNode *pcOut, D3DS::Node *pcIn, aiMatrix4x4 & /*absTrafo*/) {
  410|      2|    std::vector<unsigned int> iArray;
  411|      2|    iArray.reserve(3);
  412|       |
  413|      2|    aiMatrix4x4 abs;
  414|       |
  415|       |    // Find all meshes with the same name as the node
  416|     10|    for (unsigned int a = 0; a < pcSOut->mNumMeshes; ++a) {
  ------------------
  |  Branch (416:30): [True: 8, False: 2]
  ------------------
  417|      8|        const auto *pcMesh = (const D3DS::Mesh *)pcSOut->mMeshes[a]->mColors[0];
  418|      8|        ai_assert(nullptr != pcMesh);
  419|       |
  420|      8|        if (pcIn->mName == pcMesh->mName)
  ------------------
  |  Branch (420:13): [True: 4, False: 4]
  ------------------
  421|      4|            iArray.push_back(a);
  422|      8|    }
  423|      2|    if (!iArray.empty()) {
  ------------------
  |  Branch (423:9): [True: 1, False: 1]
  ------------------
  424|       |        // The matrix should be identical for all meshes with the
  425|       |        // same name. It HAS to be identical for all meshes .....
  426|      1|        auto *imesh = ((D3DS::Mesh *)pcSOut->mMeshes[iArray[0]]->mColors[0]);
  427|       |
  428|       |        // Compute the inverse of the transformation matrix to move the
  429|       |        // vertices back to their relative and local space
  430|      1|        aiMatrix4x4 mInv = imesh->mMat, mInvTransposed = imesh->mMat;
  431|      1|        mInv.Inverse();
  432|      1|        mInvTransposed.Transpose();
  433|      1|        aiVector3D pivot = pcIn->vPivot;
  434|       |
  435|      1|        pcOut->mNumMeshes = static_cast<unsigned int>(iArray.size());
  436|      1|        pcOut->mMeshes = new unsigned int[iArray.size()];
  437|      5|        for (unsigned int i = 0; i < iArray.size(); ++i) {
  ------------------
  |  Branch (437:34): [True: 4, False: 1]
  ------------------
  438|      4|            const unsigned int iIndex = iArray[i];
  439|      4|            aiMesh *const mesh = pcSOut->mMeshes[iIndex];
  440|       |
  441|      4|            if (mesh->mColors[1] == nullptr) {
  ------------------
  |  Branch (441:17): [True: 4, False: 0]
  ------------------
  442|       |                // Transform the vertices back into their local space
  443|       |                // fixme: consider computing normals after this, so we don't need to transform them
  444|      4|                const aiVector3D *const pvEnd = mesh->mVertices + mesh->mNumVertices;
  445|      4|                aiVector3D *pvCurrent = mesh->mVertices, *t2 = mesh->mNormals;
  446|       |
  447|  4.10k|                for (; pvCurrent != pvEnd; ++pvCurrent, ++t2) {
  ------------------
  |  Branch (447:24): [True: 4.10k, False: 4]
  ------------------
  448|  4.10k|                    *pvCurrent = mInv * (*pvCurrent);
  449|  4.10k|                    *t2 = mInvTransposed * (*t2);
  450|  4.10k|                }
  451|       |
  452|       |                // Handle negative transformation matrix determinant -> invert vertex x
  453|      4|                if (imesh->mMat.Determinant() < 0.0f) {
  ------------------
  |  Branch (453:21): [True: 0, False: 4]
  ------------------
  454|       |                    // we *must* have normals
  455|      0|                    for (pvCurrent = mesh->mVertices, t2 = mesh->mNormals; pvCurrent != pvEnd; ++pvCurrent, ++t2) {
  ------------------
  |  Branch (455:76): [True: 0, False: 0]
  ------------------
  456|      0|                        pvCurrent->x *= -1.f;
  457|      0|                        t2->x *= -1.f;
  458|      0|                    }
  459|      0|                    ASSIMP_LOG_INFO("3DS: Flipping mesh X-Axis");
  460|      0|                }
  461|       |
  462|       |                // Handle pivot point
  463|      4|                if (pivot.x || pivot.y || pivot.z) {
  ------------------
  |  Branch (463:21): [True: 0, False: 4]
  |  Branch (463:32): [True: 0, False: 4]
  |  Branch (463:43): [True: 0, False: 4]
  ------------------
  464|      0|                    for (pvCurrent = mesh->mVertices; pvCurrent != pvEnd; ++pvCurrent) {
  ------------------
  |  Branch (464:55): [True: 0, False: 0]
  ------------------
  465|      0|                        *pvCurrent -= pivot;
  466|      0|                    }
  467|      0|                }
  468|       |
  469|      4|                mesh->mColors[1] = (aiColor4D *)1;
  470|      4|            } else
  471|      0|                mesh->mColors[1] = (aiColor4D *)1;
  472|       |
  473|       |            // Setup the mesh index
  474|      4|            pcOut->mMeshes[i] = iIndex;
  475|      4|        }
  476|      1|    }
  477|       |
  478|       |    // Setup the name of the node
  479|       |    // First instance keeps its name otherwise something might break, all others will be postfixed with their instance number
  480|      2|    if (pcIn->mInstanceNumber > 1) {
  ------------------
  |  Branch (480:9): [True: 0, False: 2]
  ------------------
  481|      0|        char tmp[12] = {'\0'};
  482|      0|        ASSIMP_itoa10(tmp, pcIn->mInstanceNumber);
  483|      0|        std::string tempStr = pcIn->mName + "_inst_";
  484|      0|        tempStr += tmp;
  485|      0|        pcOut->mName.Set(tempStr);
  486|      0|    } else
  487|      2|        pcOut->mName.Set(pcIn->mName);
  488|       |
  489|       |    // Now build the transformation matrix of the node
  490|       |    // ROTATION
  491|      2|    if (pcIn->aRotationKeys.size()) {
  ------------------
  |  Branch (491:9): [True: 1, False: 1]
  ------------------
  492|       |
  493|       |        // FIX to get to Assimp's quaternion conventions
  494|      2|        for (auto it = pcIn->aRotationKeys.begin(); it != pcIn->aRotationKeys.end(); ++it) {
  ------------------
  |  Branch (494:53): [True: 1, False: 1]
  ------------------
  495|      1|            (*it).mValue.w *= -1.f;
  496|      1|        }
  497|       |
  498|      1|        pcOut->mTransformation = aiMatrix4x4(pcIn->aRotationKeys[0].mValue.GetMatrix());
  499|      1|    } else if (pcIn->aCameraRollKeys.size()) {
  ------------------
  |  Branch (499:16): [True: 0, False: 1]
  ------------------
  500|      0|        aiMatrix4x4::RotationZ(AI_DEG_TO_RAD(-pcIn->aCameraRollKeys[0].mValue),
  501|      0|                pcOut->mTransformation);
  502|      0|    }
  503|       |
  504|       |    // SCALING
  505|      2|    aiMatrix4x4 &m = pcOut->mTransformation;
  506|      2|    if (pcIn->aScalingKeys.size()) {
  ------------------
  |  Branch (506:9): [True: 1, False: 1]
  ------------------
  507|      1|        const aiVector3D &v = pcIn->aScalingKeys[0].mValue;
  508|      1|        m.a1 *= v.x;
  509|      1|        m.b1 *= v.x;
  510|      1|        m.c1 *= v.x;
  511|      1|        m.a2 *= v.y;
  512|      1|        m.b2 *= v.y;
  513|      1|        m.c2 *= v.y;
  514|      1|        m.a3 *= v.z;
  515|      1|        m.b3 *= v.z;
  516|      1|        m.c3 *= v.z;
  517|      1|    }
  518|       |
  519|       |    // TRANSLATION
  520|      2|    if (pcIn->aPositionKeys.size()) {
  ------------------
  |  Branch (520:9): [True: 1, False: 1]
  ------------------
  521|      1|        const aiVector3D &v = pcIn->aPositionKeys[0].mValue;
  522|      1|        m.a4 += v.x;
  523|      1|        m.b4 += v.y;
  524|      1|        m.c4 += v.z;
  525|      1|    }
  526|       |
  527|       |    // Generate animation channels for the node
  528|      2|    if (pcIn->aPositionKeys.size() > 1 || pcIn->aRotationKeys.size() > 1 ||
  ------------------
  |  Branch (528:9): [True: 0, False: 2]
  |  Branch (528:43): [True: 0, False: 2]
  ------------------
  529|      2|            pcIn->aScalingKeys.size() > 1 || pcIn->aCameraRollKeys.size() > 1 ||
  ------------------
  |  Branch (529:13): [True: 0, False: 2]
  |  Branch (529:46): [True: 0, False: 2]
  ------------------
  530|      2|            pcIn->aTargetPositionKeys.size() > 1) {
  ------------------
  |  Branch (530:13): [True: 0, False: 2]
  ------------------
  531|      0|        aiAnimation *anim = pcSOut->mAnimations[0];
  532|      0|        ai_assert(nullptr != anim);
  533|       |
  534|      0|        if (pcIn->aCameraRollKeys.size() > 1) {
  ------------------
  |  Branch (534:13): [True: 0, False: 0]
  ------------------
  535|      0|            ASSIMP_LOG_VERBOSE_DEBUG("3DS: Converting camera roll track ...");
  536|       |
  537|       |            // Camera roll keys - in fact they're just rotations
  538|       |            // around the camera's z axis. The angles are given
  539|       |            // in degrees (and they're clockwise).
  540|      0|            pcIn->aRotationKeys.resize(pcIn->aCameraRollKeys.size());
  541|      0|            for (unsigned int i = 0; i < pcIn->aCameraRollKeys.size(); ++i) {
  ------------------
  |  Branch (541:38): [True: 0, False: 0]
  ------------------
  542|      0|                aiQuatKey &q = pcIn->aRotationKeys[i];
  543|      0|                aiFloatKey &f = pcIn->aCameraRollKeys[i];
  544|       |
  545|      0|                q.mTime = f.mTime;
  546|       |
  547|       |                // FIX to get to Assimp quaternion conventions
  548|      0|                q.mValue = aiQuaternion(0.f, 0.f, AI_DEG_TO_RAD(/*-*/ f.mValue));
  549|      0|            }
  550|      0|        }
  551|       |#if 0
  552|       |        if (pcIn->aTargetPositionKeys.size() > 1)
  553|       |        {
  554|       |            ASSIMP_LOG_VERBOSE_DEBUG("3DS: Converting target track ...");
  555|       |
  556|       |            // Camera or spot light - need to convert the separate
  557|       |            // target position channel to our representation
  558|       |            TargetAnimationHelper helper;
  559|       |
  560|       |            if (pcIn->aPositionKeys.empty())
  561|       |            {
  562|       |                // We can just pass zero here ...
  563|       |                helper.SetFixedMainAnimationChannel(aiVector3D());
  564|       |            }
  565|       |            else  helper.SetMainAnimationChannel(&pcIn->aPositionKeys);
  566|       |            helper.SetTargetAnimationChannel(&pcIn->aTargetPositionKeys);
  567|       |
  568|       |            // Do the conversion
  569|       |            std::vector<aiVectorKey> distanceTrack;
  570|       |            helper.Process(&distanceTrack);
  571|       |
  572|       |            // Now add a new node as child, name it <ourName>.Target
  573|       |            // and assign the distance track to it. This is that the
  574|       |            // information where the target is and how it moves is
  575|       |            // not lost
  576|       |            D3DS::Node* nd = new D3DS::Node();
  577|       |            pcIn->push_back(nd);
  578|       |
  579|       |            nd->mName = pcIn->mName + ".Target";
  580|       |
  581|       |            aiNodeAnim* nda = anim->mChannels[anim->mNumChannels++] = new aiNodeAnim();
  582|       |            nda->mNodeName.Set(nd->mName);
  583|       |
  584|       |            nda->mNumPositionKeys = (unsigned int)distanceTrack.size();
  585|       |            nda->mPositionKeys = new aiVectorKey[nda->mNumPositionKeys];
  586|       |            ::memcpy(nda->mPositionKeys,&distanceTrack[0],
  587|       |                sizeof(aiVectorKey)*nda->mNumPositionKeys);
  588|       |        }
  589|       |#endif
  590|       |
  591|       |        // Cameras or lights define their transformation in their parent node and in the
  592|       |        // corresponding light or camera chunks. However, we read and process the latter
  593|       |        // to be able to return valid cameras/lights even if no scenegraph is given.
  594|      0|        for (unsigned int n = 0; n < pcSOut->mNumCameras; ++n) {
  ------------------
  |  Branch (594:34): [True: 0, False: 0]
  ------------------
  595|      0|            if (pcSOut->mCameras[n]->mName == pcOut->mName) {
  ------------------
  |  Branch (595:17): [True: 0, False: 0]
  ------------------
  596|      0|                pcSOut->mCameras[n]->mLookAt = aiVector3D(0.f, 0.f, 1.f);
  597|      0|            }
  598|      0|        }
  599|      0|        for (unsigned int n = 0; n < pcSOut->mNumLights; ++n) {
  ------------------
  |  Branch (599:34): [True: 0, False: 0]
  ------------------
  600|      0|            if (pcSOut->mLights[n]->mName == pcOut->mName) {
  ------------------
  |  Branch (600:17): [True: 0, False: 0]
  ------------------
  601|      0|                pcSOut->mLights[n]->mDirection = aiVector3D(0.f, 0.f, 1.f);
  602|      0|            }
  603|      0|        }
  604|       |
  605|       |        // Allocate a new node anim and setup its name
  606|      0|        auto *nda = anim->mChannels[anim->mNumChannels++] = new aiNodeAnim();
  607|      0|        nda->mNodeName.Set(pcIn->mName);
  608|       |
  609|       |        // POSITION keys
  610|      0|        if (!pcIn->aPositionKeys.empty()) {
  ------------------
  |  Branch (610:13): [True: 0, False: 0]
  ------------------
  611|      0|            nda->mNumPositionKeys = (unsigned int)pcIn->aPositionKeys.size();
  612|      0|            nda->mPositionKeys = new aiVectorKey[nda->mNumPositionKeys];
  613|      0|            ::memcpy(nda->mPositionKeys, &pcIn->aPositionKeys[0],
  614|      0|                    sizeof(aiVectorKey) * nda->mNumPositionKeys);
  615|      0|        }
  616|       |
  617|       |        // ROTATION keys
  618|      0|        if (!pcIn->aRotationKeys.empty()) {
  ------------------
  |  Branch (618:13): [True: 0, False: 0]
  ------------------
  619|      0|            nda->mNumRotationKeys = (unsigned int)pcIn->aRotationKeys.size();
  620|      0|            nda->mRotationKeys = new aiQuatKey[nda->mNumRotationKeys];
  621|       |
  622|       |            // Rotations are quaternion offsets
  623|      0|            aiQuaternion abs1;
  624|      0|            for (unsigned int n = 0; n < nda->mNumRotationKeys; ++n) {
  ------------------
  |  Branch (624:38): [True: 0, False: 0]
  ------------------
  625|      0|                const aiQuatKey &q = pcIn->aRotationKeys[n];
  626|       |
  627|      0|                abs1 = (n ? abs1 * q.mValue : q.mValue);
  ------------------
  |  Branch (627:25): [True: 0, False: 0]
  ------------------
  628|      0|                nda->mRotationKeys[n].mTime = q.mTime;
  629|      0|                nda->mRotationKeys[n].mValue = abs1.Normalize();
  630|      0|            }
  631|      0|        }
  632|       |
  633|       |        // SCALING keys
  634|      0|        if (!pcIn->aScalingKeys.empty()) {
  ------------------
  |  Branch (634:13): [True: 0, False: 0]
  ------------------
  635|      0|            nda->mNumScalingKeys = (unsigned int)pcIn->aScalingKeys.size();
  636|      0|            nda->mScalingKeys = new aiVectorKey[nda->mNumScalingKeys];
  637|      0|            ::memcpy(nda->mScalingKeys, &pcIn->aScalingKeys[0],
  638|      0|                    sizeof(aiVectorKey) * nda->mNumScalingKeys);
  639|      0|        }
  640|      0|    }
  641|       |
  642|       |    // Allocate storage for children
  643|      2|    const auto size = static_cast<unsigned int>(pcIn->mChildren.size());
  644|       |
  645|      2|    pcOut->mNumChildren = size;
  646|      2|    if (size == 0) {
  ------------------
  |  Branch (646:9): [True: 1, False: 1]
  ------------------
  647|      1|        return;
  648|      1|    }
  649|       |
  650|      1|    pcOut->mChildren = new aiNode *[pcIn->mChildren.size()];
  651|       |
  652|       |    // Recursively process all children
  653|       |
  654|      2|    for (unsigned int i = 0; i < size; ++i) {
  ------------------
  |  Branch (654:30): [True: 1, False: 1]
  ------------------
  655|      1|        pcOut->mChildren[i] = new aiNode();
  656|      1|        pcOut->mChildren[i]->mParent = pcOut;
  657|      1|        AddNodeToGraph(pcSOut, pcOut->mChildren[i], pcIn->mChildren[i], abs);
  658|      1|    }
  659|      1|}
_ZN6Assimp11CountTracksEPNS_4D3DS4NodeERj:
  663|      2|void CountTracks(D3DS::Node *node, unsigned int &cnt) {
  664|       |    //////////////////////////////////////////////////////////////////////////////
  665|       |    // We will never generate more than one channel for a node, so
  666|       |    // this is rather easy here.
  667|       |
  668|      2|    if (node->aPositionKeys.size() > 1 || node->aRotationKeys.size() > 1 ||
  ------------------
  |  Branch (668:9): [True: 0, False: 2]
  |  Branch (668:43): [True: 0, False: 2]
  ------------------
  669|      2|            node->aScalingKeys.size() > 1 || node->aCameraRollKeys.size() > 1 ||
  ------------------
  |  Branch (669:13): [True: 0, False: 2]
  |  Branch (669:46): [True: 0, False: 2]
  ------------------
  670|      2|            node->aTargetPositionKeys.size() > 1) {
  ------------------
  |  Branch (670:13): [True: 0, False: 2]
  ------------------
  671|      0|        ++cnt;
  672|       |
  673|       |        // account for the additional channel for the camera/spotlight target position
  674|      0|        if (node->aTargetPositionKeys.size() > 1) ++cnt;
  ------------------
  |  Branch (674:13): [True: 0, False: 0]
  ------------------
  675|      0|    }
  676|       |
  677|       |    // Recursively process all children
  678|      3|    for (unsigned int i = 0; i < node->mChildren.size(); ++i)
  ------------------
  |  Branch (678:30): [True: 1, False: 2]
  ------------------
  679|      1|        CountTracks(node->mChildren[i], cnt);
  680|      2|}
_ZN6Assimp19Discreet3DSImporter17GenerateNodeGraphEP7aiScene:
  684|      3|void Discreet3DSImporter::GenerateNodeGraph(aiScene *pcOut) {
  685|      3|    pcOut->mRootNode = new aiNode();
  686|      3|    if (mRootNode->mChildren.empty()) {
  ------------------
  |  Branch (686:9): [True: 2, False: 1]
  ------------------
  687|       |        //////////////////////////////////////////////////////////////////////////////
  688|       |        // It seems the file is so messed up that it has not even a hierarchy.
  689|       |        // generate a flat hiearachy which looks like this:
  690|       |        //
  691|       |        //                ROOT_NODE
  692|       |        //                   |
  693|       |        //   ----------------------------------------
  694|       |        //   |       |       |            |         |
  695|       |        // MESH_0  MESH_1  MESH_2  ...  MESH_N    CAMERA_0 ....
  696|       |        //
  697|      2|        ASSIMP_LOG_WARN("No hierarchy information has been found in the file. ");
  698|       |
  699|      2|        pcOut->mRootNode->mNumChildren = pcOut->mNumMeshes +
  700|      2|                                         static_cast<unsigned int>(mScene->mCameras.size() + mScene->mLights.size());
  701|       |
  702|      2|        pcOut->mRootNode->mChildren = new aiNode *[pcOut->mRootNode->mNumChildren];
  703|      2|        pcOut->mRootNode->mName.Set("<3DSDummyRoot>");
  704|       |
  705|       |        // Build dummy nodes for all meshes
  706|      2|        unsigned int a = 0;
  707|      4|        for (unsigned int i = 0; i < pcOut->mNumMeshes; ++i, ++a) {
  ------------------
  |  Branch (707:34): [True: 2, False: 2]
  ------------------
  708|      2|            pcOut->mRootNode->mChildren[a] = new aiNode();  
  709|      2|            auto *pcNode = pcOut->mRootNode->mChildren[a];
  710|      2|            pcNode->mParent = pcOut->mRootNode;
  711|      2|            pcNode->mMeshes = new unsigned int[1];
  712|      2|            pcNode->mMeshes[0] = i;
  713|      2|            pcNode->mNumMeshes = 1;
  714|       |
  715|       |            // Build a name for the node
  716|      2|            pcNode->mName.length = ai_snprintf(pcNode->mName.data, AI_MAXLEN, "3DSMesh_%u", i);
  717|      2|        }
  718|       |
  719|       |        // Build dummy nodes for all cameras
  720|      2|        for (unsigned int i = 0; i < (unsigned int)mScene->mCameras.size(); ++i, ++a) {
  ------------------
  |  Branch (720:34): [True: 0, False: 2]
  ------------------
  721|      0|            auto *pcNode = pcOut->mRootNode->mChildren[a] = new aiNode();
  722|      0|            pcNode->mParent = pcOut->mRootNode;
  723|       |
  724|       |            // Build a name for the node
  725|      0|            pcNode->mName = mScene->mCameras[i]->mName;
  726|      0|        }
  727|       |
  728|       |        // Build dummy nodes for all lights
  729|      2|        for (unsigned int i = 0; i < (unsigned int)mScene->mLights.size(); ++i, ++a) {
  ------------------
  |  Branch (729:34): [True: 0, False: 2]
  ------------------
  730|      0|            auto *pcNode = pcOut->mRootNode->mChildren[a] = new aiNode();
  731|      0|            pcNode->mParent = pcOut->mRootNode;
  732|       |
  733|       |            // Build a name for the node
  734|      0|            pcNode->mName = mScene->mLights[i]->mName;
  735|      0|        }
  736|      2|    } else {
  737|       |        // First of all: find out how many scaling, rotation and translation
  738|       |        // animation tracks we'll have afterwards
  739|      1|        unsigned int numChannel = 0;
  740|      1|        CountTracks(mRootNode, numChannel);
  741|       |
  742|      1|        if (numChannel) {
  ------------------
  |  Branch (742:13): [True: 0, False: 1]
  ------------------
  743|       |            // Allocate a primary animation channel
  744|      0|            pcOut->mNumAnimations = 1;
  745|      0|            pcOut->mAnimations = new aiAnimation *[1];
  746|      0|            auto *anim = pcOut->mAnimations[0] = new aiAnimation();
  747|       |
  748|      0|            anim->mName.Set("3DSMasterAnim");
  749|       |
  750|       |            // Allocate enough storage for all node animation channels,
  751|       |            // but don't set the mNumChannels member - we'll use it to
  752|       |            // index into the array
  753|      0|            anim->mChannels = new aiNodeAnim *[numChannel];
  754|      0|        }
  755|       |
  756|      1|        aiMatrix4x4 m;
  757|      1|        AddNodeToGraph(pcOut, pcOut->mRootNode, mRootNode, m);
  758|      1|    }
  759|       |
  760|       |    // We used the first and second vertex color set to store some temporary values so we need to cleanup here
  761|      9|    for (unsigned int a = 0; a < pcOut->mNumMeshes; ++a) {
  ------------------
  |  Branch (761:30): [True: 6, False: 3]
  ------------------
  762|      6|        pcOut->mMeshes[a]->mColors[0] = nullptr;
  763|      6|        pcOut->mMeshes[a]->mColors[1] = nullptr;
  764|      6|    }
  765|       |
  766|      3|    pcOut->mRootNode->mTransformation = aiMatrix4x4(
  767|      3|                                                1.f, 0.f, 0.f, 0.f,
  768|      3|                                                0.f, 0.f, 1.f, 0.f,
  769|      3|                                                0.f, -1.f, 0.f, 0.f,
  770|      3|                                                0.f, 0.f, 0.f, 1.f) *
  771|      3|                                        pcOut->mRootNode->mTransformation;
  772|       |
  773|       |    // If the root node is unnamed name it "<3DSRoot>"
  774|      3|    if (::strstr(pcOut->mRootNode->mName.data, "UNNAMED") ||
  ------------------
  |  Branch (774:9): [True: 1, False: 2]
  ------------------
  775|      2|            (pcOut->mRootNode->mName.data[0] == '$' && pcOut->mRootNode->mName.data[1] == '$')) {
  ------------------
  |  Branch (775:14): [True: 0, False: 2]
  |  Branch (775:56): [True: 0, False: 0]
  ------------------
  776|      1|        pcOut->mRootNode->mName.Set("<3DSRoot>");
  777|      1|    }
  778|      3|}
_ZN6Assimp19Discreet3DSImporter12ConvertSceneEP7aiScene:
  782|      3|void Discreet3DSImporter::ConvertScene(aiScene *pcOut) {
  783|       |    // Allocate enough storage for all output materials
  784|      3|    pcOut->mNumMaterials = static_cast<unsigned int>(mScene->mMaterials.size());
  785|      3|    pcOut->mMaterials = new aiMaterial *[pcOut->mNumMaterials];
  786|       |
  787|       |    //  ... and convert the 3DS materials to aiMaterial's
  788|      9|    for (unsigned int i = 0; i < pcOut->mNumMaterials; ++i) {
  ------------------
  |  Branch (788:30): [True: 6, False: 3]
  ------------------
  789|      6|        auto *pcNew = new aiMaterial();
  790|      6|        ConvertMaterial(mScene->mMaterials[i], *pcNew);
  791|      6|        pcOut->mMaterials[i] = pcNew;
  792|      6|    }
  793|       |
  794|       |    // Generate the output mesh list
  795|      3|    ConvertMeshes(pcOut);
  796|       |
  797|       |    // Now copy all light sources to the output scene
  798|      3|    pcOut->mNumLights = static_cast<unsigned int>(mScene->mLights.size());
  799|      3|    if (pcOut->mNumLights) {
  ------------------
  |  Branch (799:9): [True: 0, False: 3]
  ------------------
  800|      0|        pcOut->mLights = new aiLight *[pcOut->mNumLights];
  801|      0|        memcpy(pcOut->mLights, &mScene->mLights[0], sizeof(void *) * pcOut->mNumLights);
  802|      0|    }
  803|       |
  804|       |    // Now copy all cameras to the output scene
  805|      3|    pcOut->mNumCameras = static_cast<unsigned int>(mScene->mCameras.size());
  806|      3|    if (pcOut->mNumCameras) {
  ------------------
  |  Branch (806:9): [True: 0, False: 3]
  ------------------
  807|      0|        pcOut->mCameras = new aiCamera *[pcOut->mNumCameras];
  808|      0|        memcpy(pcOut->mCameras, &mScene->mCameras[0], sizeof(void *) * pcOut->mNumCameras);
  809|      0|    }
  810|      3|}

_ZN6Assimp4D3DS7TextureC2Ev:
  322|    456|            : mTextureBlend(0.0f),
  323|    456|              mOffsetU(0.0),
  324|    456|              mOffsetV(0.0),
  325|    456|              mScaleU(1.0),
  326|    456|              mScaleV(1.0),
  327|    456|              mRotation(0.0),
  328|    456|              mMapMode(aiTextureMapMode_Wrap),
  329|       |              bPrivate(),
  330|    456|              iUVSrc(0) {
  331|    456|        mTextureBlend = get_qnan();
  332|    456|    }
_ZN6Assimp4D3DS8MaterialC2ERKNSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEE:
  384|     57|            mName(name),
  385|     57|            mDiffuse(0.6f, 0.6f, 0.6f),
  386|     57|            mSpecularExponent(ai_real(0.0)),
  387|     57|            mShininessStrength(ai_real(1.0)),
  388|     57|            mShading(Discreet3DS::Gouraud),
  389|     57|            mTransparency(ai_real(1.0)),
  390|     57|            mBumpHeight(ai_real(1.0)),
  391|     57|            mTwoSided(false) {
  392|       |        // empty
  393|     57|    }
_ZN6Assimp4D3DS4MeshC2ERKNSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEE:
  448|      9|            mName(name) {
  449|      9|    }
_ZN6Assimp4D3DS4NodeC2ERKNSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEE:
  493|     10|            mParent(nullptr),
  494|     10|            mName(name),
  495|     10|            mInstanceNumber(0),
  496|     10|            mHierarchyPos(0),
  497|     10|            mHierarchyIndex(0),
  498|     10|            mInstanceCount(1) {
  499|     10|        aRotationKeys.reserve(20);
  500|     10|        aPositionKeys.reserve(20);
  501|     10|        aScalingKeys.reserve(20);
  502|     10|    }
_ZN6Assimp4D3DS4NodeD2Ev:
  504|     10|    ~Node() {
  505|     11|        for (unsigned int i = 0; i < mChildren.size(); ++i)
  ------------------
  |  Branch (505:34): [True: 1, False: 10]
  ------------------
  506|      1|            delete mChildren[i];
  507|     10|    }
_ZN6Assimp4D3DS4Node9push_backEPS1_:
  554|      1|    inline Node &push_back(Node *pc) {
  555|      1|        mChildren.push_back(pc);
  556|      1|        pc->mParent = this;
  557|      1|        return *this;
  558|      1|    }
_ZN6Assimp4D3DS8MaterialD2Ev:
  397|     87|    virtual ~Material() = default;
_ZN6Assimp4D3DS8MaterialC2ERKS1_:
  395|     30|    Material(const Material &other) = default;
_ZN6Assimp4D3DS7TextureC2ERKS1_:
  334|    240|    Texture(const Texture &other) = default;

_ZN6Assimp19Discreet3DSImporterC2Ev:
  104|    624|        mStream(nullptr), mLastNodeIndex(), mCurrentNode(), mRootNode(), mScene(), mMasterScale(), bHasBG(), bIsPrj() {
  105|       |    // empty
  106|    624|}
_ZNK6Assimp19Discreet3DSImporter7CanReadERKNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEPNS_8IOSystemEb:
  110|    483|bool Discreet3DSImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool /*checkSig*/) const {
  111|    483|    static constexpr uint16_t token[] = { 0x4d4d, 0x3dc2 /*, 0x3daa */ };
  112|       |    return CheckMagicToken(pIOHandler, pFile, token, AI_COUNT_OF(token), 0, sizeof token[0]);
  113|    483|}
_ZNK6Assimp19Discreet3DSImporter7GetInfoEv:
  117|    643|const aiImporterDesc *Discreet3DSImporter::GetInfo() const {
  118|    643|    return &desc;
  119|    643|}
_ZN6Assimp19Discreet3DSImporter15SetupPropertiesEPKNS_8ImporterE:
  123|      9|void Discreet3DSImporter::SetupProperties(const Importer * /*pImp*/) {
  124|       |    // nothing to be done for the moment
  125|      9|}
_ZN6Assimp19Discreet3DSImporter14InternReadFileERKNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEP7aiScenePNS_8IOSystemE:
  129|      9|void Discreet3DSImporter::InternReadFile(const std::string &pFile, aiScene *pScene, IOSystem *pIOHandler) {
  130|      9|    auto theFile = pIOHandler->Open(pFile, "rb");
  131|      9|    if (!theFile) {
  ------------------
  |  Branch (131:9): [True: 0, False: 9]
  ------------------
  132|      0|        throw DeadlyImportError("3DS: Could not open ", pFile);
  133|      0|    }
  134|       |
  135|      9|    StreamReaderLE theStream(theFile);
  136|       |
  137|       |    // We should have at least one chunk
  138|      9|    if (theStream.GetRemainingSize() < 16) {
  ------------------
  |  Branch (138:9): [True: 0, False: 9]
  ------------------
  139|      0|        throw DeadlyImportError("3DS file is either empty or corrupt: ", pFile);
  140|      0|    }
  141|      9|    mStream = &theStream;
  142|       |
  143|       |    // Allocate our temporary 3DS representation
  144|      9|    Scene _scene;
  145|      9|    mScene = &_scene;
  146|       |
  147|       |    // Initialize members
  148|      9|    Node _rootNode("UNNAMED");
  149|      9|    mLastNodeIndex = -1;
  150|      9|    mCurrentNode = &_rootNode;
  151|      9|    mRootNode = mCurrentNode;
  152|      9|    mRootNode->mHierarchyPos = -1;
  153|      9|    mRootNode->mHierarchyIndex = -1;
  154|      9|    mRootNode->mParent = nullptr;
  155|      9|    mMasterScale = 1.0f;
  156|      9|    mBackgroundImage = std::string();
  157|      9|    bHasBG = false;
  158|      9|    bIsPrj = false;
  159|       |
  160|       |    // Parse the file
  161|      9|    ParseMainChunk();
  162|       |
  163|       |    // Process all meshes in the file. First check whether all
  164|       |    // face indices have valid values. The generate our
  165|       |    // internal verbose representation. Finally compute normal
  166|       |    // vectors from the smoothing groups we read from the
  167|       |    // file.
  168|      9|    for (auto &mesh : mScene->mMeshes) {
  ------------------
  |  Branch (168:21): [True: 3, False: 9]
  ------------------
  169|      3|        if (!mesh.mFaces.empty() && mesh.mPositions.empty()) {
  ------------------
  |  Branch (169:13): [True: 3, False: 0]
  |  Branch (169:37): [True: 0, False: 3]
  ------------------
  170|      0|            throw DeadlyImportError("3DS file contains faces but no vertices: ", pFile);
  171|      0|        }
  172|      3|        CheckIndices(mesh);
  173|      3|        MakeUnique(mesh);
  174|      3|        ComputeNormalsWithSmoothingsGroups<Face>(mesh);
  175|      3|    }
  176|       |
  177|       |    // Replace all occurrences of the default material with a
  178|       |    // valid material. Generate it if no material containing
  179|       |    // DEFAULT in its name has been found in the file
  180|      9|    ReplaceDefaultMaterial();
  181|       |
  182|       |    // Convert the scene from our internal representation to an
  183|       |    // aiScene object. This involves copying all meshes, lights
  184|       |    // and cameras to the scene
  185|      9|    ConvertScene(pScene);
  186|       |
  187|       |    // Generate the node graph for the scene. This is a little bit
  188|       |    // tricky since we'll need to split some meshes into sub-meshes
  189|      9|    GenerateNodeGraph(pScene);
  190|       |
  191|       |    // Now apply the master scaling factor to the scene
  192|      9|    ApplyMasterScale(pScene);
  193|       |
  194|       |    // Our internal scene representation and the root
  195|       |    // node will be automatically deleted, so the whole hierarchy will follow
  196|       |
  197|      9|    AI_DEBUG_INVALIDATE_PTR(mRootNode);
  198|      9|    AI_DEBUG_INVALIDATE_PTR(mScene);
  199|       |    AI_DEBUG_INVALIDATE_PTR(mStream);
  200|      9|}
_ZN6Assimp19Discreet3DSImporter16ApplyMasterScaleEPK7aiScene:
  204|      3|void Discreet3DSImporter::ApplyMasterScale(const aiScene *pScene) {
  205|       |    // There are some 3DS files with a zero scaling factor
  206|      3|    if (!mMasterScale)
  ------------------
  |  Branch (206:9): [True: 0, False: 3]
  ------------------
  207|      0|        mMasterScale = 1.0f;
  208|      3|    else
  209|      3|        mMasterScale = 1.0f / mMasterScale;
  210|       |
  211|       |    // Construct an uniform scaling matrix and multiply with it
  212|      3|    pScene->mRootNode->mTransformation *= aiMatrix4x4(
  213|      3|            mMasterScale, 0.0f, 0.0f, 0.0f,
  214|      3|            0.0f, mMasterScale, 0.0f, 0.0f,
  215|      3|            0.0f, 0.0f, mMasterScale, 0.0f,
  216|      3|            0.0f, 0.0f, 0.0f, 1.0f);
  217|       |
  218|       |    // Check whether a scaling track is assigned to the root node.
  219|      3|}
_ZN6Assimp19Discreet3DSImporter9ReadChunkEPNS_4D3DS11Discreet3DS5ChunkE:
  223|    185|void Discreet3DSImporter::ReadChunk(Discreet3DS::Chunk *pcOut) {
  224|    185|    ai_assert(pcOut != nullptr);
  225|       |
  226|    185|    pcOut->Flag = mStream->GetI2();
  227|    185|    pcOut->Size = mStream->GetI4();
  228|       |
  229|    185|    if (pcOut->Size - sizeof(Discreet3DS::Chunk) > mStream->GetRemainingSize()) {
  ------------------
  |  Branch (229:9): [True: 6, False: 179]
  ------------------
  230|      6|        throw DeadlyImportError("Chunk is too large");
  231|      6|    }
  232|       |
  233|    179|    if (pcOut->Size - sizeof(Discreet3DS::Chunk) > mStream->GetRemainingSizeToLimit()) {
  ------------------
  |  Branch (233:9): [True: 0, False: 179]
  ------------------
  234|       |        ASSIMP_LOG_ERROR("3DS: Chunk overflow");
  235|      0|    }
  236|    179|}
_ZN6Assimp19Discreet3DSImporter14ParseMainChunkEv:
  249|      9|void Discreet3DSImporter::ParseMainChunk() {
  250|     31|    ASSIMP_3DS_BEGIN_CHUNK();
  ------------------
  |  |   79|     11|    while (true) {                                                            \
  |  |  ------------------
  |  |  |  Branch (79:12): [True: 11, Folded]
  |  |  ------------------
  |  |   80|     11|        if (mStream->GetRemainingSizeToLimit() < sizeof(Discreet3DS::Chunk)) { \
  |  |  ------------------
  |  |  |  Branch (80:13): [True: 1, False: 10]
  |  |  ------------------
  |  |   81|      1|            return;                                                           \
  |  |   82|      1|        }                                                                     \
  |  |   83|     11|        Discreet3DS::Chunk chunk;                                             \
  |  |   84|     10|        ReadChunk(&chunk);                                                    \
  |  |   85|     10|        int chunkSize = chunk.Size - sizeof(Discreet3DS::Chunk);              \
  |  |   86|     10|        if (chunkSize <= 0)                                                   \
  |  |  ------------------
  |  |  |  Branch (86:13): [True: 0, False: 10]
  |  |  ------------------
  |  |   87|     10|            continue;                                                         \
  |  |   88|     10|        const unsigned int oldReadLimit = mStream->SetReadLimit(               \
  |  |   89|     10|                mStream->GetCurrentPos() + chunkSize);
  ------------------
  251|       |
  252|       |    // get chunk type
  253|     31|    switch (chunk.Flag) {
  ------------------
  |  Branch (253:13): [True: 9, False: 1]
  ------------------
  254|       |
  255|      0|    case Discreet3DS::CHUNK_PRJ:
  ------------------
  |  Branch (255:5): [True: 0, False: 10]
  ------------------
  256|      0|        bIsPrj = true;
  257|      0|        break;
  258|      9|    case Discreet3DS::CHUNK_MAIN:
  ------------------
  |  Branch (258:5): [True: 9, False: 1]
  ------------------
  259|      9|        ParseEditorChunk();
  260|      9|        break;
  261|     31|    }
  262|       |
  263|      4|    ASSIMP_3DS_END_CHUNK();
  ------------------
  |  |   95|      4|    mStream->SkipToReadLimit();                  \
  |  |   96|      4|    mStream->SetReadLimit(oldReadLimit);         \
  |  |   97|      4|    if (mStream->GetRemainingSizeToLimit() == 0) \
  |  |  ------------------
  |  |  |  Branch (97:9): [True: 2, False: 2]
  |  |  ------------------
  |  |   98|      4|        return;                                 \
  |  |   99|      4|    }
  ------------------
  264|      0|#if defined(__clang__)
  265|      0|#pragma clang diagnostic push
  266|      0|#pragma clang diagnostic ignored "-Wunreachable-code-return"
  267|      0|#endif
  268|       |    // recursively continue processing this hierarchy level
  269|      0|    return ParseMainChunk();
  270|      9|#if defined(__clang__)
  271|      9|#pragma clang diagnostic pop
  272|      9|#endif
  273|      9|}
_ZN6Assimp19Discreet3DSImporter16ParseEditorChunkEv:
  276|      9|void Discreet3DSImporter::ParseEditorChunk() {
  277|     57|    ASSIMP_3DS_BEGIN_CHUNK()
  ------------------
  |  |   79|     19|    while (true) {                                                            \
  |  |  ------------------
  |  |  |  Branch (79:12): [True: 19, Folded]
  |  |  ------------------
  |  |   80|     19|        if (mStream->GetRemainingSizeToLimit() < sizeof(Discreet3DS::Chunk)) { \
  |  |  ------------------
  |  |  |  Branch (80:13): [True: 0, False: 19]
  |  |  ------------------
  |  |   81|      0|            return;                                                           \
  |  |   82|      0|        }                                                                     \
  |  |   83|     19|        Discreet3DS::Chunk chunk;                                             \
  |  |   84|     19|        ReadChunk(&chunk);                                                    \
  |  |   85|     19|        int chunkSize = chunk.Size - sizeof(Discreet3DS::Chunk);              \
  |  |   86|     19|        if (chunkSize <= 0)                                                   \
  |  |  ------------------
  |  |  |  Branch (86:13): [True: 0, False: 19]
  |  |  ------------------
  |  |   87|     19|            continue;                                                         \
  |  |   88|     19|        const unsigned int oldReadLimit = mStream->SetReadLimit(               \
  |  |   89|     19|                mStream->GetCurrentPos() + chunkSize);
  ------------------
  278|       |
  279|       |    // get chunk type
  280|     57|    switch (chunk.Flag) {
  ------------------
  |  Branch (280:13): [True: 19, False: 0]
  ------------------
  281|      9|        case Discreet3DS::CHUNK_OBJMESH:
  ------------------
  |  Branch (281:9): [True: 9, False: 10]
  ------------------
  282|      9|            ParseObjectChunk();
  283|      9|            break;
  284|       |
  285|       |        // NOTE: In several documentations in the internet this
  286|       |        // chunk appears at different locations
  287|      1|        case Discreet3DS::CHUNK_KEYFRAMER:
  ------------------
  |  Branch (287:9): [True: 1, False: 18]
  ------------------
  288|      1|            ParseKeyframeChunk();
  289|      1|            break;
  290|       |    
  291|      9|        case Discreet3DS::CHUNK_VERSION: {
  ------------------
  |  Branch (291:9): [True: 9, False: 10]
  ------------------
  292|       |            // print the version number
  293|      9|            char buff[10];
  294|      9|            ASSIMP_itoa10(buff, mStream->GetI2());
  295|      9|            ASSIMP_LOG_INFO("3DS file format version: ", buff);
  296|      9|        }
  297|      9|        break;
  298|     57|    };
  299|     14|    ASSIMP_3DS_END_CHUNK()
  ------------------
  |  |   95|     14|    mStream->SkipToReadLimit();                  \
  |  |   96|     14|    mStream->SetReadLimit(oldReadLimit);         \
  |  |   97|     14|    if (mStream->GetRemainingSizeToLimit() == 0) \
  |  |  ------------------
  |  |  |  Branch (97:9): [True: 4, False: 10]
  |  |  ------------------
  |  |   98|     14|        return;                                 \
  |  |   99|     14|    }
  ------------------
  300|      9|}
_ZN6Assimp19Discreet3DSImporter16ParseObjectChunkEv:
  303|      9|void Discreet3DSImporter::ParseObjectChunk() {
  304|     99|    ASSIMP_3DS_BEGIN_CHUNK();
  ------------------
  |  |   79|     33|    while (true) {                                                            \
  |  |  ------------------
  |  |  |  Branch (79:12): [True: 33, Folded]
  |  |  ------------------
  |  |   80|     33|        if (mStream->GetRemainingSizeToLimit() < sizeof(Discreet3DS::Chunk)) { \
  |  |  ------------------
  |  |  |  Branch (80:13): [True: 0, False: 33]
  |  |  ------------------
  |  |   81|      0|            return;                                                           \
  |  |   82|      0|        }                                                                     \
  |  |   83|     33|        Discreet3DS::Chunk chunk;                                             \
  |  |   84|     33|        ReadChunk(&chunk);                                                    \
  |  |   85|     33|        int chunkSize = chunk.Size - sizeof(Discreet3DS::Chunk);              \
  |  |   86|     33|        if (chunkSize <= 0)                                                   \
  |  |  ------------------
  |  |  |  Branch (86:13): [True: 0, False: 33]
  |  |  ------------------
  |  |   87|     33|            continue;                                                         \
  |  |   88|     33|        const unsigned int oldReadLimit = mStream->SetReadLimit(               \
  |  |   89|     33|                mStream->GetCurrentPos() + chunkSize);
  ------------------
  305|       |
  306|       |    // get chunk type
  307|     99|    switch (chunk.Flag) {
  ------------------
  |  Branch (307:13): [True: 24, False: 9]
  ------------------
  308|      9|    case Discreet3DS::CHUNK_OBJBLOCK: {
  ------------------
  |  Branch (308:5): [True: 9, False: 24]
  ------------------
  309|      9|        unsigned int cnt = 0;
  310|      9|        const auto *sz = (const char *)mStream->GetPtr();
  311|       |
  312|       |        // Get the name of the geometry object
  313|     62|        while (mStream->GetI1())
  ------------------
  |  Branch (313:16): [True: 53, False: 9]
  ------------------
  314|     53|            ++cnt;
  315|      9|        ParseChunk(sz, cnt);
  316|      9|    } break;
  317|       |
  318|      7|    case Discreet3DS::CHUNK_MAT_MATERIAL:
  ------------------
  |  Branch (318:5): [True: 7, False: 26]
  ------------------
  319|       |
  320|       |        // Add a new material to the list
  321|      7|        mScene->mMaterials.emplace_back(std::string("UNNAMED_" + ai_to_string(mScene->mMaterials.size())));
  322|      7|        ParseMaterialChunk();
  323|      7|        break;
  324|       |
  325|      0|    case Discreet3DS::CHUNK_AMBCOLOR:
  ------------------
  |  Branch (325:5): [True: 0, False: 33]
  ------------------
  326|       |
  327|       |        // This is the ambient base color of the scene.
  328|       |        // We add it to the ambient color of all materials
  329|      0|        ParseColorChunk(&mClrAmbient, true);
  330|      0|        if (is_qnan(mClrAmbient.r)) {
  ------------------
  |  Branch (330:13): [True: 0, False: 0]
  ------------------
  331|       |            // We failed to read the ambient base color.
  332|      0|            ASSIMP_LOG_ERROR("3DS: Failed to read ambient base color");
  333|      0|            mClrAmbient.r = mClrAmbient.g = mClrAmbient.b = 0.0f;
  334|      0|        }
  335|      0|        break;
  336|       |
  337|      0|    case Discreet3DS::CHUNK_BIT_MAP: {
  ------------------
  |  Branch (337:5): [True: 0, False: 33]
  ------------------
  338|       |        // Specifies the background image. The string should already be
  339|       |        // properly 0 terminated but we need to be sure
  340|      0|        unsigned int cnt = 0;
  341|      0|        auto *sz = (const char *)mStream->GetPtr();
  342|      0|        while (mStream->GetI1())
  ------------------
  |  Branch (342:16): [True: 0, False: 0]
  ------------------
  343|      0|            ++cnt;
  344|      0|        mBackgroundImage = std::string(sz, cnt);
  345|      0|    } break;
  346|       |
  347|      0|    case Discreet3DS::CHUNK_BIT_MAP_EXISTS:
  ------------------
  |  Branch (347:5): [True: 0, False: 33]
  ------------------
  348|      0|        bHasBG = true;
  349|      0|        break;
  350|       |
  351|      8|    case Discreet3DS::CHUNK_MASTER_SCALE:
  ------------------
  |  Branch (351:5): [True: 8, False: 25]
  ------------------
  352|       |        // Scene master scaling factor
  353|      8|        mMasterScale = mStream->GetF4();
  354|      8|        break;
  355|     99|    };
  356|     28|    ASSIMP_3DS_END_CHUNK();
  ------------------
  |  |   95|     28|    mStream->SkipToReadLimit();                  \
  |  |   96|     28|    mStream->SetReadLimit(oldReadLimit);         \
  |  |   97|     28|    if (mStream->GetRemainingSizeToLimit() == 0) \
  |  |  ------------------
  |  |  |  Branch (97:9): [True: 4, False: 24]
  |  |  ------------------
  |  |   98|     28|        return;                                 \
  |  |   99|     28|    }
  ------------------
  357|      0|}
_ZN6Assimp19Discreet3DSImporter10ParseChunkEPKcj:
  360|      9|void Discreet3DSImporter::ParseChunk(const char *name, unsigned int num) {
  361|     27|    ASSIMP_3DS_BEGIN_CHUNK();
  ------------------
  |  |   79|      9|    while (true) {                                                            \
  |  |  ------------------
  |  |  |  Branch (79:12): [True: 9, Folded]
  |  |  ------------------
  |  |   80|      9|        if (mStream->GetRemainingSizeToLimit() < sizeof(Discreet3DS::Chunk)) { \
  |  |  ------------------
  |  |  |  Branch (80:13): [True: 0, False: 9]
  |  |  ------------------
  |  |   81|      0|            return;                                                           \
  |  |   82|      0|        }                                                                     \
  |  |   83|      9|        Discreet3DS::Chunk chunk;                                             \
  |  |   84|      9|        ReadChunk(&chunk);                                                    \
  |  |   85|      9|        int chunkSize = chunk.Size - sizeof(Discreet3DS::Chunk);              \
  |  |   86|      9|        if (chunkSize <= 0)                                                   \
  |  |  ------------------
  |  |  |  Branch (86:13): [True: 0, False: 9]
  |  |  ------------------
  |  |   87|      9|            continue;                                                         \
  |  |   88|      9|        const unsigned int oldReadLimit = mStream->SetReadLimit(               \
  |  |   89|      9|                mStream->GetCurrentPos() + chunkSize);
  ------------------
  362|       |
  363|       |    // IMPLEMENTATION NOTE;
  364|       |    // Cameras or lights define their transformation in their parent node and in the
  365|       |    // corresponding light or camera chunks. However, we read and process the latter
  366|       |    // to be able to return valid cameras/lights even if no scenegraph is given.
  367|       |
  368|       |    // get chunk type
  369|     27|    switch (chunk.Flag) {
  ------------------
  |  Branch (369:13): [True: 9, False: 0]
  ------------------
  370|      9|    case Discreet3DS::CHUNK_TRIMESH: {
  ------------------
  |  Branch (370:5): [True: 9, False: 0]
  ------------------
  371|       |        // this starts a new triangle mesh
  372|      9|        mScene->mMeshes.emplace_back(std::string(name, num));
  373|       |
  374|       |        // Read mesh chunks
  375|      9|        ParseMeshChunk();
  376|      9|    } break;
  377|       |
  378|      0|    case Discreet3DS::CHUNK_LIGHT: {
  ------------------
  |  Branch (378:5): [True: 0, False: 9]
  ------------------
  379|       |        // This starts a new light
  380|      0|        auto *light = new aiLight();
  381|      0|        mScene->mLights.push_back(light);
  382|       |
  383|      0|        light->mName.Set(std::string(name, num));
  384|       |
  385|       |        // First read the position of the light
  386|      0|        light->mPosition.x = mStream->GetF4();
  387|      0|        light->mPosition.y = mStream->GetF4();
  388|      0|        light->mPosition.z = mStream->GetF4();
  389|       |
  390|      0|        light->mColorDiffuse = aiColor3D(1.f, 1.f, 1.f);
  391|       |
  392|       |        // Now check for further subchunks
  393|      0|        if (!bIsPrj) /* fixme */
  ------------------
  |  Branch (393:13): [True: 0, False: 0]
  ------------------
  394|      0|            ParseLightChunk();
  395|       |
  396|       |        // The specular light color is identical the the diffuse light color. The ambient light color
  397|       |        // is equal to the ambient base color of the whole scene.
  398|      0|        light->mColorSpecular = light->mColorDiffuse;
  399|      0|        light->mColorAmbient = mClrAmbient;
  400|       |
  401|      0|        if (light->mType == aiLightSource_UNDEFINED) {
  ------------------
  |  Branch (401:13): [True: 0, False: 0]
  ------------------
  402|       |            // It must be a point light
  403|      0|            light->mType = aiLightSource_POINT;
  404|      0|        }
  405|      0|    } break;
  406|       |
  407|      0|    case Discreet3DS::CHUNK_CAMERA: {
  ------------------
  |  Branch (407:5): [True: 0, False: 9]
  ------------------
  408|       |        // This starts a new camera
  409|      0|        auto *camera = new aiCamera();
  410|      0|        mScene->mCameras.push_back(camera);
  411|      0|        camera->mName.Set(std::string(name, num));
  412|       |
  413|       |        // First read the position of the camera
  414|      0|        camera->mPosition.x = mStream->GetF4();
  415|      0|        camera->mPosition.y = mStream->GetF4();
  416|      0|        camera->mPosition.z = mStream->GetF4();
  417|       |
  418|       |        // Then the camera target
  419|      0|        camera->mLookAt.x = mStream->GetF4() - camera->mPosition.x;
  420|      0|        camera->mLookAt.y = mStream->GetF4() - camera->mPosition.y;
  421|      0|        camera->mLookAt.z = mStream->GetF4() - camera->mPosition.z;
  422|      0|        ai_real len = camera->mLookAt.Length();
  423|      0|        if (len < 1e-5) {
  ------------------
  |  Branch (423:13): [True: 0, False: 0]
  ------------------
  424|       |
  425|       |            // There are some files with lookat == position. Don't know why or whether it's ok or not.
  426|      0|            ASSIMP_LOG_ERROR("3DS: Unable to read proper camera look-at vector");
  427|      0|            camera->mLookAt = aiVector3D(0.0, 1.0, 0.0);
  428|       |
  429|      0|        } else
  430|      0|            camera->mLookAt /= len;
  431|       |
  432|       |        // And finally - the camera rotation angle, in counter clockwise direction
  433|      0|        const ai_real angle = AI_DEG_TO_RAD(mStream->GetF4());
  434|      0|        aiQuaternion quat(camera->mLookAt, angle);
  435|      0|        camera->mUp = quat.GetMatrix() * aiVector3D(0.0, 1.0, 0.0);
  436|       |
  437|       |        // Read the lense angle
  438|      0|        camera->mHorizontalFOV = AI_DEG_TO_RAD(mStream->GetF4());
  439|      0|        if (camera->mHorizontalFOV < 0.001f) {
  ------------------
  |  Branch (439:13): [True: 0, False: 0]
  ------------------
  440|      0|            camera->mHorizontalFOV = float(AI_DEG_TO_RAD(45.f));
  441|      0|        }
  442|       |
  443|       |        // Now check for further subchunks
  444|      0|        if (!bIsPrj) /* fixme */ {
  ------------------
  |  Branch (444:13): [True: 0, False: 0]
  ------------------
  445|      0|            ParseCameraChunk();
  446|      0|        }
  447|      0|    } break;
  448|     27|    };
  449|      4|    ASSIMP_3DS_END_CHUNK();
  ------------------
  |  |   95|      4|    mStream->SkipToReadLimit();                  \
  |  |   96|      4|    mStream->SetReadLimit(oldReadLimit);         \
  |  |   97|      4|    if (mStream->GetRemainingSizeToLimit() == 0) \
  |  |  ------------------
  |  |  |  Branch (97:9): [True: 4, False: 0]
  |  |  ------------------
  |  |   98|      4|        return;                                 \
  |  |   99|      4|    }
  ------------------
  450|      0|}
_ZN6Assimp19Discreet3DSImporter18ParseKeyframeChunkEv:
  516|      1|void Discreet3DSImporter::ParseKeyframeChunk() {
  517|     12|    ASSIMP_3DS_BEGIN_CHUNK();
  ------------------
  |  |   79|      4|    while (true) {                                                            \
  |  |  ------------------
  |  |  |  Branch (79:12): [True: 4, Folded]
  |  |  ------------------
  |  |   80|      4|        if (mStream->GetRemainingSizeToLimit() < sizeof(Discreet3DS::Chunk)) { \
  |  |  ------------------
  |  |  |  Branch (80:13): [True: 0, False: 4]
  |  |  ------------------
  |  |   81|      0|            return;                                                           \
  |  |   82|      0|        }                                                                     \
  |  |   83|      4|        Discreet3DS::Chunk chunk;                                             \
  |  |   84|      4|        ReadChunk(&chunk);                                                    \
  |  |   85|      4|        int chunkSize = chunk.Size - sizeof(Discreet3DS::Chunk);              \
  |  |   86|      4|        if (chunkSize <= 0)                                                   \
  |  |  ------------------
  |  |  |  Branch (86:13): [True: 0, False: 4]
  |  |  ------------------
  |  |   87|      4|            continue;                                                         \
  |  |   88|      4|        const unsigned int oldReadLimit = mStream->SetReadLimit(               \
  |  |   89|      4|                mStream->GetCurrentPos() + chunkSize);
  ------------------
  518|       |
  519|       |    // get chunk type
  520|     12|    switch (chunk.Flag) {
  ------------------
  |  Branch (520:13): [True: 1, False: 3]
  ------------------
  521|      0|    case Discreet3DS::CHUNK_TRACKCAMTGT:
  ------------------
  |  Branch (521:5): [True: 0, False: 4]
  ------------------
  522|      0|    case Discreet3DS::CHUNK_TRACKSPOTL:
  ------------------
  |  Branch (522:5): [True: 0, False: 4]
  ------------------
  523|      0|    case Discreet3DS::CHUNK_TRACKCAMERA:
  ------------------
  |  Branch (523:5): [True: 0, False: 4]
  ------------------
  524|      1|    case Discreet3DS::CHUNK_TRACKINFO:
  ------------------
  |  Branch (524:5): [True: 1, False: 3]
  ------------------
  525|      1|    case Discreet3DS::CHUNK_TRACKLIGHT:
  ------------------
  |  Branch (525:5): [True: 0, False: 4]
  ------------------
  526|      1|    case Discreet3DS::CHUNK_TRACKLIGTGT:
  ------------------
  |  Branch (526:5): [True: 0, False: 4]
  ------------------
  527|       |
  528|       |        // this starts a new mesh hierarchy chunk
  529|      1|        ParseHierarchyChunk(chunk.Flag);
  530|      1|        break;
  531|     12|    };
  532|       |
  533|      4|    ASSIMP_3DS_END_CHUNK();
  ------------------
  |  |   95|      4|    mStream->SkipToReadLimit();                  \
  |  |   96|      4|    mStream->SetReadLimit(oldReadLimit);         \
  |  |   97|      4|    if (mStream->GetRemainingSizeToLimit() == 0) \
  |  |  ------------------
  |  |  |  Branch (97:9): [True: 1, False: 3]
  |  |  ------------------
  |  |   98|      4|        return;                                 \
  |  |   99|      4|    }
  ------------------
  534|      0|}
_ZN6Assimp8FindNodeEPNS_4D3DS4NodeERKNSt3__112basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEE:
  556|      1|Node *FindNode(Node *root, const std::string &name) {
  557|      1|    if (root->mName == name) {
  ------------------
  |  Branch (557:9): [True: 0, False: 1]
  ------------------
  558|      0|        return root;
  559|      0|    }
  560|       |
  561|      1|    for (auto it = root->mChildren.begin(); it != root->mChildren.end(); ++it) {
  ------------------
  |  Branch (561:45): [True: 0, False: 1]
  ------------------
  562|      0|        if (auto *nd = FindNode(*it, name); nullptr != nd) {
  ------------------
  |  Branch (562:45): [True: 0, False: 0]
  ------------------
  563|      0|            return nd;
  564|      0|        }
  565|      0|    }
  566|       |
  567|      1|    return nullptr;
  568|      1|}
_ZN6Assimp19Discreet3DSImporter11SkipTCBInfoEv:
  579|      3|void Discreet3DSImporter::SkipTCBInfo() {
  580|      3|    unsigned int flags = mStream->GetI2();
  581|       |
  582|      3|    if (!flags) {
  ------------------
  |  Branch (582:9): [True: 3, False: 0]
  ------------------
  583|       |        // Currently we can't do anything with these values. They occur
  584|       |        // quite rare, so it wouldn't be worth the effort implementing
  585|       |        // them. 3DS is not really suitable for complex animations,
  586|       |        // so full support is not required.
  587|      3|        ASSIMP_LOG_WARN("3DS: Skipping TCB animation info");
  588|      3|    }
  589|       |
  590|      3|    if (flags & Discreet3DS::KEY_USE_TENS) {
  ------------------
  |  Branch (590:9): [True: 0, False: 3]
  ------------------
  591|      0|        mStream->IncPtr(4);
  592|      0|    }
  593|      3|    if (flags & Discreet3DS::KEY_USE_BIAS) {
  ------------------
  |  Branch (593:9): [True: 0, False: 3]
  ------------------
  594|      0|        mStream->IncPtr(4);
  595|      0|    }
  596|      3|    if (flags & Discreet3DS::KEY_USE_CONT) {
  ------------------
  |  Branch (596:9): [True: 0, False: 3]
  ------------------
  597|      0|        mStream->IncPtr(4);
  598|      0|    }
  599|      3|    if (flags & Discreet3DS::KEY_USE_EASE_FROM) {
  ------------------
  |  Branch (599:9): [True: 0, False: 3]
  ------------------
  600|      0|        mStream->IncPtr(4);
  601|      0|    }
  602|      3|    if (flags & Discreet3DS::KEY_USE_EASE_TO) {
  ------------------
  |  Branch (602:9): [True: 0, False: 3]
  ------------------
  603|      0|        mStream->IncPtr(4);
  604|      0|    }
  605|      3|}
_ZN6Assimp19Discreet3DSImporter19ParseHierarchyChunkEt:
  609|      1|void Discreet3DSImporter::ParseHierarchyChunk(uint16_t parent) {
  610|     18|    ASSIMP_3DS_BEGIN_CHUNK();
  ------------------
  |  |   79|      6|    while (true) {                                                            \
  |  |  ------------------
  |  |  |  Branch (79:12): [True: 6, Folded]
  |  |  ------------------
  |  |   80|      6|        if (mStream->GetRemainingSizeToLimit() < sizeof(Discreet3DS::Chunk)) { \
  |  |  ------------------
  |  |  |  Branch (80:13): [True: 0, False: 6]
  |  |  ------------------
  |  |   81|      0|            return;                                                           \
  |  |   82|      0|        }                                                                     \
  |  |   83|      6|        Discreet3DS::Chunk chunk;                                             \
  |  |   84|      6|        ReadChunk(&chunk);                                                    \
  |  |   85|      6|        int chunkSize = chunk.Size - sizeof(Discreet3DS::Chunk);              \
  |  |   86|      6|        if (chunkSize <= 0)                                                   \
  |  |  ------------------
  |  |  |  Branch (86:13): [True: 0, False: 6]
  |  |  ------------------
  |  |   87|      6|            continue;                                                         \
  |  |   88|      6|        const unsigned int oldReadLimit = mStream->SetReadLimit(               \
  |  |   89|      6|                mStream->GetCurrentPos() + chunkSize);
  ------------------
  611|       |
  612|       |    // get chunk type
  613|     18|    switch (chunk.Flag) {
  ------------------
  |  Branch (613:13): [True: 5, False: 1]
  ------------------
  614|      1|    case Discreet3DS::CHUNK_TRACKOBJNAME:
  ------------------
  |  Branch (614:5): [True: 1, False: 5]
  ------------------
  615|       |
  616|       |        // This is the name of the object to which the track applies. The chunk also
  617|       |        // defines the position of this object in the hierarchy.
  618|      1|        {
  619|       |
  620|       |            // First of all: get the name of the object
  621|      1|            unsigned int cnt = 0;
  622|      1|            auto *sz = (const char *)mStream->GetPtr();
  623|       |
  624|      8|            while (mStream->GetI1())
  ------------------
  |  Branch (624:20): [True: 7, False: 1]
  ------------------
  625|      7|                ++cnt;
  626|      1|            std::string name = std::string(sz, cnt);
  627|       |
  628|       |            // Now find out whether we have this node already (target animation channels
  629|       |            // are stored with a separate object ID)
  630|      1|            Node *pcNode = FindNode(mRootNode, name);
  631|      1|            int instanceNumber = 1;
  632|       |
  633|      1|            if (pcNode) {
  ------------------
  |  Branch (633:17): [True: 0, False: 1]
  ------------------
  634|       |                // if the source is not a CHUNK_TRACKINFO block it won't be an object instance
  635|      0|                if (parent != Discreet3DS::CHUNK_TRACKINFO) {
  ------------------
  |  Branch (635:21): [True: 0, False: 0]
  ------------------
  636|      0|                    mCurrentNode = pcNode;
  637|      0|                    break;
  638|      0|                }
  639|      0|                pcNode->mInstanceCount++;
  640|      0|                instanceNumber = pcNode->mInstanceCount;
  641|      0|            }
  642|      1|            pcNode = new D3DS::Node(name);
  643|      1|            pcNode->mInstanceNumber = instanceNumber;
  644|       |
  645|       |            // There are two unknown values which we can safely ignore
  646|      1|            mStream->IncPtr(4);
  647|       |
  648|       |            // Now read the hierarchy position of the object
  649|      1|            uint16_t hierarchy = mStream->GetI2() + 1;
  650|      1|            pcNode->mHierarchyPos = hierarchy;
  651|      1|            pcNode->mHierarchyIndex = mLastNodeIndex;
  652|       |
  653|       |            // And find a proper position in the graph for it
  654|      1|            if (mCurrentNode && mCurrentNode->mHierarchyPos == hierarchy) {
  ------------------
  |  Branch (654:17): [True: 1, False: 0]
  |  Branch (654:33): [True: 0, False: 1]
  ------------------
  655|       |
  656|       |                // add to the parent of the last touched node
  657|      0|                mCurrentNode->mParent->push_back(pcNode);
  658|      0|                mLastNodeIndex++;
  659|      1|            } else if (hierarchy >= mLastNodeIndex) {
  ------------------
  |  Branch (659:24): [True: 1, False: 0]
  ------------------
  660|       |
  661|       |                // place it at the current position in the hierarchy
  662|      1|                mCurrentNode->push_back(pcNode);
  663|      1|                mLastNodeIndex = hierarchy;
  664|      1|            } else {
  665|       |                // need to go back to the specified position in the hierarchy.
  666|      0|                InverseNodeSearch(pcNode, mCurrentNode);
  667|      0|                mLastNodeIndex++;
  668|      0|            }
  669|       |            // Make this node the current node
  670|      1|            mCurrentNode = pcNode;
  671|      1|        }
  672|      0|        break;
  673|       |
  674|      0|    case Discreet3DS::CHUNK_TRACKDUMMYOBJNAME:
  ------------------
  |  Branch (674:5): [True: 0, False: 6]
  ------------------
  675|       |
  676|       |        // This is the "real" name of a $$$DUMMY object
  677|      0|        {
  678|      0|            const char *sz = (const char *)mStream->GetPtr();
  679|      0|            while (mStream->GetI1())
  ------------------
  |  Branch (679:20): [True: 0, False: 0]
  ------------------
  680|      0|                ;
  681|       |
  682|       |            // If object name is DUMMY, take this one instead
  683|      0|            if (mCurrentNode->mName == "$$$DUMMY") {
  ------------------
  |  Branch (683:17): [True: 0, False: 0]
  ------------------
  684|      0|                mCurrentNode->mName = std::string(sz);
  685|      0|                break;
  686|      0|            }
  687|      0|        }
  688|      0|        break;
  689|       |
  690|      1|    case Discreet3DS::CHUNK_TRACKPIVOT:
  ------------------
  |  Branch (690:5): [True: 1, False: 5]
  ------------------
  691|       |
  692|      1|        if (Discreet3DS::CHUNK_TRACKINFO != parent) {
  ------------------
  |  Branch (692:13): [True: 0, False: 1]
  ------------------
  693|      0|            ASSIMP_LOG_WARN("3DS: Skipping pivot subchunk for non usual object");
  694|      0|            break;
  695|      0|        }
  696|       |
  697|       |        // Pivot = origin of rotation and scaling
  698|      1|        mCurrentNode->vPivot.x = mStream->GetF4();
  699|      1|        mCurrentNode->vPivot.y = mStream->GetF4();
  700|      1|        mCurrentNode->vPivot.z = mStream->GetF4();
  701|      1|        break;
  702|       |
  703|       |        // ////////////////////////////////////////////////////////////////////
  704|       |        // POSITION KEYFRAME
  705|      1|    case Discreet3DS::CHUNK_TRACKPOS: {
  ------------------
  |  Branch (705:5): [True: 1, False: 5]
  ------------------
  706|      1|        mStream->IncPtr(10);
  707|      1|        const unsigned int numFrames = mStream->GetI4();
  708|      1|        bool sortKeys = false;
  709|       |
  710|       |        // This could also be meant as the target position for
  711|       |        // (targeted) lights and cameras
  712|      1|        std::vector<aiVectorKey> *l;
  713|      1|        if (Discreet3DS::CHUNK_TRACKCAMTGT == parent || Discreet3DS::CHUNK_TRACKLIGTGT == parent) {
  ------------------
  |  Branch (713:13): [True: 0, False: 1]
  |  Branch (713:57): [True: 0, False: 1]
  ------------------
  714|      0|            l = &mCurrentNode->aTargetPositionKeys;
  715|      0|        } else
  716|      1|            l = &mCurrentNode->aPositionKeys;
  717|       |
  718|      1|        l->reserve(numFrames);
  719|      2|        for (unsigned int i = 0; i < numFrames; ++i) {
  ------------------
  |  Branch (719:34): [True: 1, False: 1]
  ------------------
  720|      1|            const unsigned int fidx = mStream->GetI4();
  721|       |
  722|       |            // Setup a new position key
  723|      1|            aiVectorKey v;
  724|      1|            v.mTime = (double)fidx;
  725|       |
  726|      1|            SkipTCBInfo();
  727|      1|            v.mValue.x = mStream->GetF4();
  728|      1|            v.mValue.y = mStream->GetF4();
  729|      1|            v.mValue.z = mStream->GetF4();
  730|       |
  731|       |            // check whether we'll need to sort the keys
  732|      1|            if (!l->empty() && v.mTime <= l->back().mTime)
  ------------------
  |  Branch (732:17): [True: 0, False: 1]
  |  Branch (732:32): [True: 0, False: 0]
  ------------------
  733|      0|                sortKeys = true;
  734|       |
  735|       |            // Add the new keyframe to the list
  736|      1|            l->push_back(v);
  737|      1|        }
  738|       |
  739|       |        // Sort all keys with ascending time values and remove duplicates?
  740|      1|        if (sortKeys) {
  ------------------
  |  Branch (740:13): [True: 0, False: 1]
  ------------------
  741|      0|            std::stable_sort(l->begin(), l->end());
  742|      0|            l->erase(std::unique(l->begin(), l->end(), &KeyUniqueCompare<aiVectorKey>), l->end());
  743|      0|        }
  744|      1|    }
  745|       |
  746|      1|    break;
  747|       |
  748|       |        // ////////////////////////////////////////////////////////////////////
  749|       |        // CAMERA ROLL KEYFRAME
  750|      0|    case Discreet3DS::CHUNK_TRACKROLL: {
  ------------------
  |  Branch (750:5): [True: 0, False: 6]
  ------------------
  751|       |        // roll keys are accepted for cameras only
  752|      0|        if (parent != Discreet3DS::CHUNK_TRACKCAMERA) {
  ------------------
  |  Branch (752:13): [True: 0, False: 0]
  ------------------
  753|      0|            ASSIMP_LOG_WARN("3DS: Ignoring roll track for non-camera object");
  754|      0|            break;
  755|      0|        }
  756|      0|        bool sortKeys = false;
  757|      0|        std::vector<aiFloatKey> *l = &mCurrentNode->aCameraRollKeys;
  758|       |
  759|      0|        mStream->IncPtr(10);
  760|      0|        const unsigned int numFrames = mStream->GetI4();
  761|      0|        l->reserve(numFrames);
  762|      0|        for (unsigned int i = 0; i < numFrames; ++i) {
  ------------------
  |  Branch (762:34): [True: 0, False: 0]
  ------------------
  763|      0|            const unsigned int fidx = mStream->GetI4();
  764|       |
  765|       |            // Setup a new position key
  766|      0|            aiFloatKey v;
  767|      0|            v.mTime = (double)fidx;
  768|       |
  769|       |            // This is just a single float
  770|      0|            SkipTCBInfo();
  771|      0|            v.mValue = mStream->GetF4();
  772|       |
  773|       |            // Check whether we'll need to sort the keys
  774|      0|            if (!l->empty() && v.mTime <= l->back().mTime)
  ------------------
  |  Branch (774:17): [True: 0, False: 0]
  |  Branch (774:32): [True: 0, False: 0]
  ------------------
  775|      0|                sortKeys = true;
  776|       |
  777|       |            // Add the new keyframe to the list
  778|      0|            l->push_back(v);
  779|      0|        }
  780|       |
  781|       |        // Sort all keys with ascending time values and remove duplicates?
  782|      0|        if (sortKeys) {
  ------------------
  |  Branch (782:13): [True: 0, False: 0]
  ------------------
  783|      0|            std::stable_sort(l->begin(), l->end());
  784|      0|            l->erase(std::unique(l->begin(), l->end(), &KeyUniqueCompare<aiFloatKey>), l->end());
  785|      0|        }
  786|      0|    } break;
  787|       |
  788|       |        // ////////////////////////////////////////////////////////////////////
  789|       |        // CAMERA FOV KEYFRAME
  790|      0|    case Discreet3DS::CHUNK_TRACKFOV: {
  ------------------
  |  Branch (790:5): [True: 0, False: 6]
  ------------------
  791|      0|        ASSIMP_LOG_ERROR("3DS: Skipping FOV animation track. "
  792|      0|                         "This is not supported");
  793|      0|    } break;
  794|       |
  795|       |        // ////////////////////////////////////////////////////////////////////
  796|       |        // ROTATION KEYFRAME
  797|      1|    case Discreet3DS::CHUNK_TRACKROTATE: {
  ------------------
  |  Branch (797:5): [True: 1, False: 5]
  ------------------
  798|      1|        mStream->IncPtr(10);
  799|      1|        const unsigned int numFrames = mStream->GetI4();
  800|       |
  801|      1|        bool sortKeys = false;
  802|      1|        std::vector<aiQuatKey> *l = &mCurrentNode->aRotationKeys;
  803|      1|        l->reserve(numFrames);
  804|       |
  805|      2|        for (unsigned int i = 0; i < numFrames; ++i) {
  ------------------
  |  Branch (805:34): [True: 1, False: 1]
  ------------------
  806|      1|            const unsigned int fidx = mStream->GetI4();
  807|      1|            SkipTCBInfo();
  808|       |
  809|      1|            aiQuatKey v;
  810|      1|            v.mTime = (double)fidx;
  811|       |
  812|       |            // The rotation keyframe is given as an axis-angle pair
  813|      1|            const float rad = mStream->GetF4();
  814|      1|            aiVector3D axis;
  815|      1|            axis.x = mStream->GetF4();
  816|      1|            axis.y = mStream->GetF4();
  817|      1|            axis.z = mStream->GetF4();
  818|       |
  819|      1|            if (!axis.x && !axis.y && !axis.z)
  ------------------
  |  Branch (819:17): [True: 1, False: 0]
  |  Branch (819:28): [True: 1, False: 0]
  |  Branch (819:39): [True: 1, False: 0]
  ------------------
  820|      1|                axis.y = 1.f;
  821|       |
  822|       |            // Construct a rotation quaternion from the axis-angle pair
  823|      1|            v.mValue = aiQuaternion(axis, rad);
  824|       |
  825|       |            // Check whether we'll need to sort the keys
  826|      1|            if (!l->empty() && v.mTime <= l->back().mTime)
  ------------------
  |  Branch (826:17): [True: 0, False: 1]
  |  Branch (826:32): [True: 0, False: 0]
  ------------------
  827|      0|                sortKeys = true;
  828|       |
  829|       |            // add the new keyframe to the list
  830|      1|            l->push_back(v);
  831|      1|        }
  832|       |        // Sort all keys with ascending time values and remove duplicates?
  833|      1|        if (sortKeys) {
  ------------------
  |  Branch (833:13): [True: 0, False: 1]
  ------------------
  834|      0|            std::stable_sort(l->begin(), l->end());
  835|      0|            l->erase(std::unique(l->begin(), l->end(), &KeyUniqueCompare<aiQuatKey>), l->end());
  836|      0|        }
  837|      1|    } break;
  838|       |
  839|       |        // ////////////////////////////////////////////////////////////////////
  840|       |        // SCALING KEYFRAME
  841|      1|    case Discreet3DS::CHUNK_TRACKSCALE: {
  ------------------
  |  Branch (841:5): [True: 1, False: 5]
  ------------------
  842|      1|        mStream->IncPtr(10);
  843|      1|        const unsigned int numFrames = mStream->GetI2();
  844|      1|        mStream->IncPtr(2);
  845|       |
  846|      1|        bool sortKeys = false;
  847|      1|        std::vector<aiVectorKey> *l = &mCurrentNode->aScalingKeys;
  848|      1|        l->reserve(numFrames);
  849|       |
  850|      2|        for (unsigned int i = 0; i < numFrames; ++i) {
  ------------------
  |  Branch (850:34): [True: 1, False: 1]
  ------------------
  851|      1|            const unsigned int fidx = mStream->GetI4();
  852|      1|            SkipTCBInfo();
  853|       |
  854|       |            // Setup a new key
  855|      1|            aiVectorKey v;
  856|      1|            v.mTime = (double)fidx;
  857|       |
  858|       |            // ... and read its value
  859|      1|            v.mValue.x = mStream->GetF4();
  860|      1|            v.mValue.y = mStream->GetF4();
  861|      1|            v.mValue.z = mStream->GetF4();
  862|       |
  863|       |            // check whether we'll need to sort the keys
  864|      1|            if (!l->empty() && v.mTime <= l->back().mTime)
  ------------------
  |  Branch (864:17): [True: 0, False: 1]
  |  Branch (864:32): [True: 0, False: 0]
  ------------------
  865|      0|                sortKeys = true;
  866|       |
  867|       |            // Remove zero-scalings on singular axes - they've been reported to be there erroneously in some strange files
  868|      1|            if (!v.mValue.x) v.mValue.x = 1.f;
  ------------------
  |  Branch (868:17): [True: 0, False: 1]
  ------------------
  869|      1|            if (!v.mValue.y) v.mValue.y = 1.f;
  ------------------
  |  Branch (869:17): [True: 0, False: 1]
  ------------------
  870|      1|            if (!v.mValue.z) v.mValue.z = 1.f;
  ------------------
  |  Branch (870:17): [True: 0, False: 1]
  ------------------
  871|       |
  872|      1|            l->push_back(v);
  873|      1|        }
  874|       |        // Sort all keys with ascending time values and remove duplicates?
  875|      1|        if (sortKeys) {
  ------------------
  |  Branch (875:13): [True: 0, False: 1]
  ------------------
  876|      0|            std::stable_sort(l->begin(), l->end());
  877|      0|            l->erase(std::unique(l->begin(), l->end(), &KeyUniqueCompare<aiVectorKey>), l->end());
  878|      0|        }
  879|      1|    } break;
  880|     18|    };
  881|       |
  882|      6|    ASSIMP_3DS_END_CHUNK();
  ------------------
  |  |   95|      6|    mStream->SkipToReadLimit();                  \
  |  |   96|      6|    mStream->SetReadLimit(oldReadLimit);         \
  |  |   97|      6|    if (mStream->GetRemainingSizeToLimit() == 0) \
  |  |  ------------------
  |  |  |  Branch (97:9): [True: 1, False: 5]
  |  |  ------------------
  |  |   98|      6|        return;                                 \
  |  |   99|      6|    }
  ------------------
  883|      0|}
_ZN6Assimp19Discreet3DSImporter14ParseFaceChunkEv:
  887|      4|void Discreet3DSImporter::ParseFaceChunk() {
  888|     24|    ASSIMP_3DS_BEGIN_CHUNK();
  ------------------
  |  |   79|      8|    while (true) {                                                            \
  |  |  ------------------
  |  |  |  Branch (79:12): [True: 8, Folded]
  |  |  ------------------
  |  |   80|      8|        if (mStream->GetRemainingSizeToLimit() < sizeof(Discreet3DS::Chunk)) { \
  |  |  ------------------
  |  |  |  Branch (80:13): [True: 0, False: 8]
  |  |  ------------------
  |  |   81|      0|            return;                                                           \
  |  |   82|      0|        }                                                                     \
  |  |   83|      8|        Discreet3DS::Chunk chunk;                                             \
  |  |   84|      8|        ReadChunk(&chunk);                                                    \
  |  |   85|      8|        int chunkSize = chunk.Size - sizeof(Discreet3DS::Chunk);              \
  |  |   86|      8|        if (chunkSize <= 0)                                                   \
  |  |  ------------------
  |  |  |  Branch (86:13): [True: 0, False: 8]
  |  |  ------------------
  |  |   87|      8|            continue;                                                         \
  |  |   88|      8|        const unsigned int oldReadLimit = mStream->SetReadLimit(               \
  |  |   89|      8|                mStream->GetCurrentPos() + chunkSize);
  ------------------
  889|       |
  890|       |    // Get the mesh we're currently working on
  891|     24|    D3DS::Mesh &mMesh = mScene->mMeshes.back();
  892|       |
  893|       |    // Get chunk type
  894|     24|    switch (chunk.Flag) {
  ------------------
  |  Branch (894:13): [True: 8, False: 0]
  ------------------
  895|      1|    case Discreet3DS::CHUNK_SMOOLIST: {
  ------------------
  |  Branch (895:5): [True: 1, False: 7]
  ------------------
  896|       |        // This is the list of smoothing groups - a bitfield for every face.
  897|       |        // Up to 32 smoothing groups assigned to a single face.
  898|      1|        unsigned int num = chunkSize / 4, m = 0;
  899|      1|        if (num > mMesh.mFaces.size()) {
  ------------------
  |  Branch (899:13): [True: 0, False: 1]
  ------------------
  900|      0|            throw DeadlyImportError("3DS: More smoothing groups than faces");
  901|      0|        }
  902|  1.36k|        for (auto i = mMesh.mFaces.begin(); m != num; ++i, ++m) {
  ------------------
  |  Branch (902:45): [True: 1.36k, False: 1]
  ------------------
  903|       |            // nth bit is set for nth smoothing group
  904|  1.36k|            i->iSmoothGroup = mStream->GetI4();
  905|  1.36k|        }
  906|      1|    } break;
  907|       |
  908|      7|    case Discreet3DS::CHUNK_FACEMAT: {
  ------------------
  |  Branch (908:5): [True: 7, False: 1]
  ------------------
  909|       |        // at fist an asciiz with the material name
  910|      7|        const char *sz = (const char *)mStream->GetPtr();
  911|     84|        while (mStream->GetI1())
  ------------------
  |  Branch (911:16): [True: 77, False: 7]
  ------------------
  912|     77|            ;
  913|       |
  914|       |        // find the index of the material
  915|      7|        unsigned int idx = 0xcdcdcdcd, cnt = 0;
  916|     14|        for (auto i = mScene->mMaterials.begin(); i != mScene->mMaterials.end(); ++i, ++cnt) {
  ------------------
  |  Branch (916:51): [True: 13, False: 1]
  ------------------
  917|       |            // use case independent comparisons. hopefully it will work.
  918|     13|            if (i->mName.length() && !ASSIMP_stricmp(sz, i->mName.c_str())) {
  ------------------
  |  Branch (918:17): [True: 13, False: 0]
  |  Branch (918:38): [True: 6, False: 7]
  ------------------
  919|      6|                idx = cnt;
  920|      6|                break;
  921|      6|            }
  922|     13|        }
  923|      7|        if (0xcdcdcdcd == idx) {
  ------------------
  |  Branch (923:13): [True: 1, False: 6]
  ------------------
  924|      1|            ASSIMP_LOG_ERROR("3DS: Unknown material: ", sz);
  925|      1|        }
  926|       |
  927|       |        // Now continue and read all material indices
  928|      7|        cnt = (uint16_t)mStream->GetI2();
  929|  2.91k|        for (unsigned int i = 0; i < cnt; ++i) {
  ------------------
  |  Branch (929:34): [True: 2.90k, False: 7]
  ------------------
  930|  2.90k|            unsigned int fidx = (uint16_t)mStream->GetI2();
  931|       |
  932|       |            // check range
  933|  2.90k|            if (fidx >= mMesh.mFaceMaterials.size()) {
  ------------------
  |  Branch (933:17): [True: 2, False: 2.90k]
  ------------------
  934|      2|                ASSIMP_LOG_ERROR("3DS: Invalid face index in face material list");
  935|      2|            } else
  936|  2.90k|                mMesh.mFaceMaterials[fidx] = idx;
  937|  2.90k|        }
  938|      7|    } break;
  939|     24|    };
  940|      8|    ASSIMP_3DS_END_CHUNK();
  ------------------
  |  |   95|      8|    mStream->SkipToReadLimit();                  \
  |  |   96|      8|    mStream->SetReadLimit(oldReadLimit);         \
  |  |   97|      8|    if (mStream->GetRemainingSizeToLimit() == 0) \
  |  |  ------------------
  |  |  |  Branch (97:9): [True: 4, False: 4]
  |  |  ------------------
  |  |   98|      8|        return;                                 \
  |  |   99|      8|    }
  ------------------
  941|      0|}
_ZN6Assimp19Discreet3DSImporter14ParseMeshChunkEv:
  945|      9|void Discreet3DSImporter::ParseMeshChunk() {
  946|     66|    ASSIMP_3DS_BEGIN_CHUNK();
  ------------------
  |  |   79|     22|    while (true) {                                                            \
  |  |  ------------------
  |  |  |  Branch (79:12): [True: 22, Folded]
  |  |  ------------------
  |  |   80|     22|        if (mStream->GetRemainingSizeToLimit() < sizeof(Discreet3DS::Chunk)) { \
  |  |  ------------------
  |  |  |  Branch (80:13): [True: 0, False: 22]
  |  |  ------------------
  |  |   81|      0|            return;                                                           \
  |  |   82|      0|        }                                                                     \
  |  |   83|     22|        Discreet3DS::Chunk chunk;                                             \
  |  |   84|     22|        ReadChunk(&chunk);                                                    \
  |  |   85|     22|        int chunkSize = chunk.Size - sizeof(Discreet3DS::Chunk);              \
  |  |   86|     22|        if (chunkSize <= 0)                                                   \
  |  |  ------------------
  |  |  |  Branch (86:13): [True: 0, False: 22]
  |  |  ------------------
  |  |   87|     22|            continue;                                                         \
  |  |   88|     22|        const unsigned int oldReadLimit = mStream->SetReadLimit(               \
  |  |   89|     22|                mStream->GetCurrentPos() + chunkSize);
  ------------------
  947|       |
  948|       |    // Get the mesh we're currently working on
  949|     66|    D3DS::Mesh &mMesh = mScene->mMeshes.back();
  950|       |
  951|       |    // get chunk type
  952|     66|    switch (chunk.Flag) {
  ------------------
  |  Branch (952:13): [True: 14, False: 8]
  ------------------
  953|      9|    case Discreet3DS::CHUNK_VERTLIST: {
  ------------------
  |  Branch (953:5): [True: 9, False: 13]
  ------------------
  954|       |        // This is the list of all vertices in the current mesh
  955|      9|        int num = (int)(uint16_t)mStream->GetI2();
  956|      9|        mMesh.mPositions.reserve(num);
  957|  2.05k|        while (num-- > 0) {
  ------------------
  |  Branch (957:16): [True: 2.05k, False: 9]
  ------------------
  958|  2.05k|            aiVector3D v;
  959|  2.05k|            v.x = mStream->GetF4();
  960|  2.05k|            v.y = mStream->GetF4();
  961|  2.05k|            v.z = mStream->GetF4();
  962|  2.05k|            mMesh.mPositions.push_back(v);
  963|  2.05k|        }
  964|      9|    } break;
  965|      1|    case Discreet3DS::CHUNK_TRMATRIX: {
  ------------------
  |  Branch (965:5): [True: 1, False: 21]
  ------------------
  966|       |        // This is the RLEATIVE transformation matrix of the current mesh. Vertices are
  967|       |        // pretransformed by this matrix wonder.
  968|      1|        mMesh.mMat.a1 = mStream->GetF4();
  969|      1|        mMesh.mMat.b1 = mStream->GetF4();
  970|      1|        mMesh.mMat.c1 = mStream->GetF4();
  971|      1|        mMesh.mMat.a2 = mStream->GetF4();
  972|      1|        mMesh.mMat.b2 = mStream->GetF4();
  973|      1|        mMesh.mMat.c2 = mStream->GetF4();
  974|      1|        mMesh.mMat.a3 = mStream->GetF4();
  975|      1|        mMesh.mMat.b3 = mStream->GetF4();
  976|      1|        mMesh.mMat.c3 = mStream->GetF4();
  977|      1|        mMesh.mMat.a4 = mStream->GetF4();
  978|      1|        mMesh.mMat.b4 = mStream->GetF4();
  979|      1|        mMesh.mMat.c4 = mStream->GetF4();
  980|      1|    } break;
  981|       |
  982|      0|    case Discreet3DS::CHUNK_MAPLIST: {
  ------------------
  |  Branch (982:5): [True: 0, False: 22]
  ------------------
  983|       |        // This is the list of all UV coords in the current mesh
  984|      0|        int num = (int)(uint16_t)mStream->GetI2();
  985|      0|        mMesh.mTexCoords.reserve(num);
  986|      0|        while (num-- > 0) {
  ------------------
  |  Branch (986:16): [True: 0, False: 0]
  ------------------
  987|      0|            aiVector3D v;
  988|      0|            v.x = mStream->GetF4();
  989|      0|            v.y = mStream->GetF4();
  990|      0|            mMesh.mTexCoords.push_back(v);
  991|      0|        }
  992|      0|    } break;
  993|       |
  994|      4|    case Discreet3DS::CHUNK_FACELIST: {
  ------------------
  |  Branch (994:5): [True: 4, False: 18]
  ------------------
  995|       |        // This is the list of all faces in the current mesh
  996|      4|        int num = (int)(uint16_t)mStream->GetI2();
  997|      4|        mMesh.mFaces.reserve(num);
  998|  3.67k|        while (num-- > 0) {
  ------------------
  |  Branch (998:16): [True: 3.67k, False: 4]
  ------------------
  999|       |            // 3DS faces are ALWAYS triangles
 1000|  3.67k|            mMesh.mFaces.emplace_back();
 1001|  3.67k|            Face &sFace = mMesh.mFaces.back();
 1002|       |
 1003|  3.67k|            sFace.mIndices[0] = (uint16_t)mStream->GetI2();
 1004|  3.67k|            sFace.mIndices[1] = (uint16_t)mStream->GetI2();
 1005|  3.67k|            sFace.mIndices[2] = (uint16_t)mStream->GetI2();
 1006|       |
 1007|  3.67k|            mStream->IncPtr(2); // skip edge visibility flag
 1008|  3.67k|        }
 1009|       |
 1010|       |        // Resize the material array (0xcdcdcdcd marks the default material; so if a face is
 1011|       |        // not referenced by a material, $$DEFAULT will be assigned to it)
 1012|      4|        mMesh.mFaceMaterials.resize(mMesh.mFaces.size(), 0xcdcdcdcd);
 1013|       |
 1014|       |        // Larger 3DS files could have multiple FACE chunks here
 1015|      4|        chunkSize = (int)mStream->GetRemainingSizeToLimit();
 1016|      4|        if (chunkSize > (int)sizeof(Discreet3DS::Chunk))
  ------------------
  |  Branch (1016:13): [True: 4, False: 0]
  ------------------
 1017|      4|            ParseFaceChunk();
 1018|      4|    } break;
 1019|     66|    };
 1020|     17|    ASSIMP_3DS_END_CHUNK();
  ------------------
  |  |   95|     17|    mStream->SkipToReadLimit();                  \
  |  |   96|     17|    mStream->SetReadLimit(oldReadLimit);         \
  |  |   97|     17|    if (mStream->GetRemainingSizeToLimit() == 0) \
  |  |  ------------------
  |  |  |  Branch (97:9): [True: 4, False: 13]
  |  |  ------------------
  |  |   98|     17|        return;                                 \
  |  |   99|     17|    }
  ------------------
 1021|      0|}
_ZN6Assimp19Discreet3DSImporter18ParseMaterialChunkEv:
 1025|      7|void Discreet3DSImporter::ParseMaterialChunk() {
 1026|    132|    ASSIMP_3DS_BEGIN_CHUNK();
  ------------------
  |  |   79|     44|    while (true) {                                                            \
  |  |  ------------------
  |  |  |  Branch (79:12): [True: 44, Folded]
  |  |  ------------------
  |  |   80|     44|        if (mStream->GetRemainingSizeToLimit() < sizeof(Discreet3DS::Chunk)) { \
  |  |  ------------------
  |  |  |  Branch (80:13): [True: 0, False: 44]
  |  |  ------------------
  |  |   81|      0|            return;                                                           \
  |  |   82|      0|        }                                                                     \
  |  |   83|     44|        Discreet3DS::Chunk chunk;                                             \
  |  |   84|     44|        ReadChunk(&chunk);                                                    \
  |  |   85|     44|        int chunkSize = chunk.Size - sizeof(Discreet3DS::Chunk);              \
  |  |   86|     44|        if (chunkSize <= 0)                                                   \
  |  |  ------------------
  |  |  |  Branch (86:13): [True: 0, False: 44]
  |  |  ------------------
  |  |   87|     44|            continue;                                                         \
  |  |   88|     44|        const unsigned int oldReadLimit = mStream->SetReadLimit(               \
  |  |   89|     44|                mStream->GetCurrentPos() + chunkSize);
  ------------------
 1027|    132|    switch (chunk.Flag) {
  ------------------
  |  Branch (1027:13): [True: 44, False: 0]
  ------------------
 1028|      7|    case Discreet3DS::CHUNK_MAT_MATNAME:
  ------------------
  |  Branch (1028:5): [True: 7, False: 37]
  ------------------
 1029|       |
 1030|      7|    {
 1031|       |        // The material name string is already zero-terminated, but we need to be sure ...
 1032|      7|        const char *sz = (const char *)mStream->GetPtr();
 1033|      7|        unsigned int cnt = 0;
 1034|     72|        while (mStream->GetI1())
  ------------------
  |  Branch (1034:16): [True: 65, False: 7]
  ------------------
 1035|     65|            ++cnt;
 1036|       |
 1037|      7|        if (!cnt) {
  ------------------
  |  Branch (1037:13): [True: 0, False: 7]
  ------------------
 1038|       |            // This may not be, we use the default name instead
 1039|      0|            ASSIMP_LOG_ERROR("3DS: Empty material name");
 1040|      0|        } else
 1041|      7|            mScene->mMaterials.back().mName = std::string(sz, cnt);
 1042|      7|    } break;
 1043|       |
 1044|      7|    case Discreet3DS::CHUNK_MAT_DIFFUSE: {
  ------------------
  |  Branch (1044:5): [True: 7, False: 37]
  ------------------
 1045|       |        // This is the diffuse material color
 1046|      7|        aiColor3D *pc = &mScene->mMaterials.back().mDiffuse;
 1047|      7|        ParseColorChunk(pc);
 1048|      7|        if (is_qnan(pc->r)) {
  ------------------
  |  Branch (1048:13): [True: 0, False: 7]
  ------------------
 1049|       |            // color chunk is invalid. Simply ignore it
 1050|      0|            ASSIMP_LOG_ERROR("3DS: Unable to read DIFFUSE chunk");
 1051|      0|            pc->r = pc->g = pc->b = 1.0f;
 1052|      0|        }
 1053|      7|    } break;
 1054|       |
 1055|      3|    case Discreet3DS::CHUNK_MAT_SPECULAR: {
  ------------------
  |  Branch (1055:5): [True: 3, False: 41]
  ------------------
 1056|       |        // This is the specular material color
 1057|      3|        aiColor3D *pc = &mScene->mMaterials.back().mSpecular;
 1058|      3|        ParseColorChunk(pc);
 1059|      3|        if (is_qnan(pc->r)) {
  ------------------
  |  Branch (1059:13): [True: 0, False: 3]
  ------------------
 1060|       |            // color chunk is invalid. Simply ignore it
 1061|      0|            ASSIMP_LOG_ERROR("3DS: Unable to read SPECULAR chunk");
 1062|      0|            pc->r = pc->g = pc->b = 1.0f;
 1063|      0|        }
 1064|      3|    } break;
 1065|       |
 1066|      3|    case Discreet3DS::CHUNK_MAT_AMBIENT: {
  ------------------
  |  Branch (1066:5): [True: 3, False: 41]
  ------------------
 1067|       |        // This is the ambient material color
 1068|      3|        aiColor3D *pc = &mScene->mMaterials.back().mAmbient;
 1069|      3|        ParseColorChunk(pc);
 1070|      3|        if (is_qnan(pc->r)) {
  ------------------
  |  Branch (1070:13): [True: 0, False: 3]
  ------------------
 1071|       |            // color chunk is invalid. Simply ignore it
 1072|      0|            ASSIMP_LOG_ERROR("3DS: Unable to read AMBIENT chunk");
 1073|      0|            pc->r = pc->g = pc->b = 0.0f;
 1074|      0|        }
 1075|      3|    } break;
 1076|       |
 1077|      0|    case Discreet3DS::CHUNK_MAT_SELF_ILLUM: {
  ------------------
  |  Branch (1077:5): [True: 0, False: 44]
  ------------------
 1078|       |        // This is the emissive material color
 1079|      0|        aiColor3D *pc = &mScene->mMaterials.back().mEmissive;
 1080|      0|        ParseColorChunk(pc);
 1081|      0|        if (is_qnan(pc->r)) {
  ------------------
  |  Branch (1081:13): [True: 0, False: 0]
  ------------------
 1082|       |            // color chunk is invalid. Simply ignore it
 1083|      0|            ASSIMP_LOG_ERROR("3DS: Unable to read EMISSIVE chunk");
 1084|      0|            pc->r = pc->g = pc->b = 0.0f;
 1085|      0|        }
 1086|      0|    } break;
 1087|       |
 1088|      7|    case Discreet3DS::CHUNK_MAT_TRANSPARENCY: {
  ------------------
  |  Branch (1088:5): [True: 7, False: 37]
  ------------------
 1089|       |        // This is the material's transparency
 1090|      7|        ai_real *pcf = &mScene->mMaterials.back().mTransparency;
 1091|      7|        *pcf = ParsePercentageChunk();
 1092|       |
 1093|       |        // NOTE: transparency, not opacity
 1094|      7|        if (is_qnan(*pcf))
  ------------------
  |  Branch (1094:13): [True: 0, False: 7]
  ------------------
 1095|      0|            *pcf = ai_real(1.0);
 1096|      7|        else
 1097|      7|            *pcf = ai_real(1.0) - *pcf * (ai_real)0xFFFF / ai_real(100.0);
 1098|      7|    } break;
 1099|       |
 1100|      7|    case Discreet3DS::CHUNK_MAT_SHADING:
  ------------------
  |  Branch (1100:5): [True: 7, False: 37]
  ------------------
 1101|       |        // This is the material shading mode
 1102|      7|        mScene->mMaterials.back().mShading = (Discreet3DS::shadetype3ds)mStream->GetI2();
 1103|      7|        break;
 1104|       |
 1105|      0|    case Discreet3DS::CHUNK_MAT_TWO_SIDE:
  ------------------
  |  Branch (1105:5): [True: 0, False: 44]
  ------------------
 1106|       |        // This is the two-sided flag
 1107|      0|        mScene->mMaterials.back().mTwoSided = true;
 1108|      0|        break;
 1109|       |
 1110|      7|    case Discreet3DS::CHUNK_MAT_SHININESS: { // This is the shininess of the material
  ------------------
  |  Branch (1110:5): [True: 7, False: 37]
  ------------------
 1111|      7|        ai_real *pcf = &mScene->mMaterials.back().mSpecularExponent;
 1112|      7|        *pcf = ParsePercentageChunk();
 1113|      7|        if (is_qnan(*pcf))
  ------------------
  |  Branch (1113:13): [True: 0, False: 7]
  ------------------
 1114|      0|            *pcf = 0.0;
 1115|      7|        else
 1116|      7|            *pcf *= (ai_real)0xFFFF;
 1117|      7|    } break;
 1118|       |
 1119|      3|    case Discreet3DS::CHUNK_MAT_SHININESS_PERCENT: { // This is the shininess strength of the material
  ------------------
  |  Branch (1119:5): [True: 3, False: 41]
  ------------------
 1120|      3|        ai_real *pcf = &mScene->mMaterials.back().mShininessStrength;
 1121|      3|        *pcf = ParsePercentageChunk();
 1122|      3|        if (is_qnan(*pcf))
  ------------------
  |  Branch (1122:13): [True: 0, False: 3]
  ------------------
 1123|      0|            *pcf = ai_real(0.0);
 1124|      3|        else
 1125|      3|            *pcf *= (ai_real)0xffff / ai_real(100.0);
 1126|      3|    } break;
 1127|       |
 1128|      0|    case Discreet3DS::CHUNK_MAT_SELF_ILPCT: { // This is the self illumination strength of the material
  ------------------
  |  Branch (1128:5): [True: 0, False: 44]
  ------------------
 1129|      0|        ai_real f = ParsePercentageChunk();
 1130|      0|        if (is_qnan(f))
  ------------------
  |  Branch (1130:13): [True: 0, False: 0]
  ------------------
 1131|      0|            f = ai_real(0.0);
 1132|      0|        else
 1133|      0|            f *= (ai_real)0xFFFF / ai_real(100.0);
 1134|      0|        mScene->mMaterials.back().mEmissive = aiColor3D(f, f, f);
 1135|      0|    } break;
 1136|       |
 1137|       |    // Parse texture chunks
 1138|      0|    case Discreet3DS::CHUNK_MAT_TEXTURE:
  ------------------
  |  Branch (1138:5): [True: 0, False: 44]
  ------------------
 1139|       |        // Diffuse texture
 1140|      0|        ParseTextureChunk(&mScene->mMaterials.back().sTexDiffuse);
 1141|      0|        break;
 1142|      0|    case Discreet3DS::CHUNK_MAT_BUMPMAP:
  ------------------
  |  Branch (1142:5): [True: 0, False: 44]
  ------------------
 1143|       |        // Height map
 1144|      0|        ParseTextureChunk(&mScene->mMaterials.back().sTexBump);
 1145|      0|        break;
 1146|      0|    case Discreet3DS::CHUNK_MAT_OPACMAP:
  ------------------
  |  Branch (1146:5): [True: 0, False: 44]
  ------------------
 1147|       |        // Opacity texture
 1148|      0|        ParseTextureChunk(&mScene->mMaterials.back().sTexOpacity);
 1149|      0|        break;
 1150|      0|    case Discreet3DS::CHUNK_MAT_MAT_SHINMAP:
  ------------------
  |  Branch (1150:5): [True: 0, False: 44]
  ------------------
 1151|       |        // Shininess map
 1152|      0|        ParseTextureChunk(&mScene->mMaterials.back().sTexShininess);
 1153|      0|        break;
 1154|      0|    case Discreet3DS::CHUNK_MAT_SPECMAP:
  ------------------
  |  Branch (1154:5): [True: 0, False: 44]
  ------------------
 1155|       |        // Specular map
 1156|      0|        ParseTextureChunk(&mScene->mMaterials.back().sTexSpecular);
 1157|      0|        break;
 1158|      0|    case Discreet3DS::CHUNK_MAT_SELFIMAP:
  ------------------
  |  Branch (1158:5): [True: 0, False: 44]
  ------------------
 1159|       |        // Self-illumination (emissive) map
 1160|      0|        ParseTextureChunk(&mScene->mMaterials.back().sTexEmissive);
 1161|      0|        break;
 1162|      0|    case Discreet3DS::CHUNK_MAT_REFLMAP:
  ------------------
  |  Branch (1162:5): [True: 0, False: 44]
  ------------------
 1163|       |        // Reflection map
 1164|      0|        ParseTextureChunk(&mScene->mMaterials.back().sTexReflective);
 1165|      0|        break;
 1166|    132|    };
 1167|     44|    ASSIMP_3DS_END_CHUNK();
  ------------------
  |  |   95|     44|    mStream->SkipToReadLimit();                  \
  |  |   96|     44|    mStream->SetReadLimit(oldReadLimit);         \
  |  |   97|     44|    if (mStream->GetRemainingSizeToLimit() == 0) \
  |  |  ------------------
  |  |  |  Branch (97:9): [True: 7, False: 37]
  |  |  ------------------
  |  |   98|     44|        return;                                 \
  |  |   99|     44|    }
  ------------------
 1168|      0|}
_ZN6Assimp19Discreet3DSImporter20ParsePercentageChunkEv:
 1253|     17|ai_real Discreet3DSImporter::ParsePercentageChunk() {
 1254|     17|    Discreet3DS::Chunk chunk;
 1255|     17|    ReadChunk(&chunk);
 1256|       |
 1257|     17|    if (Discreet3DS::CHUNK_PERCENTF == chunk.Flag) {
  ------------------
  |  Branch (1257:9): [True: 0, False: 17]
  ------------------
 1258|      0|        return mStream->GetF4() * ai_real(100) / ai_real(0xFFFF);
 1259|      0|    }
 1260|       |
 1261|     17|    if (Discreet3DS::CHUNK_PERCENTW == chunk.Flag) {
  ------------------
  |  Branch (1261:9): [True: 17, False: 0]
  ------------------
 1262|     17|        return (ai_real)((uint16_t)mStream->GetI2()) / (ai_real)0xFFFF;
 1263|     17|    }
 1264|       |
 1265|      0|    return get_qnan();
 1266|     17|}
_ZN6Assimp19Discreet3DSImporter15ParseColorChunkEP9aiColor3Db:
 1270|     13|void Discreet3DSImporter::ParseColorChunk(aiColor3D *out, bool acceptPercent) {
 1271|     13|    ai_assert(out != nullptr);
 1272|       |
 1273|       |    // error return value
 1274|     13|    const ai_real qnan = get_qnan();
 1275|     13|    static const aiColor3D clrError = aiColor3D(qnan, qnan, qnan);
 1276|       |
 1277|     13|    Discreet3DS::Chunk chunk;
 1278|     13|    ReadChunk(&chunk);
 1279|     13|    const unsigned int diff = chunk.Size - sizeof(Discreet3DS::Chunk);
 1280|       |
 1281|     13|    bool bGamma = false;
 1282|       |
 1283|       |    // Get the type of the chunk
 1284|     13|    switch (chunk.Flag) {
 1285|      0|    case Discreet3DS::CHUNK_LINRGBF:
  ------------------
  |  Branch (1285:5): [True: 0, False: 13]
  ------------------
 1286|      0|        bGamma = true;
 1287|       |    // fallthrough
 1288|      0|    case Discreet3DS::CHUNK_RGBF:
  ------------------
  |  Branch (1288:5): [True: 0, False: 13]
  ------------------
 1289|      0|        if (sizeof(float) * 3 > diff) {
  ------------------
  |  Branch (1289:13): [True: 0, False: 0]
  ------------------
 1290|      0|            *out = clrError;
 1291|      0|            return;
 1292|      0|        }
 1293|      0|        out->r = mStream->GetF4();
 1294|      0|        out->g = mStream->GetF4();
 1295|      0|        out->b = mStream->GetF4();
 1296|      0|        break;
 1297|       |
 1298|      0|    case Discreet3DS::CHUNK_LINRGBB:
  ------------------
  |  Branch (1298:5): [True: 0, False: 13]
  ------------------
 1299|      0|        bGamma = true;
 1300|       |            // fallthrough
 1301|     13|    case Discreet3DS::CHUNK_RGBB: {
  ------------------
  |  Branch (1301:5): [True: 13, False: 0]
  ------------------
 1302|     13|        if (sizeof(char) * 3 > diff) {
  ------------------
  |  Branch (1302:13): [True: 0, False: 13]
  ------------------
 1303|      0|            *out = clrError;
 1304|      0|            return;
 1305|      0|        }
 1306|     13|        const ai_real invVal = ai_real(1.0) / ai_real(255.0);
 1307|     13|        out->r = (ai_real)(uint8_t)mStream->GetI1() * invVal;
 1308|     13|        out->g = (ai_real)(uint8_t)mStream->GetI1() * invVal;
 1309|     13|        out->b = (ai_real)(uint8_t)mStream->GetI1() * invVal;
 1310|     13|    } break;
 1311|       |
 1312|       |    // Percentage chunks are accepted, too.
 1313|      0|    case Discreet3DS::CHUNK_PERCENTF:
  ------------------
  |  Branch (1313:5): [True: 0, False: 13]
  ------------------
 1314|      0|        if (acceptPercent && 4 <= diff) {
  ------------------
  |  Branch (1314:13): [True: 0, False: 0]
  |  Branch (1314:30): [True: 0, False: 0]
  ------------------
 1315|      0|            out->g = out->b = out->r = mStream->GetF4();
 1316|      0|            break;
 1317|      0|        }
 1318|      0|        *out = clrError;
 1319|      0|        return;
 1320|       |
 1321|      0|    case Discreet3DS::CHUNK_PERCENTW:
  ------------------
  |  Branch (1321:5): [True: 0, False: 13]
  ------------------
 1322|      0|        if (acceptPercent && 1 <= diff) {
  ------------------
  |  Branch (1322:13): [True: 0, False: 0]
  |  Branch (1322:30): [True: 0, False: 0]
  ------------------
 1323|      0|            out->g = out->b = out->r = (ai_real)(uint8_t)mStream->GetI1() / ai_real(255.0);
 1324|      0|            break;
 1325|      0|        }
 1326|      0|        *out = clrError;
 1327|      0|        return;
 1328|       |
 1329|      0|    default:
  ------------------
  |  Branch (1329:5): [True: 0, False: 13]
  ------------------
 1330|      0|        mStream->IncPtr(diff);
 1331|       |        // Skip unknown chunks, hope this won't cause any problems.
 1332|      0|        return ParseColorChunk(out, acceptPercent);
 1333|     13|    };
 1334|     13|    (void)bGamma;
 1335|     13|}

_ZNK6Assimp19Discreet3DSImporter16ContainsTexturesEj:
  201|      2|    bool ContainsTextures(unsigned int i) const {
  202|      2|        return !mScene->mMaterials[i].sTexDiffuse.mMapName.empty() ||
  ------------------
  |  Branch (202:16): [True: 0, False: 2]
  ------------------
  203|      2|               !mScene->mMaterials[i].sTexBump.mMapName.empty() ||
  ------------------
  |  Branch (203:16): [True: 0, False: 2]
  ------------------
  204|      2|               !mScene->mMaterials[i].sTexOpacity.mMapName.empty() ||
  ------------------
  |  Branch (204:16): [True: 0, False: 2]
  ------------------
  205|      2|               !mScene->mMaterials[i].sTexEmissive.mMapName.empty() ||
  ------------------
  |  Branch (205:16): [True: 0, False: 2]
  ------------------
  206|      2|               !mScene->mMaterials[i].sTexSpecular.mMapName.empty() ||
  ------------------
  |  Branch (206:16): [True: 0, False: 2]
  ------------------
  207|      2|               !mScene->mMaterials[i].sTexShininess.mMapName.empty() ;
  ------------------
  |  Branch (207:16): [True: 0, False: 2]
  ------------------
  208|      2|    }
_ZN6Assimp19Discreet3DSImporterD2Ev:
   65|    624|    ~Discreet3DSImporter() override = default;

_ZNK6Assimp12D3MFImporter7CanReadERKNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEPNS_8IOSystemEb:
   84|     43|bool D3MFImporter::CanRead(const std::string &filename, IOSystem *pIOHandler, bool ) const {
   85|     43|    if (!ZipArchiveIOSystem::isZipArchive(pIOHandler, filename)) {
  ------------------
  |  Branch (85:9): [True: 36, False: 7]
  ------------------
   86|     36|        return false;
   87|     36|    }
   88|      7|    static constexpr char ModelRef[] = "3D/3dmodel.model";
   89|      7|    ZipArchiveIOSystem archive(pIOHandler, filename);
   90|      7|    if (!archive.Exists(ModelRef)) {
  ------------------
  |  Branch (90:9): [True: 7, False: 0]
  ------------------
   91|      7|        return false;
   92|      7|    }
   93|       |
   94|      0|    return true;
   95|      7|}
_ZNK6Assimp12D3MFImporter7GetInfoEv:
  101|    634|const aiImporterDesc *D3MFImporter::GetInfo() const {
  102|    634|    return &desc;
  103|    634|}

_ZN6Assimp12D3MFImporterC2Ev:
   59|    624|    D3MFImporter() = default;

_ZN6Assimp12AC3DImporterC2Ev:
  161|    624|        mBuffer(),
  162|       |        configSplitBFCull(),
  163|       |        configEvalSubdivision(),
  164|       |        mNumMeshes(),
  165|       |        mLights(),
  166|    624|        mLightsCounter(0),
  167|    624|        mGroupsCounter(0),
  168|    624|        mPolysCounter(0),
  169|    624|        mWorldsCounter(0) {
  170|       |    // nothing to be done here
  171|    624|}
_ZNK6Assimp12AC3DImporter7CanReadERKNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEPNS_8IOSystemEb:
  175|    352|bool AC3DImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool /*checkSig*/) const {
  176|    352|    static constexpr uint32_t tokens[] = { AI_MAKE_MAGIC("AC3D") };
  177|       |    return CheckMagicToken(pIOHandler, pFile, tokens, AI_COUNT_OF(tokens));
  178|    352|}
_ZNK6Assimp12AC3DImporter7GetInfoEv:
  182|    639|const aiImporterDesc *AC3DImporter::GetInfo() const {
  183|    639|    return &desc;
  184|    639|}
_ZN6Assimp12AC3DImporter11GetNextLineEv:
  188|  42.3k|bool AC3DImporter::GetNextLine() {
  189|  42.3k|    SkipLine(&mBuffer.data, mBuffer.end);
  190|  42.3k|    return SkipSpaces(&mBuffer.data, mBuffer.end);
  191|  42.3k|}
_ZN6Assimp12AC3DImporter17LoadObjectSectionERNSt3__16vectorINS0_6ObjectENS1_9allocatorIS3_EEEE:
  195|     13|bool AC3DImporter::LoadObjectSection(std::vector<Object> &objects) {
  196|     13|    if (!TokenMatch(mBuffer.data, "OBJECT", 6)) {
  ------------------
  |  Branch (196:9): [True: 0, False: 13]
  ------------------
  197|      0|        return false;
  198|      0|    }
  199|       |
  200|     13|    SkipSpaces(&mBuffer.data, mBuffer.end);
  201|       |
  202|     13|    ++mNumMeshes;
  203|       |
  204|     13|    objects.emplace_back();
  205|     13|    Object &obj = objects.back();
  206|       |
  207|     13|    aiLight *light = nullptr;
  208|     13|    if (!ASSIMP_strincmp(mBuffer.data, "light", 5)) {
  ------------------
  |  Branch (208:9): [True: 3, False: 10]
  ------------------
  209|       |        // This is a light source. Add it to the list
  210|      3|        mLights->push_back(light = new aiLight());
  211|       |
  212|       |        // Return a point light with no attenuation
  213|      3|        light->mType = aiLightSource_POINT;
  214|      3|        light->mColorDiffuse = light->mColorSpecular = aiColor3D(1.f, 1.f, 1.f);
  215|      3|        light->mAttenuationConstant = 1.f;
  216|       |
  217|       |        // Generate a default name for both the light source and the node
  218|      3|        light->mName.length = ::ai_snprintf(light->mName.data, AI_MAXLEN, "ACLight_%i", static_cast<unsigned int>(mLights->size()) - 1);
  219|      3|        obj.name = std::string(light->mName.data);
  220|       |
  221|      3|        ASSIMP_LOG_VERBOSE_DEBUG("AC3D: Light source encountered");
  222|      3|        obj.type = Object::Light;
  223|     10|    } else if (!ASSIMP_strincmp(mBuffer.data, "group", 5)) {
  ------------------
  |  Branch (223:16): [True: 0, False: 10]
  ------------------
  224|      0|        obj.type = Object::Group;
  225|     10|    } else if (!ASSIMP_strincmp(mBuffer.data, "world", 5)) {
  ------------------
  |  Branch (225:16): [True: 5, False: 5]
  ------------------
  226|      5|        obj.type = Object::World;
  227|      5|    } else {
  228|      5|        obj.type = Object::Poly;
  229|      5|    }
  230|       |
  231|     51|    while (GetNextLine()) {
  ------------------
  |  Branch (231:12): [True: 51, False: 0]
  ------------------
  232|     51|        if (TokenMatch(mBuffer.data, "kids", 4)) {
  ------------------
  |  Branch (232:13): [True: 13, False: 38]
  ------------------
  233|     13|            SkipSpaces(&mBuffer.data, mBuffer.end);
  234|     13|            unsigned int num = strtoul10(mBuffer.data, &mBuffer.data);
  235|     13|            GetNextLine();
  236|     13|            if (num) {
  ------------------
  |  Branch (236:17): [True: 5, False: 8]
  ------------------
  237|       |                // load the children of this object recursively
  238|      5|                obj.children.reserve(num);
  239|     13|                for (unsigned int i = 0; i < num; ++i) {
  ------------------
  |  Branch (239:42): [True: 8, False: 5]
  ------------------
  240|      8|                    if (!LoadObjectSection(obj.children)) {
  ------------------
  |  Branch (240:25): [True: 0, False: 8]
  ------------------
  241|      0|                        ASSIMP_LOG_WARN("AC3D: wrong number of kids");
  242|      0|                        break;
  243|      0|                    }
  244|      8|                }
  245|      5|            }
  246|     13|            return true;
  247|     38|        } else if (TokenMatch(mBuffer.data, "name", 4)) {
  ------------------
  |  Branch (247:20): [True: 8, False: 30]
  ------------------
  248|      8|            SkipSpaces(&mBuffer.data, mBuffer.data);
  249|      8|            mBuffer.data = AcGetString(mBuffer.data, mBuffer.end, obj.name);
  250|       |
  251|       |            // If this is a light source, we'll also need to store
  252|       |            // the name of the node in it.
  253|      8|            if (light) {
  ------------------
  |  Branch (253:17): [True: 3, False: 5]
  ------------------
  254|      3|                light->mName.Set(obj.name);
  255|      3|            }
  256|     30|        } else if (TokenMatch(mBuffer.data, "texture", 7)) {
  ------------------
  |  Branch (256:20): [True: 6, False: 24]
  ------------------
  257|      6|            SkipSpaces(&mBuffer.data, mBuffer.end);
  258|      6|            std::string texture;
  259|      6|            mBuffer.data = AcGetString(mBuffer.data, mBuffer.end, texture);
  260|      6|            obj.textures.push_back(texture);
  261|     24|        } else if (TokenMatch(mBuffer.data, "texrep", 6)) {
  ------------------
  |  Branch (261:20): [True: 1, False: 23]
  ------------------
  262|      1|            SkipSpaces(&mBuffer.data, mBuffer.end);
  263|      1|            mBuffer.data = TAcCheckedLoadFloatArray(mBuffer.data, mBuffer.end, "", 0, 2, &obj.texRepeat);
  264|      1|            if (!obj.texRepeat.x || !obj.texRepeat.y)
  ------------------
  |  Branch (264:17): [True: 0, False: 1]
  |  Branch (264:37): [True: 0, False: 1]
  ------------------
  265|      0|                obj.texRepeat = aiVector2D(1.f, 1.f);
  266|     23|        } else if (TokenMatch(mBuffer.data, "texoff", 6)) {
  ------------------
  |  Branch (266:20): [True: 1, False: 22]
  ------------------
  267|      1|            SkipSpaces(&mBuffer.data, mBuffer.end);
  268|      1|            mBuffer.data = TAcCheckedLoadFloatArray(mBuffer.data, mBuffer.end, "", 0, 2, &obj.texOffset);
  269|     22|        } else if (TokenMatch(mBuffer.data, "rot", 3)) {
  ------------------
  |  Branch (269:20): [True: 0, False: 22]
  ------------------
  270|      0|            SkipSpaces(&mBuffer.data, mBuffer.end);
  271|      0|            mBuffer.data = TAcCheckedLoadFloatArray(mBuffer.data, mBuffer.end, "", 0, 9, &obj.rotation);
  272|     22|        } else if (TokenMatch(mBuffer.data, "loc", 3)) {
  ------------------
  |  Branch (272:20): [True: 5, False: 17]
  ------------------
  273|      5|            SkipSpaces(&mBuffer.data, mBuffer.end);
  274|      5|            mBuffer.data = TAcCheckedLoadFloatArray(mBuffer.data, mBuffer.end, "", 0, 3, &obj.translation);
  275|     17|        } else if (TokenMatch(mBuffer.data, "subdiv", 6)) {
  ------------------
  |  Branch (275:20): [True: 2, False: 15]
  ------------------
  276|      2|            SkipSpaces(&mBuffer.data, mBuffer.end);
  277|      2|            obj.subDiv = strtoul10(mBuffer.data, &mBuffer.data);
  278|     15|        } else if (TokenMatch(mBuffer.data, "crease", 6)) {
  ------------------
  |  Branch (278:20): [True: 3, False: 12]
  ------------------
  279|      3|            SkipSpaces(&mBuffer.data, mBuffer.end);
  280|      3|            obj.crease = fast_atof(mBuffer.data);
  281|     12|        } else if (TokenMatch(mBuffer.data, "numvert", 7)) {
  ------------------
  |  Branch (281:20): [True: 5, False: 7]
  ------------------
  282|      5|            SkipSpaces(&mBuffer.data, mBuffer.end);
  283|       |
  284|      5|            unsigned int t = strtoul10(mBuffer.data, &mBuffer.data);
  285|      5|            if (t >= AI_MAX_ALLOC(aiVector3D)) {
  ------------------
  |  Branch (285:17): [True: 0, False: 5]
  ------------------
  286|      0|                throw DeadlyImportError("AC3D: Too many vertices, would run out of memory");
  287|      0|            }
  288|      5|            obj.vertices.reserve(t);
  289|  6.79k|            for (unsigned int i = 0; i < t; ++i) {
  ------------------
  |  Branch (289:38): [True: 6.79k, False: 4]
  ------------------
  290|  6.79k|                if (!GetNextLine()) {
  ------------------
  |  Branch (290:21): [True: 0, False: 6.79k]
  ------------------
  291|      0|                    ASSIMP_LOG_ERROR("AC3D: Unexpected EOF: not all vertices have been parsed yet");
  292|      0|                    break;
  293|  6.79k|                } else if (!IsNumeric(*mBuffer.data)) {
  ------------------
  |  Branch (293:28): [True: 1, False: 6.78k]
  ------------------
  294|      1|                    ASSIMP_LOG_ERROR("AC3D: Unexpected token: not all vertices have been parsed yet");
  295|      1|                    --mBuffer.data; // make sure the line is processed a second time
  296|      1|                    break;
  297|      1|                }
  298|  6.78k|                obj.vertices.emplace_back();
  299|  6.78k|                aiVector3D &v = obj.vertices.back();
  300|  6.78k|                mBuffer.data = TAcCheckedLoadFloatArray(mBuffer.data, mBuffer.end, "", 0, 3, &v.x);
  301|  6.78k|            }
  302|      7|        } else if (TokenMatch(mBuffer.data, "numsurf", 7)) {
  ------------------
  |  Branch (302:20): [True: 5, False: 2]
  ------------------
  303|      5|            SkipSpaces(&mBuffer.data, mBuffer.end);
  304|       |
  305|      5|            bool Q3DWorkAround = false;
  306|       |
  307|      5|            const unsigned int t = strtoul10(mBuffer.data, &mBuffer.data);
  308|      5|            obj.surfaces.reserve(t);
  309|  4.38k|            for (unsigned int i = 0; i < t; ++i) {
  ------------------
  |  Branch (309:38): [True: 4.37k, False: 5]
  ------------------
  310|  4.37k|                GetNextLine();
  311|  4.37k|                if (!TokenMatch(mBuffer.data, "SURF", 4)) {
  ------------------
  |  Branch (311:21): [True: 0, False: 4.37k]
  ------------------
  312|       |                    // FIX: this can occur for some files - Quick 3D for
  313|       |                    // example writes no surf chunks
  314|      0|                    if (!Q3DWorkAround) {
  ------------------
  |  Branch (314:25): [True: 0, False: 0]
  ------------------
  315|      0|                        ASSIMP_LOG_WARN("AC3D: SURF token was expected");
  316|      0|                        ASSIMP_LOG_VERBOSE_DEBUG("Continuing with Quick3D Workaround enabled");
  317|      0|                    }
  318|      0|                    --mBuffer.data; // make sure the line is processed a second time
  319|       |                    // break; --- see fix notes above
  320|       |
  321|      0|                    Q3DWorkAround = true;
  322|      0|                }
  323|  4.37k|                SkipSpaces(&mBuffer.data, mBuffer.end);
  324|  4.37k|                obj.surfaces.emplace_back();
  325|  4.37k|                Surface &surf = obj.surfaces.back();
  326|  4.37k|                surf.flags = strtoul_cppstyle(mBuffer.data);
  327|       |
  328|  13.1k|                while (true) {
  ------------------
  |  Branch (328:24): [True: 13.1k, Folded]
  ------------------
  329|  13.1k|                    if (!GetNextLine()) {
  ------------------
  |  Branch (329:25): [True: 0, False: 13.1k]
  ------------------
  330|      0|                        throw DeadlyImportError("AC3D: Unexpected EOF: surface is incomplete");
  331|      0|                    }
  332|  13.1k|                    if (TokenMatch(mBuffer.data, "mat", 3)) {
  ------------------
  |  Branch (332:25): [True: 4.37k, False: 8.75k]
  ------------------
  333|  4.37k|                        SkipSpaces(&mBuffer.data, mBuffer.end);
  334|  4.37k|                        surf.mat = strtoul10(mBuffer.data);
  335|  8.75k|                    } else if (TokenMatch(mBuffer.data, "refs", 4)) {
  ------------------
  |  Branch (335:32): [True: 4.37k, False: 4.37k]
  ------------------
  336|       |                        // --- see fix notes above
  337|  4.37k|                        if (Q3DWorkAround) {
  ------------------
  |  Branch (337:29): [True: 0, False: 4.37k]
  ------------------
  338|      0|                            if (!surf.entries.empty()) {
  ------------------
  |  Branch (338:33): [True: 0, False: 0]
  ------------------
  339|      0|                                mBuffer.data -= 6;
  340|      0|                                break;
  341|      0|                            }
  342|      0|                        }
  343|       |
  344|  4.37k|                        SkipSpaces(&mBuffer.data, mBuffer.end);
  345|  4.37k|                        const unsigned int m = strtoul10(mBuffer.data);
  346|  4.37k|                        surf.entries.reserve(m);
  347|       |
  348|  4.37k|                        obj.numRefs += m;
  349|       |
  350|  22.3k|                        for (unsigned int k = 0; k < m; ++k) {
  ------------------
  |  Branch (350:50): [True: 17.9k, False: 4.37k]
  ------------------
  351|  17.9k|                            if (!GetNextLine()) {
  ------------------
  |  Branch (351:33): [True: 0, False: 17.9k]
  ------------------
  352|      0|                                ASSIMP_LOG_ERROR("AC3D: Unexpected EOF: surface references are incomplete");
  353|      0|                                break;
  354|      0|                            }
  355|  17.9k|                            surf.entries.emplace_back();
  356|  17.9k|                            Surface::SurfaceEntry &entry = surf.entries.back();
  357|       |
  358|  17.9k|                            entry.first = strtoul10(mBuffer.data, &mBuffer.data);
  359|  17.9k|                            SkipSpaces(&mBuffer.data, mBuffer.end);
  360|  17.9k|                            mBuffer.data = TAcCheckedLoadFloatArray(mBuffer.data, mBuffer.end, "", 0, 2, &entry.second);
  361|  17.9k|                        }
  362|  4.37k|                    } else {
  363|  4.37k|                        --mBuffer.data; // make sure the line is processed a second time
  364|  4.37k|                        break;
  365|  4.37k|                    }
  366|  13.1k|                }
  367|  4.37k|            }
  368|      5|        }
  369|     51|    }
  370|     13|    ASSIMP_LOG_ERROR("AC3D: Unexpected EOF: \'kids\' line was expected");
  371|       |
  372|      0|    return false;
  373|     13|}
_ZN6Assimp12AC3DImporter15ConvertMaterialERKNS0_6ObjectERKNS0_8MaterialER10aiMaterial:
  379|      5|        aiMaterial &matDest) {
  380|      5|    aiString s;
  381|       |
  382|      5|    if (matSrc.name.length()) {
  ------------------
  |  Branch (382:9): [True: 5, False: 0]
  ------------------
  383|      5|        s.Set(matSrc.name);
  384|      5|        matDest.AddProperty(&s, AI_MATKEY_NAME);
  385|      5|    }
  386|      5|    if (!object.textures.empty()) {
  ------------------
  |  Branch (386:9): [True: 3, False: 2]
  ------------------
  387|      3|        s.Set(object.textures[0]);
  388|      3|        matDest.AddProperty(&s, AI_MATKEY_TEXTURE_DIFFUSE(0));
  389|       |
  390|       |        // UV transformation
  391|      3|        if (1.f != object.texRepeat.x || 1.f != object.texRepeat.y ||
  ------------------
  |  Branch (391:13): [True: 1, False: 2]
  |  Branch (391:42): [True: 0, False: 2]
  ------------------
  392|      2|                object.texOffset.x || object.texOffset.y) {
  ------------------
  |  Branch (392:17): [True: 0, False: 2]
  |  Branch (392:39): [True: 0, False: 2]
  ------------------
  393|      1|            aiUVTransform transform;
  394|      1|            transform.mScaling = object.texRepeat;
  395|      1|            transform.mTranslation = object.texOffset;
  396|      1|            matDest.AddProperty(&transform, 1, AI_MATKEY_UVTRANSFORM_DIFFUSE(0));
  397|      1|        }
  398|      3|    }
  399|       |
  400|      5|    matDest.AddProperty<aiColor3D>(&matSrc.rgb, 1, AI_MATKEY_COLOR_DIFFUSE);
  401|      5|    matDest.AddProperty<aiColor3D>(&matSrc.amb, 1, AI_MATKEY_COLOR_AMBIENT);
  402|      5|    matDest.AddProperty<aiColor3D>(&matSrc.emis, 1, AI_MATKEY_COLOR_EMISSIVE);
  403|      5|    matDest.AddProperty<aiColor3D>(&matSrc.spec, 1, AI_MATKEY_COLOR_SPECULAR);
  404|       |
  405|      5|    int n = -1;
  406|      5|    if (matSrc.shin) {
  ------------------
  |  Branch (406:9): [True: 3, False: 2]
  ------------------
  407|      3|        n = aiShadingMode_Phong;
  408|      3|        matDest.AddProperty<float>(&matSrc.shin, 1, AI_MATKEY_SHININESS);
  409|      3|    } else {
  410|      2|        n = aiShadingMode_Gouraud;
  411|      2|    }
  412|      5|    matDest.AddProperty<int>(&n, 1, AI_MATKEY_SHADING_MODEL);
  413|       |
  414|      5|    float f = 1.f - matSrc.trans;
  415|       |    matDest.AddProperty<float>(&f, 1, AI_MATKEY_OPACITY);
  416|      5|}
_ZN6Assimp12AC3DImporter20ConvertObjectSectionERNS0_6ObjectERNSt3__16vectorIP6aiMeshNS3_9allocatorIS6_EEEERNS4_IP10aiMaterialNS7_ISC_EEEERKNS4_INS0_8MaterialENS7_ISG_EEEEP6aiNode:
  424|     13|        aiNode *parent) {
  425|     13|    aiNode *node = new aiNode();
  426|     13|    node->mParent = parent;
  427|     13|    if (object.vertices.size()) {
  ------------------
  |  Branch (427:9): [True: 5, False: 8]
  ------------------
  428|      5|        if (!object.surfaces.size() || !object.numRefs) {
  ------------------
  |  Branch (428:13): [True: 0, False: 5]
  |  Branch (428:40): [True: 0, False: 5]
  ------------------
  429|       |            /* " An object with 7 vertices (no surfaces, no materials defined).
  430|       |                 This is a good way of getting point data into AC3D.
  431|       |                 The Vertex->create convex-surface/object can be used on these
  432|       |                 vertices to 'wrap' a 3d shape around them "
  433|       |                 (http://www.opencity.info/html/ac3dfileformat.html)
  434|       |
  435|       |                 therefore: if no surfaces are defined return point data only
  436|       |             */
  437|       |
  438|      0|            ASSIMP_LOG_INFO("AC3D: No surfaces defined in object definition, "
  439|      0|                            "a point list is returned");
  440|       |
  441|      0|            meshes.push_back(new aiMesh());
  442|      0|            aiMesh *mesh = meshes.back();
  443|       |
  444|      0|            mesh->mNumFaces = mesh->mNumVertices = (unsigned int)object.vertices.size();
  445|      0|            aiFace *faces = mesh->mFaces = new aiFace[mesh->mNumFaces];
  446|      0|            aiVector3D *verts = mesh->mVertices = new aiVector3D[mesh->mNumVertices];
  447|       |
  448|      0|            for (unsigned int i = 0; i < mesh->mNumVertices; ++i, ++faces, ++verts) {
  ------------------
  |  Branch (448:38): [True: 0, False: 0]
  ------------------
  449|      0|                *verts = object.vertices[i];
  450|      0|                faces->mNumIndices = 1;
  451|      0|                faces->mIndices = new unsigned int[1];
  452|      0|                faces->mIndices[0] = i;
  453|      0|            }
  454|       |
  455|       |            // use the primary material in this case. this should be the
  456|       |            // default material if all objects of the file contain points
  457|       |            // and no faces.
  458|      0|            mesh->mMaterialIndex = 0;
  459|      0|            outMaterials.push_back(new aiMaterial());
  460|      0|            ConvertMaterial(object, materials[0], *outMaterials.back());
  461|      5|        } else {
  462|       |            // need to generate one or more meshes for this object.
  463|       |            // find out how many different materials we have
  464|      5|            typedef std::pair<unsigned int, unsigned int> IntPair;
  465|      5|            typedef std::vector<IntPair> MatTable;
  466|      5|            MatTable needMat(materials.size(), IntPair(0, 0));
  467|       |
  468|      5|            std::vector<Surface>::iterator it, end = object.surfaces.end();
  469|      5|            std::vector<Surface::SurfaceEntry>::iterator it2, end2;
  470|       |
  471|  4.38k|            for (it = object.surfaces.begin(); it != end; ++it) {
  ------------------
  |  Branch (471:48): [True: 4.37k, False: 5]
  ------------------
  472|  4.37k|                unsigned int idx = (*it).mat;
  473|  4.37k|                if (idx >= needMat.size()) {
  ------------------
  |  Branch (473:21): [True: 0, False: 4.37k]
  ------------------
  474|      0|                    ASSIMP_LOG_ERROR("AC3D: material index is out of range");
  475|      0|                    idx = 0;
  476|      0|                }
  477|  4.37k|                if ((*it).entries.empty()) {
  ------------------
  |  Branch (477:21): [True: 0, False: 4.37k]
  ------------------
  478|      0|                    ASSIMP_LOG_WARN("AC3D: surface has zero vertex references");
  479|      0|                }
  480|  4.37k|                const bool isDoubleSided = ACDoubleSidedFlag == (it->flags & ACDoubleSidedFlag);
  481|  4.37k|                const int doubleSidedFactor = isDoubleSided ? 2 : 1;
  ------------------
  |  Branch (481:47): [True: 345, False: 4.03k]
  ------------------
  482|       |
  483|       |                // validate all vertex indices to make sure we won't crash here
  484|  4.37k|                for (it2 = (*it).entries.begin(),
  485|  4.37k|                    end2 = (*it).entries.end();
  486|  22.3k|                        it2 != end2; ++it2) {
  ------------------
  |  Branch (486:25): [True: 17.9k, False: 4.37k]
  ------------------
  487|  17.9k|                    if ((*it2).first >= object.vertices.size()) {
  ------------------
  |  Branch (487:25): [True: 35, False: 17.9k]
  ------------------
  488|     35|                        ASSIMP_LOG_WARN("AC3D: Invalid vertex reference");
  489|     35|                        (*it2).first = 0;
  490|     35|                    }
  491|  17.9k|                }
  492|       |
  493|  4.37k|                if (!needMat[idx].first) {
  ------------------
  |  Branch (493:21): [True: 5, False: 4.37k]
  ------------------
  494|      5|                    ++node->mNumMeshes;
  495|      5|                }
  496|       |
  497|  4.37k|                switch ((*it).GetType()) {
  498|      0|                case Surface::ClosedLine: // closed line
  ------------------
  |  Branch (498:17): [True: 0, False: 4.37k]
  ------------------
  499|      0|                    needMat[idx].first += static_cast<unsigned int>((*it).entries.size());
  500|      0|                    needMat[idx].second += static_cast<unsigned int>((*it).entries.size() << 1u);
  501|      0|                    break;
  502|       |
  503|       |                    // unclosed line
  504|      0|                case Surface::OpenLine:
  ------------------
  |  Branch (504:17): [True: 0, False: 4.37k]
  ------------------
  505|      0|                    needMat[idx].first += static_cast<unsigned int>((*it).entries.size() - 1);
  506|      0|                    needMat[idx].second += static_cast<unsigned int>(((*it).entries.size() - 1) << 1u);
  507|      0|                    break;
  508|       |
  509|       |                    // triangle strip
  510|    358|                case Surface::TriangleStrip:
  ------------------
  |  Branch (510:17): [True: 358, False: 4.02k]
  ------------------
  511|    358|                    needMat[idx].first += static_cast<unsigned int>(it->entries.size() - 2) * doubleSidedFactor;
  512|    358|                    needMat[idx].second += static_cast<unsigned int>(it->entries.size() - 2) * 3 * doubleSidedFactor;
  513|    358|                    break;
  514|       |
  515|      0|                default:
  ------------------
  |  Branch (515:17): [True: 0, False: 4.37k]
  ------------------
  516|       |                    // Coerce unknowns to a polygon and warn
  517|      0|                    ASSIMP_LOG_WARN("AC3D: The type flag of a surface is unknown: ", (*it).flags);
  518|      0|                    (*it).flags &= ~(Surface::Mask);
  519|       |                    // fallthrough
  520|       |
  521|       |                    // polygon
  522|  4.02k|                case Surface::Polygon:
  ------------------
  |  Branch (522:17): [True: 4.02k, False: 358]
  ------------------
  523|       |                    // the number of faces increments by one, the number
  524|       |                    // of vertices by surface.numref.
  525|  4.02k|                    needMat[idx].first += doubleSidedFactor;
  526|  4.02k|                    needMat[idx].second += static_cast<unsigned int>(it->entries.size()) * doubleSidedFactor;
  527|  4.37k|                };
  528|  4.37k|            }
  529|      5|            unsigned int *pip = node->mMeshes = new unsigned int[node->mNumMeshes];
  530|      5|            unsigned int mat = 0;
  531|      5|            const size_t oldm = meshes.size();
  532|      5|            for (MatTable::const_iterator cit = needMat.begin(), cend = needMat.end();
  533|     10|                    cit != cend; ++cit, ++mat) {
  ------------------
  |  Branch (533:21): [True: 5, False: 5]
  ------------------
  534|      5|                if (!(*cit).first) {
  ------------------
  |  Branch (534:21): [True: 0, False: 5]
  ------------------
  535|      0|                    continue;
  536|      0|                }
  537|       |
  538|       |                // allocate a new aiMesh object
  539|      5|                *pip++ = (unsigned int)meshes.size();
  540|      5|                aiMesh *mesh = new aiMesh();
  541|      5|                meshes.push_back(mesh);
  542|       |
  543|      5|                mesh->mMaterialIndex = static_cast<unsigned int>(outMaterials.size());
  544|      5|                outMaterials.push_back(new aiMaterial());
  545|      5|                ConvertMaterial(object, materials[mat], *outMaterials.back());
  546|       |
  547|       |                // allocate storage for vertices and normals
  548|      5|                mesh->mNumFaces = (*cit).first;
  549|      5|                if (mesh->mNumFaces == 0) {
  ------------------
  |  Branch (549:21): [True: 0, False: 5]
  ------------------
  550|      0|                    throw DeadlyImportError("AC3D: No faces");
  551|      5|                } else if (mesh->mNumFaces > AI_MAX_ALLOC(aiFace)) {
  ------------------
  |  Branch (551:28): [True: 0, False: 5]
  ------------------
  552|      0|                    throw DeadlyImportError("AC3D: Too many faces, would run out of memory");
  553|      0|                }
  554|      5|                aiFace *faces = mesh->mFaces = new aiFace[mesh->mNumFaces];
  555|       |
  556|      5|                mesh->mNumVertices = (*cit).second;
  557|      5|                if (mesh->mNumVertices == 0) {
  ------------------
  |  Branch (557:21): [True: 0, False: 5]
  ------------------
  558|      0|                    throw DeadlyImportError("AC3D: No vertices");
  559|      5|                } else if (mesh->mNumVertices > AI_MAX_ALLOC(aiVector3D)) {
  ------------------
  |  Branch (559:28): [True: 0, False: 5]
  ------------------
  560|      0|                    throw DeadlyImportError("AC3D: Too many vertices, would run out of memory");
  561|      0|                }
  562|      5|                aiVector3D *vertices = mesh->mVertices = new aiVector3D[mesh->mNumVertices];
  563|      5|                unsigned int cur = 0;
  564|       |
  565|       |                // allocate UV coordinates, but only if the texture name for the
  566|       |                // surface is not empty
  567|      5|                aiVector3D *uv = nullptr;
  568|      5|                if (!object.textures.empty()) {
  ------------------
  |  Branch (568:21): [True: 3, False: 2]
  ------------------
  569|      3|                    uv = mesh->mTextureCoords[0] = new aiVector3D[mesh->mNumVertices];
  570|      3|                    mesh->mNumUVComponents[0] = 2;
  571|      3|                }
  572|       |
  573|  4.38k|                for (it = object.surfaces.begin(); it != end; ++it) {
  ------------------
  |  Branch (573:52): [True: 4.37k, False: 5]
  ------------------
  574|  4.37k|                    if (mat == (*it).mat) {
  ------------------
  |  Branch (574:25): [True: 4.37k, False: 0]
  ------------------
  575|  4.37k|                        const Surface &src = *it;
  576|  4.37k|                        const bool isDoubleSided = ACDoubleSidedFlag == (src.flags & ACDoubleSidedFlag);
  577|       |
  578|       |                        // closed polygon
  579|  4.37k|                        uint8_t type = (*it).GetType();
  580|  4.37k|                        if (type == Surface::Polygon) {
  ------------------
  |  Branch (580:29): [True: 4.02k, False: 358]
  ------------------
  581|  4.02k|                            aiFace &face = *faces++;
  582|  4.02k|                            face.mNumIndices = (unsigned int)src.entries.size();
  583|  4.02k|                            if (0 != face.mNumIndices) {
  ------------------
  |  Branch (583:33): [True: 4.02k, False: 0]
  ------------------
  584|  4.02k|                                face.mIndices = new unsigned int[face.mNumIndices];
  585|  16.3k|                                for (unsigned int i = 0; i < face.mNumIndices; ++i, ++vertices) {
  ------------------
  |  Branch (585:58): [True: 12.3k, False: 4.02k]
  ------------------
  586|  12.3k|                                    const Surface::SurfaceEntry &entry = src.entries[i];
  587|  12.3k|                                    face.mIndices[i] = cur++;
  588|       |
  589|       |                                    // copy vertex positions
  590|  12.3k|                                    if (static_cast<unsigned>(vertices - mesh->mVertices) >= mesh->mNumVertices) {
  ------------------
  |  Branch (590:41): [True: 0, False: 12.3k]
  ------------------
  591|      0|                                        throw DeadlyImportError("AC3D: Invalid number of vertices");
  592|      0|                                    }
  593|  12.3k|                                    *vertices = object.vertices[entry.first] + object.translation;
  594|       |
  595|       |                                    // copy texture coordinates
  596|  12.3k|                                    if (uv) {
  ------------------
  |  Branch (596:41): [True: 1.10k, False: 11.1k]
  ------------------
  597|  1.10k|                                        uv->x = entry.second.x;
  598|  1.10k|                                        uv->y = entry.second.y;
  599|  1.10k|                                        ++uv;
  600|  1.10k|                                    }
  601|  12.3k|                                }
  602|  4.02k|                                if(isDoubleSided) // Need a backface?
  ------------------
  |  Branch (602:36): [True: 0, False: 4.02k]
  ------------------
  603|      0|                                    buildBacksideOfFace(faces[-1], faces, vertices, mesh->mVertices, uv, mesh->mTextureCoords[0], cur);
  604|  4.02k|                            }
  605|  4.02k|                        } else if (type == Surface::TriangleStrip) {
  ------------------
  |  Branch (605:36): [True: 358, False: 0]
  ------------------
  606|  5.27k|                            for (unsigned int i = 0; i < (unsigned int)src.entries.size() - 2; ++i) {
  ------------------
  |  Branch (606:54): [True: 4.91k, False: 358]
  ------------------
  607|  4.91k|                                const Surface::SurfaceEntry &entry1 = src.entries[i];
  608|  4.91k|                                const Surface::SurfaceEntry &entry2 = src.entries[i + 1];
  609|  4.91k|                                const Surface::SurfaceEntry &entry3 = src.entries[i + 2];
  610|  4.91k|                                const unsigned int verticesNeeded = isDoubleSided ? 6 : 3;
  ------------------
  |  Branch (610:69): [True: 4.63k, False: 286]
  ------------------
  611|  4.91k|                                if (static_cast<unsigned>(vertices - mesh->mVertices) + verticesNeeded > mesh->mNumVertices) {
  ------------------
  |  Branch (611:37): [True: 0, False: 4.91k]
  ------------------
  612|      0|                                    throw DeadlyImportError("AC3D: Invalid number of vertices");
  613|      0|                                }
  614|       |
  615|  4.91k|                                aiFace &face = *faces++;
  616|  4.91k|                                face.mNumIndices = 3;
  617|  4.91k|                                face.mIndices = new unsigned int[face.mNumIndices];
  618|  4.91k|                                face.mIndices[0] = cur++;
  619|  4.91k|                                face.mIndices[1] = cur++;
  620|  4.91k|                                face.mIndices[2] = cur++;
  621|  4.91k|                                if (!(i & 1)) {
  ------------------
  |  Branch (621:37): [True: 2.55k, False: 2.36k]
  ------------------
  622|  2.55k|                                    *vertices++ = object.vertices[entry1.first] + object.translation;
  623|  2.55k|                                    if (uv) {
  ------------------
  |  Branch (623:41): [True: 144, False: 2.40k]
  ------------------
  624|    144|                                        uv->x = entry1.second.x;
  625|    144|                                        uv->y = entry1.second.y;
  626|    144|                                        ++uv;
  627|    144|                                    }
  628|  2.55k|                                    *vertices++ = object.vertices[entry2.first] + object.translation;
  629|  2.55k|                                    if (uv) {
  ------------------
  |  Branch (629:41): [True: 144, False: 2.40k]
  ------------------
  630|    144|                                        uv->x = entry2.second.x;
  631|    144|                                        uv->y = entry2.second.y;
  632|    144|                                        ++uv;
  633|    144|                                    }
  634|  2.55k|                                } else {
  635|  2.36k|                                    *vertices++ = object.vertices[entry2.first] + object.translation;
  636|  2.36k|                                    if (uv) {
  ------------------
  |  Branch (636:41): [True: 142, False: 2.22k]
  ------------------
  637|    142|                                        uv->x = entry2.second.x;
  638|    142|                                        uv->y = entry2.second.y;
  639|    142|                                        ++uv;
  640|    142|                                    }
  641|  2.36k|                                    *vertices++ = object.vertices[entry1.first] + object.translation;
  642|  2.36k|                                    if (uv) {
  ------------------
  |  Branch (642:41): [True: 142, False: 2.22k]
  ------------------
  643|    142|                                        uv->x = entry1.second.x;
  644|    142|                                        uv->y = entry1.second.y;
  645|    142|                                        ++uv;
  646|    142|                                    }
  647|  2.36k|                                }
  648|  4.91k|                                if (static_cast<unsigned>(vertices - mesh->mVertices) >= mesh->mNumVertices) {
  ------------------
  |  Branch (648:37): [True: 0, False: 4.91k]
  ------------------
  649|      0|                                    throw DeadlyImportError("AC3D: Invalid number of vertices");
  650|      0|                                }
  651|  4.91k|                                *vertices++ = object.vertices[entry3.first] + object.translation;
  652|  4.91k|                                if (uv) {
  ------------------
  |  Branch (652:37): [True: 286, False: 4.63k]
  ------------------
  653|    286|                                    uv->x = entry3.second.x;
  654|    286|                                    uv->y = entry3.second.y;
  655|    286|                                    ++uv;
  656|    286|                                }
  657|  4.91k|                                if(isDoubleSided) // Need a backface?
  ------------------
  |  Branch (657:36): [True: 4.63k, False: 286]
  ------------------
  658|  4.63k|                                    buildBacksideOfFace(faces[-1], faces, vertices, mesh->mVertices, uv, mesh->mTextureCoords[0], cur);
  659|  4.91k|                            }
  660|    358|                        } else {
  661|       |
  662|      0|                            it2 = (*it).entries.begin();
  663|       |
  664|       |                            // either a closed or an unclosed line
  665|      0|                            unsigned int tmp = (unsigned int)(*it).entries.size();
  666|      0|                            if (Surface::OpenLine == type) --tmp;
  ------------------
  |  Branch (666:33): [True: 0, False: 0]
  ------------------
  667|      0|                            for (unsigned int m = 0; m < tmp; ++m) {
  ------------------
  |  Branch (667:54): [True: 0, False: 0]
  ------------------
  668|      0|                                if (static_cast<unsigned>(vertices - mesh->mVertices) + 2 > mesh->mNumVertices) {
  ------------------
  |  Branch (668:37): [True: 0, False: 0]
  ------------------
  669|      0|                                    throw DeadlyImportError("AC3D: Invalid number of vertices");
  670|      0|                                }
  671|       |
  672|      0|                                aiFace &face = *faces++;
  673|       |
  674|      0|                                face.mNumIndices = 2;
  675|      0|                                face.mIndices = new unsigned int[2];
  676|      0|                                face.mIndices[0] = cur++;
  677|      0|                                face.mIndices[1] = cur++;
  678|       |
  679|       |                                // copy vertex positions
  680|      0|                                if (it2 == (*it).entries.end()) {
  ------------------
  |  Branch (680:37): [True: 0, False: 0]
  ------------------
  681|      0|                                    throw DeadlyImportError("AC3D: Bad line");
  682|      0|                                }
  683|      0|                                ai_assert((*it2).first < object.vertices.size());
  684|      0|                                *vertices++ = object.vertices[(*it2).first];
  685|       |
  686|       |                                // copy texture coordinates
  687|      0|                                if (uv) {
  ------------------
  |  Branch (687:37): [True: 0, False: 0]
  ------------------
  688|      0|                                    uv->x = (*it2).second.x;
  689|      0|                                    uv->y = (*it2).second.y;
  690|      0|                                    ++uv;
  691|      0|                                }
  692|       |
  693|      0|                                if (Surface::ClosedLine == type && tmp - 1 == m) {
  ------------------
  |  Branch (693:37): [True: 0, False: 0]
  |  Branch (693:68): [True: 0, False: 0]
  ------------------
  694|       |                                    // if this is a closed line repeat its beginning now
  695|      0|                                    it2 = (*it).entries.begin();
  696|      0|                                } else
  697|      0|                                    ++it2;
  698|       |
  699|       |                                // second point
  700|      0|                                *vertices++ = object.vertices[(*it2).first];
  701|       |
  702|      0|                                if (uv) {
  ------------------
  |  Branch (702:37): [True: 0, False: 0]
  ------------------
  703|      0|                                    uv->x = (*it2).second.x;
  704|      0|                                    uv->y = (*it2).second.y;
  705|      0|                                    ++uv;
  706|      0|                                }
  707|      0|                            }
  708|      0|                        }
  709|  4.37k|                    }
  710|  4.37k|                }
  711|      5|            }
  712|       |
  713|       |            // Now apply catmull clark subdivision if necessary. We split meshes into
  714|       |            // materials which is not done by AC3D during smoothing, so we need to
  715|       |            // collect all meshes using the same material group.
  716|      5|            if (object.subDiv) {
  ------------------
  |  Branch (716:17): [True: 2, False: 3]
  ------------------
  717|      2|                if (configEvalSubdivision) {
  ------------------
  |  Branch (717:21): [True: 2, False: 0]
  ------------------
  718|      2|                    std::unique_ptr<Subdivider> div(Subdivider::Create(Subdivider::CATMULL_CLARKE));
  719|      2|                    ASSIMP_LOG_INFO("AC3D: Evaluating subdivision surface: ", object.name);
  720|       |
  721|      2|                    std::vector<aiMesh *> cpy(meshes.size() - oldm, nullptr);
  722|      2|                    div->Subdivide(&meshes[oldm], cpy.size(), &cpy.front(), object.subDiv, true);
  723|      2|                    std::copy(cpy.begin(), cpy.end(), meshes.begin() + oldm);
  724|       |
  725|       |                    // previous meshes are deleted vy Subdivide().
  726|      2|                } else {
  727|      0|                    ASSIMP_LOG_INFO("AC3D: Letting the subdivision surface untouched due to my configuration: ", object.name);
  728|      0|                }
  729|      2|            }
  730|      5|        }
  731|      5|    }
  732|       |
  733|     13|    if (object.name.length())
  ------------------
  |  Branch (733:9): [True: 8, False: 5]
  ------------------
  734|      8|        node->mName.Set(object.name);
  735|      5|    else {
  736|       |        // generate a name depending on the type of the node
  737|      5|        switch (object.type) {
  ------------------
  |  Branch (737:17): [True: 5, False: 0]
  ------------------
  738|      0|        case Object::Group:
  ------------------
  |  Branch (738:9): [True: 0, False: 5]
  ------------------
  739|      0|            node->mName.length = ::ai_snprintf(node->mName.data, AI_MAXLEN, "ACGroup_%i", mGroupsCounter++);
  740|      0|            break;
  741|      0|        case Object::Poly:
  ------------------
  |  Branch (741:9): [True: 0, False: 5]
  ------------------
  742|      0|            node->mName.length = ::ai_snprintf(node->mName.data, AI_MAXLEN, "ACPoly_%i", mPolysCounter++);
  743|      0|            break;
  744|      0|        case Object::Light:
  ------------------
  |  Branch (744:9): [True: 0, False: 5]
  ------------------
  745|      0|            node->mName.length = ::ai_snprintf(node->mName.data, AI_MAXLEN, "ACLight_%i", mLightsCounter++);
  746|      0|            break;
  747|       |
  748|       |            // there shouldn't be more than one world, but we don't care
  749|      5|        case Object::World:
  ------------------
  |  Branch (749:9): [True: 5, False: 0]
  ------------------
  750|      5|            node->mName.length = ::ai_snprintf(node->mName.data, AI_MAXLEN, "ACWorld_%i", mWorldsCounter++);
  751|      5|            break;
  752|      5|        }
  753|      5|    }
  754|       |
  755|       |    // setup the local transformation matrix of the object
  756|       |    // compute the transformation offset to the parent node
  757|     13|    node->mTransformation = aiMatrix4x4(object.rotation);
  758|       |
  759|     13|    if (object.type == Object::Group || !object.numRefs) {
  ------------------
  |  Branch (759:9): [True: 0, False: 13]
  |  Branch (759:41): [True: 8, False: 5]
  ------------------
  760|      8|        node->mTransformation.a4 = object.translation.x;
  761|      8|        node->mTransformation.b4 = object.translation.y;
  762|      8|        node->mTransformation.c4 = object.translation.z;
  763|      8|    }
  764|       |
  765|       |    // add children to the object
  766|     13|    if (object.children.size()) {
  ------------------
  |  Branch (766:9): [True: 5, False: 8]
  ------------------
  767|      5|        node->mNumChildren = (unsigned int)object.children.size();
  768|      5|        node->mChildren = new aiNode *[node->mNumChildren];
  769|     13|        for (unsigned int i = 0; i < node->mNumChildren; ++i) {
  ------------------
  |  Branch (769:34): [True: 8, False: 5]
  ------------------
  770|      8|            node->mChildren[i] = ConvertObjectSection(object.children[i], meshes, outMaterials, materials, node);
  771|      8|        }
  772|      5|    }
  773|       |
  774|     13|    return node;
  775|     13|}
_ZN6Assimp12AC3DImporter15SetupPropertiesEPKNS_8ImporterE:
  778|      5|void AC3DImporter::SetupProperties(const Importer *pImp) {
  779|      5|    configSplitBFCull = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_AC_SEPARATE_BFCULL, 1) ? true : false;
  ------------------
  |  Branch (779:25): [True: 5, False: 0]
  ------------------
  780|      5|    configEvalSubdivision = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_AC_EVAL_SUBDIVISION, 1) ? true : false;
  ------------------
  |  Branch (780:29): [True: 5, False: 0]
  ------------------
  781|      5|}
_ZN6Assimp12AC3DImporter14InternReadFileERKNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEP7aiScenePNS_8IOSystemE:
  786|      5|        aiScene *pScene, IOSystem *pIOHandler) {
  787|      5|    std::unique_ptr<IOStream> file(pIOHandler->Open(pFile, "rb"));
  788|       |
  789|       |    // Check whether we can read from the file
  790|      5|    if (file == nullptr) {
  ------------------
  |  Branch (790:9): [True: 0, False: 5]
  ------------------
  791|      0|        throw DeadlyImportError("Failed to open AC3D file ", pFile, ".");
  792|      0|    }
  793|       |
  794|       |    // allocate storage and copy the contents of the file to a memory buffer
  795|      5|    std::vector<char> mBuffer2;
  796|      5|    TextFileToBuffer(file.get(), mBuffer2);
  797|       |
  798|      5|    mBuffer.data = &mBuffer2[0];
  799|      5|    mBuffer.end = &mBuffer2[0] + mBuffer2.size();
  800|      5|    mNumMeshes = 0;
  801|       |
  802|      5|    mLightsCounter = mPolysCounter = mWorldsCounter = mGroupsCounter = 0;
  803|       |
  804|      5|    if (::strncmp(mBuffer.data, "AC3D", 4)) {
  ------------------
  |  Branch (804:9): [True: 0, False: 5]
  ------------------
  805|      0|        throw DeadlyImportError("AC3D: No valid AC3D file, magic sequence not found");
  806|      0|    }
  807|       |
  808|       |    // print the file format version to the console
  809|      5|    unsigned int version = HexDigitToDecimal(mBuffer.data[4]);
  810|      5|    char msg[3];
  811|      5|    ASSIMP_itoa10(msg, 3, version);
  812|      5|    ASSIMP_LOG_INFO("AC3D file format version: ", msg);
  813|       |
  814|      5|    std::vector<Material> materials;
  815|      5|    materials.reserve(5);
  816|       |
  817|      5|    std::vector<Object> rootObjects;
  818|      5|    rootObjects.reserve(5);
  819|       |
  820|      5|    std::vector<aiLight *> lights;
  821|      5|    mLights = &lights;
  822|       |
  823|     15|    while (GetNextLine()) {
  ------------------
  |  Branch (823:12): [True: 10, False: 5]
  ------------------
  824|     10|        if (TokenMatch(mBuffer.data, "MATERIAL", 8)) {
  ------------------
  |  Branch (824:13): [True: 5, False: 5]
  ------------------
  825|      5|            materials.emplace_back();
  826|      5|            Material &mat = materials.back();
  827|       |
  828|       |            // manually parse the material ... sscanf would use the buldin atof ...
  829|       |            // Format: (name) rgb %f %f %f  amb %f %f %f  emis %f %f %f  spec %f %f %f  shi %d  trans %f
  830|       |
  831|      5|            mBuffer.data = AcSkipToNextToken(mBuffer.data, mBuffer.end);
  832|      5|            if ('\"' == *mBuffer.data) {
  ------------------
  |  Branch (832:17): [True: 5, False: 0]
  ------------------
  833|      5|                mBuffer.data = AcGetString(mBuffer.data, mBuffer.end, mat.name);
  834|      5|                mBuffer.data = AcSkipToNextToken(mBuffer.data, mBuffer.end);
  835|      5|            }
  836|       |
  837|      5|            mBuffer.data = TAcCheckedLoadFloatArray(mBuffer.data, mBuffer.end, "rgb", 3, 3, &mat.rgb);
  838|      5|            mBuffer.data = TAcCheckedLoadFloatArray(mBuffer.data, mBuffer.end, "amb", 3, 3, &mat.amb);
  839|      5|            mBuffer.data = TAcCheckedLoadFloatArray(mBuffer.data, mBuffer.end, "emis", 4, 3, &mat.emis);
  840|      5|            mBuffer.data = TAcCheckedLoadFloatArray(mBuffer.data, mBuffer.end, "spec", 4, 3, &mat.spec);
  841|      5|            mBuffer.data = TAcCheckedLoadFloatArray(mBuffer.data, mBuffer.end, "shi", 3, 1, &mat.shin);
  842|      5|            mBuffer.data = TAcCheckedLoadFloatArray(mBuffer.data, mBuffer.end, "trans", 5, 1, &mat.trans);
  843|      5|        } else {
  844|      5|            LoadObjectSection(rootObjects);
  845|      5|        }
  846|     10|    }
  847|       |
  848|      5|    if (rootObjects.empty() || mNumMeshes == 0u) {
  ------------------
  |  Branch (848:9): [True: 0, False: 5]
  |  Branch (848:32): [True: 0, False: 5]
  ------------------
  849|      0|        throw DeadlyImportError("AC3D: No meshes have been loaded");
  850|      0|    }
  851|      5|    if (materials.empty()) {
  ------------------
  |  Branch (851:9): [True: 0, False: 5]
  ------------------
  852|      0|        ASSIMP_LOG_WARN("AC3D: No material has been found");
  853|      0|        materials.emplace_back();
  854|      0|    }
  855|       |
  856|      5|    mNumMeshes += (mNumMeshes >> 2u) + 1;
  857|      5|    std::vector<aiMesh *> meshes;
  858|      5|    meshes.reserve(mNumMeshes);
  859|       |
  860|      5|    std::vector<aiMaterial *> omaterials;
  861|      5|    materials.reserve(mNumMeshes);
  862|       |
  863|       |    // generate a dummy root if there are multiple objects on the top layer
  864|      5|    Object *root = nullptr;
  865|      5|    if (1 == rootObjects.size())
  ------------------
  |  Branch (865:9): [True: 5, False: 0]
  ------------------
  866|      5|        root = &rootObjects[0];
  867|      0|    else {
  868|      0|        root = new Object();
  869|      0|    }
  870|       |
  871|       |    // now convert the imported stuff to our output data structure
  872|      5|    pScene->mRootNode = ConvertObjectSection(*root, meshes, omaterials, materials);
  873|      5|    if (1 != rootObjects.size()) {
  ------------------
  |  Branch (873:9): [True: 0, False: 5]
  ------------------
  874|      0|        delete root;
  875|      0|    }
  876|       |
  877|      5|    if (::strncmp(pScene->mRootNode->mName.data, "Node", 4) == 0) {
  ------------------
  |  Branch (877:9): [True: 0, False: 5]
  ------------------
  878|      0|        pScene->mRootNode->mName.Set("<AC3DWorld>");
  879|      0|    }
  880|       |
  881|       |    // copy meshes
  882|      5|    if (meshes.empty()) {
  ------------------
  |  Branch (882:9): [True: 0, False: 5]
  ------------------
  883|      0|        throw DeadlyImportError("An unknown error occurred during converting");
  884|      0|    }
  885|      5|    pScene->mNumMeshes = (unsigned int)meshes.size();
  886|      5|    pScene->mMeshes = new aiMesh *[pScene->mNumMeshes];
  887|      5|    ::memcpy(pScene->mMeshes, &meshes[0], pScene->mNumMeshes * sizeof(void *));
  888|       |
  889|       |    // copy materials
  890|      5|    pScene->mNumMaterials = (unsigned int)omaterials.size();
  891|      5|    pScene->mMaterials = new aiMaterial *[pScene->mNumMaterials];
  892|      5|    ::memcpy(pScene->mMaterials, &omaterials[0], pScene->mNumMaterials * sizeof(void *));
  893|       |
  894|       |    // copy lights
  895|      5|    pScene->mNumLights = (unsigned int)lights.size();
  896|      5|    if (!lights.empty()) {
  ------------------
  |  Branch (896:9): [True: 3, False: 2]
  ------------------
  897|      3|        pScene->mLights = new aiLight *[lights.size()];
  898|      3|        ::memcpy(pScene->mLights, &lights[0], lights.size() * sizeof(void *));
  899|      3|    }
  900|      5|}
_ZN6Assimp11AcGetStringEPKcS1_RNSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEE:
   91|     19|inline const char *AcGetString(const char *buffer, const char *end, std::string &out) {
   92|     19|    if (*buffer == '\0') {
  ------------------
  |  Branch (92:9): [True: 0, False: 19]
  ------------------
   93|      0|        throw DeadlyImportError("AC3D: Unexpected EOF in string");
   94|      0|    }
   95|     19|    ++buffer;
   96|     19|    const char *sz = buffer;
   97|    248|    while ('\"' != *buffer && buffer != end) {
  ------------------
  |  Branch (97:12): [True: 232, False: 16]
  |  Branch (97:31): [True: 232, False: 0]
  ------------------
   98|    232|        if (IsLineEnd(*buffer)) {
  ------------------
  |  Branch (98:13): [True: 3, False: 229]
  ------------------
   99|      3|            ASSIMP_LOG_ERROR("AC3D: Unexpected EOF/EOL in string");
  100|      3|            out = "ERROR";
  101|      3|            break;
  102|      3|        }
  103|    229|        ++buffer;
  104|    229|    }
  105|     19|    if (IsLineEnd(*buffer)) {
  ------------------
  |  Branch (105:9): [True: 3, False: 16]
  ------------------
  106|      3|        return buffer;
  107|      3|    }
  108|     16|    out = std::string(sz, (unsigned int)(buffer - sz));
  109|     16|    ++buffer;
  110|       |
  111|     16|    return buffer;
  112|     19|}
ACLoader.cpp:_ZN6AssimpL19buildBacksideOfFaceERK6aiFaceRPS0_RP10aiVector3tIfEPKS6_S8_SA_Rj:
  144|  4.63k|    aiVector3D *&outUV, const aiVector3D *allUV, unsigned &curIdx) {
  145|  4.63k|    auto &newFace = *outFaces++;
  146|  4.63k|    newFace = origFace;
  147|  4.63k|    flipWindingOrder(newFace);
  148|  18.5k|    for (unsigned f = 0; f < newFace.mNumIndices; ++f) {
  ------------------
  |  Branch (148:26): [True: 13.8k, False: 4.63k]
  ------------------
  149|  13.8k|        *outVertices++ = allVertices[newFace.mIndices[f]];
  150|  13.8k|        if (outUV) {
  ------------------
  |  Branch (150:13): [True: 0, False: 13.8k]
  ------------------
  151|      0|            *outUV = allUV[newFace.mIndices[f]];
  152|      0|            outUV++;
  153|      0|        }
  154|  13.8k|        newFace.mIndices[f] = curIdx++;
  155|  13.8k|    }
  156|  4.63k|}
ACLoader.cpp:_ZN6AssimpL16flipWindingOrderER6aiFace:
  136|  4.63k|static void flipWindingOrder(aiFace &f) {
  137|  4.63k|    std::reverse(f.mIndices, f.mIndices + f.mNumIndices);
  138|  4.63k|}
_ZN6Assimp17AcSkipToNextTokenEPKcS1_:
   82|  81.0k|inline const char *AcSkipToNextToken(const char *buffer, const char *end) {
   83|  81.0k|    if (!SkipSpaces(&buffer, end)) {
  ------------------
  |  Branch (83:9): [True: 0, False: 81.0k]
  ------------------
   84|       |        ASSIMP_LOG_ERROR("AC3D: Unexpected EOF/EOL");
   85|      0|    }
   86|  81.0k|    return buffer;
   87|  81.0k|}
_ZN6Assimp24TAcCheckedLoadFloatArrayI10aiVector2tIfEEEPKcS4_S4_S4_mmPT_:
  117|  17.9k|inline const char *TAcCheckedLoadFloatArray(const char *buffer, const char *end, const char *name, size_t name_length, size_t num, T *out) {
  118|  17.9k|    buffer = AcSkipToNextToken(buffer, end);
  119|  17.9k|    if (0 != name_length) {
  ------------------
  |  Branch (119:9): [True: 0, False: 17.9k]
  ------------------
  120|      0|        if (0 != strncmp(buffer, name, name_length) || !IsSpace(buffer[name_length])) {
  ------------------
  |  Branch (120:13): [True: 0, False: 0]
  |  Branch (120:56): [True: 0, False: 0]
  ------------------
  121|      0|            ASSIMP_LOG_ERROR("AC3D: Unexpected token. ", name, " was expected.");
  122|      0|            return buffer;
  123|      0|        }
  124|      0|        buffer += name_length + 1;
  125|      0|    }
  126|  53.8k|    for (unsigned int _i = 0; _i < num; ++_i) {
  ------------------
  |  Branch (126:31): [True: 35.8k, False: 17.9k]
  ------------------
  127|  35.8k|        buffer = AcSkipToNextToken(buffer, end);
  128|  35.8k|        buffer = fast_atoreal_move(buffer, ((float *)out)[_i]);
  129|  35.8k|    }
  130|       |
  131|  17.9k|    return buffer;
  132|  17.9k|}
_ZN6Assimp24TAcCheckedLoadFloatArrayI10aiVector3tIfEEEPKcS4_S4_S4_mmPT_:
  117|      5|inline const char *TAcCheckedLoadFloatArray(const char *buffer, const char *end, const char *name, size_t name_length, size_t num, T *out) {
  118|      5|    buffer = AcSkipToNextToken(buffer, end);
  119|      5|    if (0 != name_length) {
  ------------------
  |  Branch (119:9): [True: 0, False: 5]
  ------------------
  120|      0|        if (0 != strncmp(buffer, name, name_length) || !IsSpace(buffer[name_length])) {
  ------------------
  |  Branch (120:13): [True: 0, False: 0]
  |  Branch (120:56): [True: 0, False: 0]
  ------------------
  121|      0|            ASSIMP_LOG_ERROR("AC3D: Unexpected token. ", name, " was expected.");
  122|      0|            return buffer;
  123|      0|        }
  124|      0|        buffer += name_length + 1;
  125|      0|    }
  126|     20|    for (unsigned int _i = 0; _i < num; ++_i) {
  ------------------
  |  Branch (126:31): [True: 15, False: 5]
  ------------------
  127|     15|        buffer = AcSkipToNextToken(buffer, end);
  128|     15|        buffer = fast_atoreal_move(buffer, ((float *)out)[_i]);
  129|     15|    }
  130|       |
  131|      5|    return buffer;
  132|      5|}
_ZN6Assimp24TAcCheckedLoadFloatArrayIfEEPKcS2_S2_S2_mmPT_:
  117|  6.79k|inline const char *TAcCheckedLoadFloatArray(const char *buffer, const char *end, const char *name, size_t name_length, size_t num, T *out) {
  118|  6.79k|    buffer = AcSkipToNextToken(buffer, end);
  119|  6.79k|    if (0 != name_length) {
  ------------------
  |  Branch (119:9): [True: 10, False: 6.78k]
  ------------------
  120|     10|        if (0 != strncmp(buffer, name, name_length) || !IsSpace(buffer[name_length])) {
  ------------------
  |  Branch (120:13): [True: 0, False: 10]
  |  Branch (120:56): [True: 0, False: 10]
  ------------------
  121|      0|            ASSIMP_LOG_ERROR("AC3D: Unexpected token. ", name, " was expected.");
  122|      0|            return buffer;
  123|      0|        }
  124|     10|        buffer += name_length + 1;
  125|     10|    }
  126|  27.1k|    for (unsigned int _i = 0; _i < num; ++_i) {
  ------------------
  |  Branch (126:31): [True: 20.3k, False: 6.79k]
  ------------------
  127|  20.3k|        buffer = AcSkipToNextToken(buffer, end);
  128|  20.3k|        buffer = fast_atoreal_move(buffer, ((float *)out)[_i]);
  129|  20.3k|    }
  130|       |
  131|  6.79k|    return buffer;
  132|  6.79k|}
_ZN6Assimp24TAcCheckedLoadFloatArrayI9aiColor3DEEPKcS3_S3_S3_mmPT_:
  117|     20|inline const char *TAcCheckedLoadFloatArray(const char *buffer, const char *end, const char *name, size_t name_length, size_t num, T *out) {
  118|     20|    buffer = AcSkipToNextToken(buffer, end);
  119|     20|    if (0 != name_length) {
  ------------------
  |  Branch (119:9): [True: 20, False: 0]
  ------------------
  120|     20|        if (0 != strncmp(buffer, name, name_length) || !IsSpace(buffer[name_length])) {
  ------------------
  |  Branch (120:13): [True: 0, False: 20]
  |  Branch (120:56): [True: 0, False: 20]
  ------------------
  121|      0|            ASSIMP_LOG_ERROR("AC3D: Unexpected token. ", name, " was expected.");
  122|      0|            return buffer;
  123|      0|        }
  124|     20|        buffer += name_length + 1;
  125|     20|    }
  126|     80|    for (unsigned int _i = 0; _i < num; ++_i) {
  ------------------
  |  Branch (126:31): [True: 60, False: 20]
  ------------------
  127|     60|        buffer = AcSkipToNextToken(buffer, end);
  128|     60|        buffer = fast_atoreal_move(buffer, ((float *)out)[_i]);
  129|     60|    }
  130|       |
  131|     20|    return buffer;
  132|     20|}

_ZN6Assimp12AC3DImporter8MaterialC2Ev:
   71|      5|                rgb(0.6f, 0.6f, 0.6f),
   72|      5|                spec(1.f, 1.f, 1.f),
   73|      5|                shin(0.f),
   74|      5|                trans(0.f) {}
_ZN6Assimp12AC3DImporter7SurfaceC2Ev:
  101|  4.37k|                mat(0),
  102|  4.37k|                flags(0) {}
_ZNK6Assimp12AC3DImporter7Surface7GetTypeEv:
  119|  8.75k|        inline uint8_t GetType() const { return (flags & Mask); }
_ZN6Assimp12AC3DImporter6ObjectC2Ev:
  125|     13|                type(World),
  126|     13|                name(),
  127|     13|                children(),
  128|     13|                texRepeat(1.f, 1.f),
  129|     13|                texOffset(0.0f, 0.0f),
  130|     13|                rotation(),
  131|     13|                translation(),
  132|     13|                vertices(),
  133|     13|                surfaces(),
  134|     13|                numRefs(0),
  135|     13|                subDiv(0),
  136|     13|                crease() {}

_ZN6Assimp11AMFImporter5ClearEv:
   69|    625|void AMFImporter::Clear() {
   70|    625|    mNodeElement_Cur = nullptr;
   71|    625|    mUnit.clear();
   72|    625|    mMaterial_Converted.clear();
   73|    625|    mTexture_Converted.clear();
   74|       |    // Delete all elements
   75|    625|    if (!mNodeElement_List.empty()) {
  ------------------
  |  Branch (75:9): [True: 0, False: 625]
  ------------------
   76|      0|        for (AMFNodeElementBase *ne : mNodeElement_List) {
  ------------------
  |  Branch (76:37): [True: 0, False: 0]
  ------------------
   77|      0|            delete ne;
   78|      0|        }
   79|       |
   80|      0|        mNodeElement_List.clear();
   81|      0|    }
   82|    625|}
_ZN6Assimp11AMFImporterC2Ev:
   85|    624|        mNodeElement_Cur(nullptr),
   86|    624|        mXmlParser(nullptr) {
   87|       |    // empty
   88|    624|}
_ZN6Assimp11AMFImporterD2Ev:
   90|    624|AMFImporter::~AMFImporter() {
   91|    624|    delete mXmlParser;
   92|       |    // Clear() is accounting if data already is deleted. So, just check again if all data is deleted.
   93|    624|    Clear();
   94|    624|}
_ZN6Assimp11AMFImporter9ParseFileERKNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEPNS_8IOSystemE:
  237|      1|void AMFImporter::ParseFile(const std::string &pFile, IOSystem *pIOHandler) {
  238|      1|    std::unique_ptr<IOStream> file(pIOHandler->Open(pFile, "rb"));
  239|       |
  240|       |    // Check whether we can read from the file
  241|      1|    if (file == nullptr) {
  ------------------
  |  Branch (241:9): [True: 0, False: 1]
  ------------------
  242|      0|        throw DeadlyImportError("Failed to open AMF file ", pFile, ".");
  243|      0|    }
  244|       |
  245|      1|    mXmlParser = new XmlParser();
  246|      1|    if (!mXmlParser->parse(file.get())) {
  ------------------
  |  Branch (246:9): [True: 1, False: 0]
  ------------------
  247|      1|        delete mXmlParser;
  248|      1|        mXmlParser = nullptr;
  249|      1|        throw DeadlyImportError("Failed to create XML reader for file ", pFile, ".");
  250|      1|    }
  251|       |
  252|       |    // Start reading, search for root tag <amf>
  253|      0|    if (!mXmlParser->hasNode("amf")) {
  ------------------
  |  Branch (253:9): [True: 0, False: 0]
  ------------------
  254|      0|        throw DeadlyImportError("Root node \"amf\" not found.");
  255|      0|    }
  256|      0|    ParseNode_Root();
  257|      0|} // namespace Assimp
_ZNK6Assimp11AMFImporter7CanReadERKNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEPNS_8IOSystemEb:
  482|    484|bool AMFImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool /*pCheckSig*/) const {
  483|    484|    static const char *tokens[] = { "<amf" };
  484|       |    return SearchFileHeaderForToken(pIOHandler, pFile, tokens, AI_COUNT_OF(tokens));
  485|    484|}
_ZNK6Assimp11AMFImporter7GetInfoEv:
  487|    635|const aiImporterDesc *AMFImporter::GetInfo() const {
  488|    635|    return &Description;
  489|    635|}
_ZN6Assimp11AMFImporter14InternReadFileERKNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEP7aiScenePNS_8IOSystemE:
  491|      1|void AMFImporter::InternReadFile(const std::string &pFile, aiScene *pScene, IOSystem *pIOHandler) {
  492|      1|    Clear(); // delete old graph.
  493|      1|    ParseFile(pFile, pIOHandler);
  494|      1|    Postprocess_BuildScene(pScene);
  495|       |    // scene graph is ready, exit.
  496|      1|}

_ZN6Assimp11ASEImporterC2Ev:
   85|    624|        mParser(), mBuffer(), pcScene(), configRecomputeNormals(), noSkeletonMesh() {
   86|       |    // empty
   87|    624|}
_ZNK6Assimp11ASEImporter7CanReadERKNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEPNS_8IOSystemEb:
   91|    453|bool ASEImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool /*checkSig*/) const {
   92|    453|    static const char *tokens[] = { "*3dsmax_asciiexport" };
   93|       |    return SearchFileHeaderForToken(pIOHandler, pFile, tokens, AI_COUNT_OF(tokens));
   94|    453|}
_ZNK6Assimp11ASEImporter7GetInfoEv:
   98|    677|const aiImporterDesc *ASEImporter::GetInfo() const {
   99|    677|    return &desc;
  100|    677|}
_ZN6Assimp11ASEImporter15SetupPropertiesEPKNS_8ImporterE:
  104|     43|void ASEImporter::SetupProperties(const Importer *pImp) {
  105|     43|    configRecomputeNormals = (pImp->GetPropertyInteger(
  ------------------
  |  Branch (105:31): [True: 43, False: 0]
  ------------------
  106|     43|                                      AI_CONFIG_IMPORT_ASE_RECONSTRUCT_NORMALS, 1) ?
  107|     43|                                      true :
  108|     43|                                      false);
  109|       |
  110|       |    noSkeletonMesh = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_NO_SKELETON_MESHES, 0) != 0;
  111|     43|}
_ZN6Assimp11ASEImporter14InternReadFileERKNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEP7aiScenePNS_8IOSystemE:
  116|     43|        aiScene *pScene, IOSystem *pIOHandler) {
  117|     43|    std::unique_ptr<IOStream> file(pIOHandler->Open(pFile, "rb"));
  118|       |
  119|       |    // Check whether we can read from the file
  120|     43|    if (file == nullptr) {
  ------------------
  |  Branch (120:9): [True: 0, False: 43]
  ------------------
  121|      0|        throw DeadlyImportError("Failed to open ASE file ", pFile, ".");
  122|      0|    }
  123|       |
  124|       |    // Allocate storage and copy the contents of the file to a memory buffer
  125|     43|    std::vector<char> mBuffer2;
  126|     43|    TextFileToBuffer(file.get(), mBuffer2);
  127|     43|    const size_t fileSize = mBuffer2.size();
  128|     43|    this->mBuffer = &mBuffer2[0];
  129|     43|    this->pcScene = pScene;
  130|       |
  131|       |    // ------------------------------------------------------------------
  132|       |    // Guess the file format by looking at the extension
  133|       |    // ASC is considered to be the older format 110,
  134|       |    // ASE is the actual version 200 (that is currently written by max)
  135|       |    // ------------------------------------------------------------------
  136|     43|    unsigned int defaultFormat;
  137|     43|    std::string::size_type s = pFile.length() - 1;
  138|     43|    switch (pFile.c_str()[s]) {
  139|       |
  140|      0|    case 'C':
  ------------------
  |  Branch (140:5): [True: 0, False: 43]
  ------------------
  141|      0|    case 'c':
  ------------------
  |  Branch (141:5): [True: 0, False: 43]
  ------------------
  142|      0|        defaultFormat = AI_ASE_OLD_FILE_FORMAT;
  143|      0|        break;
  144|     43|    default:
  ------------------
  |  Branch (144:5): [True: 43, False: 0]
  ------------------
  145|     43|        defaultFormat = AI_ASE_NEW_FILE_FORMAT;
  146|     43|    };
  147|       |
  148|       |    // Construct an ASE parser and parse the file
  149|     43|    ASE::Parser parser(mBuffer, fileSize, defaultFormat);
  150|     43|    mParser = &parser;
  151|     43|    mParser->Parse();
  152|       |
  153|       |    //------------------------------------------------------------------
  154|       |    // Check whether we god at least one mesh. If we did - generate
  155|       |    // materials and copy meshes.
  156|       |    // ------------------------------------------------------------------
  157|     43|    if (!mParser->m_vMeshes.empty()) {
  ------------------
  |  Branch (157:9): [True: 17, False: 26]
  ------------------
  158|       |
  159|       |        // If absolutely no material has been loaded from the file
  160|       |        // we need to generate a default material
  161|     17|        GenerateDefaultMaterial();
  162|       |
  163|       |        // process all meshes
  164|     17|        bool tookNormals = false;
  165|     17|        std::vector<aiMesh *> avOutMeshes;
  166|     17|        avOutMeshes.reserve(mParser->m_vMeshes.size() * 2);
  167|     41|        for (std::vector<ASE::Mesh>::iterator i = mParser->m_vMeshes.begin(); i != mParser->m_vMeshes.end(); ++i) {
  ------------------
  |  Branch (167:79): [True: 24, False: 17]
  ------------------
  168|     24|            if ((*i).bSkip) {
  ------------------
  |  Branch (168:17): [True: 0, False: 24]
  ------------------
  169|      0|                continue;
  170|      0|            }
  171|     24|            BuildUniqueRepresentation(*i);
  172|       |
  173|       |            // Need to generate proper vertex normals if necessary
  174|     24|            if (GenerateNormals(*i)) {
  ------------------
  |  Branch (174:17): [True: 0, False: 24]
  ------------------
  175|      0|                tookNormals = true;
  176|      0|            }
  177|       |
  178|       |            // Convert all meshes to aiMesh objects
  179|     24|            ConvertMeshes(*i, avOutMeshes);
  180|     24|        }
  181|     17|        if (tookNormals) {
  ------------------
  |  Branch (181:13): [True: 0, False: 17]
  ------------------
  182|      0|            ASSIMP_LOG_DEBUG("ASE: Taking normals from the file. Use "
  183|      0|                             "the AI_CONFIG_IMPORT_ASE_RECONSTRUCT_NORMALS setting if you "
  184|      0|                             "experience problems");
  185|      0|        }
  186|       |
  187|       |        // Now build the output mesh list. Remove dummies
  188|     17|        pScene->mNumMeshes = (unsigned int)avOutMeshes.size();
  189|     17|        aiMesh **pp = pScene->mMeshes = new aiMesh *[pScene->mNumMeshes];
  190|     39|        for (std::vector<aiMesh *>::const_iterator i = avOutMeshes.begin(); i != avOutMeshes.end(); ++i) {
  ------------------
  |  Branch (190:77): [True: 22, False: 17]
  ------------------
  191|     22|            if (!(*i)->mNumFaces) {
  ------------------
  |  Branch (191:17): [True: 6, False: 16]
  ------------------
  192|      6|                continue;
  193|      6|            }
  194|     16|            *pp++ = *i;
  195|     16|        }
  196|     17|        pScene->mNumMeshes = (unsigned int)(pp - pScene->mMeshes);
  197|       |
  198|       |        // Build final material indices (remove submaterials and setup
  199|       |        // the final list)
  200|     17|        BuildMaterialIndices();
  201|     17|    }
  202|       |
  203|       |    // ------------------------------------------------------------------
  204|       |    // Copy all scene graph nodes - lights, cameras, dummies and meshes
  205|       |    // into one huge list.
  206|       |    //------------------------------------------------------------------
  207|     43|    std::vector<BaseNode *> nodes;
  208|     43|    nodes.reserve(mParser->m_vMeshes.size() + mParser->m_vLights.size() + mParser->m_vCameras.size() + mParser->m_vDummies.size());
  209|       |
  210|       |    // Lights
  211|     43|    for (auto &light : mParser->m_vLights)
  ------------------
  |  Branch (211:22): [True: 3, False: 43]
  ------------------
  212|      3|        nodes.push_back(&light);
  213|       |    // Cameras
  214|     43|    for (auto &camera : mParser->m_vCameras)
  ------------------
  |  Branch (214:23): [True: 4, False: 43]
  ------------------
  215|      4|        nodes.push_back(&camera);
  216|       |    // Meshes
  217|     43|    for (auto &mesh : mParser->m_vMeshes)
  ------------------
  |  Branch (217:21): [True: 22, False: 43]
  ------------------
  218|     22|        nodes.push_back(&mesh);
  219|       |    // Dummies
  220|     43|    for (auto &dummy : mParser->m_vDummies)
  ------------------
  |  Branch (220:22): [True: 0, False: 43]
  ------------------
  221|      0|        nodes.push_back(&dummy);
  222|       |
  223|       |    // build the final node graph
  224|     43|    BuildNodes(nodes);
  225|       |
  226|       |    // build output animations
  227|     43|    BuildAnimations(nodes);
  228|       |
  229|       |    // build output cameras
  230|     43|    BuildCameras();
  231|       |
  232|       |    // build output lights
  233|     43|    BuildLights();
  234|       |
  235|       |    // ------------------------------------------------------------------
  236|       |    // If we have no meshes use the SkeletonMeshBuilder helper class
  237|       |    // to build a mesh for the animation skeleton
  238|       |    // FIXME: very strange results
  239|       |    // ------------------------------------------------------------------
  240|     43|    if (!pScene->mNumMeshes) {
  ------------------
  |  Branch (240:9): [True: 8, False: 35]
  ------------------
  241|      8|        pScene->mFlags |= AI_SCENE_FLAGS_INCOMPLETE;
  242|      8|        if (!noSkeletonMesh) {
  ------------------
  |  Branch (242:13): [True: 8, False: 0]
  ------------------
  243|      8|            SkeletonMeshBuilder skeleton(pScene);
  244|      8|        }
  245|      8|    }
  246|     43|}
_ZN6Assimp11ASEImporter23GenerateDefaultMaterialEv:
  248|     17|void ASEImporter::GenerateDefaultMaterial() {
  249|     17|    ai_assert(nullptr != mParser);
  250|       |
  251|     17|    bool bHas = false;
  252|     41|    for (std::vector<ASE::Mesh>::iterator i = mParser->m_vMeshes.begin(); i != mParser->m_vMeshes.end(); ++i) {
  ------------------
  |  Branch (252:75): [True: 24, False: 17]
  ------------------
  253|     24|        if ((*i).bSkip) continue;
  ------------------
  |  Branch (253:13): [True: 0, False: 24]
  ------------------
  254|     24|        if (ASE::Face::DEFAULT_MATINDEX == (*i).iMaterialIndex) {
  ------------------
  |  Branch (254:13): [True: 16, False: 8]
  ------------------
  255|     16|            (*i).iMaterialIndex = (unsigned int)mParser->m_vMaterials.size();
  256|     16|            bHas = true;
  257|     16|        }
  258|     24|    }
  259|     17|    if (bHas || mParser->m_vMaterials.empty()) {
  ------------------
  |  Branch (259:9): [True: 13, False: 4]
  |  Branch (259:17): [True: 0, False: 4]
  ------------------
  260|       |        // add a simple material without submaterials to the parser's list
  261|     13|        mParser->m_vMaterials.emplace_back(AI_DEFAULT_MATERIAL_NAME);
  262|     13|        ASE::Material &mat = mParser->m_vMaterials.back();
  263|       |
  264|     13|        mat.mDiffuse = aiColor3D(0.6f, 0.6f, 0.6f);
  265|     13|        mat.mSpecular = aiColor3D(1.0f, 1.0f, 1.0f);
  266|     13|        mat.mAmbient = aiColor3D(0.05f, 0.05f, 0.05f);
  267|     13|        mat.mShading = Discreet3DS::Gouraud;
  268|     13|    }
  269|     17|}
_ZN6Assimp11ASEImporter15BuildAnimationsERKNSt3__16vectorIPNS_3ASE8BaseNodeENS1_9allocatorIS5_EEEE:
  272|     17|void ASEImporter::BuildAnimations(const std::vector<BaseNode *> &nodes) {
  273|       |    // check whether we have at least one mesh which has animations
  274|     17|    std::vector<ASE::BaseNode *>::const_iterator i = nodes.begin();
  275|     17|    unsigned int iNum = 0;
  276|     46|    for (; i != nodes.end(); ++i) {
  ------------------
  |  Branch (276:12): [True: 29, False: 17]
  ------------------
  277|       |
  278|       |        // TODO: Implement Bezier & TCB support
  279|     29|        if ((*i)->mAnim.mPositionType != ASE::Animation::TRACK) {
  ------------------
  |  Branch (279:13): [True: 0, False: 29]
  ------------------
  280|      0|            ASSIMP_LOG_WARN("ASE: Position controller uses Bezier/TCB keys. "
  281|      0|                            "This is not supported.");
  282|      0|        }
  283|     29|        if ((*i)->mAnim.mRotationType != ASE::Animation::TRACK) {
  ------------------
  |  Branch (283:13): [True: 0, False: 29]
  ------------------
  284|      0|            ASSIMP_LOG_WARN("ASE: Rotation controller uses Bezier/TCB keys. "
  285|      0|                            "This is not supported.");
  286|      0|        }
  287|     29|        if ((*i)->mAnim.mScalingType != ASE::Animation::TRACK) {
  ------------------
  |  Branch (287:13): [True: 0, False: 29]
  ------------------
  288|      0|            ASSIMP_LOG_WARN("ASE: Position controller uses Bezier/TCB keys. "
  289|      0|                            "This is not supported.");
  290|      0|        }
  291|       |
  292|       |        // We compare against 1 here - firstly one key is not
  293|       |        // really an animation and secondly MAX writes dummies
  294|       |        // that represent the node transformation.
  295|     29|        if ((*i)->mAnim.akeyPositions.size() > 1 || (*i)->mAnim.akeyRotations.size() > 1 || (*i)->mAnim.akeyScaling.size() > 1) {
  ------------------
  |  Branch (295:13): [True: 10, False: 19]
  |  Branch (295:53): [True: 3, False: 16]
  |  Branch (295:93): [True: 0, False: 16]
  ------------------
  296|     13|            ++iNum;
  297|     13|        }
  298|     29|        if ((*i)->mTargetAnim.akeyPositions.size() > 1 && is_not_qnan((*i)->mTargetPosition.x)) {
  ------------------
  |  Branch (298:13): [True: 3, False: 26]
  |  Branch (298:59): [True: 3, False: 0]
  ------------------
  299|      3|            ++iNum;
  300|      3|        }
  301|     29|    }
  302|     17|    if (iNum) {
  ------------------
  |  Branch (302:9): [True: 11, False: 6]
  ------------------
  303|       |        // Generate a new animation channel and setup everything for it
  304|     11|        pcScene->mNumAnimations = 1;
  305|     11|        pcScene->mAnimations = new aiAnimation *[1];
  306|     11|        aiAnimation *pcAnim = pcScene->mAnimations[0] = new aiAnimation();
  307|     11|        pcAnim->mNumChannels = iNum;
  308|     11|        pcAnim->mChannels = new aiNodeAnim *[iNum];
  309|     11|        pcAnim->mTicksPerSecond = mParser->iFrameSpeed * mParser->iTicksPerFrame;
  310|       |
  311|     11|        iNum = 0;
  312|       |
  313|       |        // Now iterate through all meshes and collect all data we can find
  314|     32|        for (i = nodes.begin(); i != nodes.end(); ++i) {
  ------------------
  |  Branch (314:33): [True: 21, False: 11]
  ------------------
  315|       |
  316|     21|            ASE::BaseNode *me = *i;
  317|     21|            if (me->mTargetAnim.akeyPositions.size() > 1 && is_not_qnan(me->mTargetPosition.x)) {
  ------------------
  |  Branch (317:17): [True: 3, False: 18]
  |  Branch (317:61): [True: 3, False: 0]
  ------------------
  318|       |                // Generate an extra channel for the camera/light target.
  319|       |                // BuildNodes() does also generate an extra node, named
  320|       |                // <baseName>.Target.
  321|      3|                aiNodeAnim *nd = pcAnim->mChannels[iNum++] = new aiNodeAnim();
  322|      3|                nd->mNodeName.Set(me->mName + ".Target");
  323|       |
  324|       |                // Allocate the key array and fill it
  325|      3|                nd->mNumPositionKeys = (unsigned int)me->mTargetAnim.akeyPositions.size();
  326|      3|                nd->mPositionKeys = new aiVectorKey[nd->mNumPositionKeys];
  327|       |
  328|      3|                ::memcpy(nd->mPositionKeys, &me->mTargetAnim.akeyPositions[0],
  329|      3|                        nd->mNumPositionKeys * sizeof(aiVectorKey));
  330|      3|            }
  331|       |
  332|     21|            if (me->mAnim.akeyPositions.size() > 1 || me->mAnim.akeyRotations.size() > 1 || me->mAnim.akeyScaling.size() > 1) {
  ------------------
  |  Branch (332:17): [True: 10, False: 11]
  |  Branch (332:55): [True: 3, False: 8]
  |  Branch (332:93): [True: 0, False: 8]
  ------------------
  333|       |                // Begin a new node animation channel for this node
  334|     13|                aiNodeAnim *nd = pcAnim->mChannels[iNum++] = new aiNodeAnim();
  335|     13|                nd->mNodeName.Set(me->mName);
  336|       |
  337|       |                // copy position keys
  338|     13|                if (me->mAnim.akeyPositions.size() > 1) {
  ------------------
  |  Branch (338:21): [True: 10, False: 3]
  ------------------
  339|       |                    // Allocate the key array and fill it
  340|     10|                    nd->mNumPositionKeys = (unsigned int)me->mAnim.akeyPositions.size();
  341|     10|                    nd->mPositionKeys = new aiVectorKey[nd->mNumPositionKeys];
  342|       |
  343|     10|                    ::memcpy(nd->mPositionKeys, &me->mAnim.akeyPositions[0],
  344|     10|                            nd->mNumPositionKeys * sizeof(aiVectorKey));
  345|     10|                }
  346|       |                // copy rotation keys
  347|     13|                if (me->mAnim.akeyRotations.size() > 1) {
  ------------------
  |  Branch (347:21): [True: 10, False: 3]
  ------------------
  348|       |                    // Allocate the key array and fill it
  349|     10|                    nd->mNumRotationKeys = (unsigned int)me->mAnim.akeyRotations.size();
  350|     10|                    nd->mRotationKeys = new aiQuatKey[nd->mNumRotationKeys];
  351|       |
  352|       |                    // --------------------------------------------------------------------
  353|       |                    // Rotation keys are offsets to the previous keys.
  354|       |                    // We have the quaternion representations of all
  355|       |                    // of them, so we just need to concatenate all
  356|       |                    // (unit-length) quaternions to get the absolute
  357|       |                    // rotations.
  358|       |                    // Rotation keys are ABSOLUTE for older files
  359|       |                    // --------------------------------------------------------------------
  360|       |
  361|     10|                    aiQuaternion cur;
  362|  1.00k|                    for (unsigned int a = 0; a < nd->mNumRotationKeys; ++a) {
  ------------------
  |  Branch (362:46): [True: 992, False: 10]
  ------------------
  363|    992|                        aiQuatKey q = me->mAnim.akeyRotations[a];
  364|       |
  365|    992|                        if (mParser->iFileFormat > 110) {
  ------------------
  |  Branch (365:29): [True: 901, False: 91]
  ------------------
  366|    901|                            cur = (a ? cur * q.mValue : q.mValue);
  ------------------
  |  Branch (366:36): [True: 892, False: 9]
  ------------------
  367|    901|                            q.mValue = cur.Normalize();
  368|    901|                        }
  369|    992|                        nd->mRotationKeys[a] = q;
  370|       |
  371|       |                        // need this to get to Assimp quaternion conventions
  372|    992|                        nd->mRotationKeys[a].mValue.w *= -1.f;
  373|    992|                    }
  374|     10|                }
  375|       |                // copy scaling keys
  376|     13|                if (me->mAnim.akeyScaling.size() > 1) {
  ------------------
  |  Branch (376:21): [True: 1, False: 12]
  ------------------
  377|       |                    // Allocate the key array and fill it
  378|      1|                    nd->mNumScalingKeys = (unsigned int)me->mAnim.akeyScaling.size();
  379|      1|                    nd->mScalingKeys = new aiVectorKey[nd->mNumScalingKeys];
  380|       |
  381|      1|                    ::memcpy(nd->mScalingKeys, &me->mAnim.akeyScaling[0],
  382|      1|                            nd->mNumScalingKeys * sizeof(aiVectorKey));
  383|      1|                }
  384|     13|            }
  385|     21|        }
  386|     11|    }
  387|     17|}
_ZN6Assimp11ASEImporter12BuildCamerasEv:
  391|     17|void ASEImporter::BuildCameras() {
  392|     17|    if (!mParser->m_vCameras.empty()) {
  ------------------
  |  Branch (392:9): [True: 4, False: 13]
  ------------------
  393|      4|        pcScene->mNumCameras = (unsigned int)mParser->m_vCameras.size();
  394|      4|        pcScene->mCameras = new aiCamera *[pcScene->mNumCameras];
  395|       |
  396|      8|        for (unsigned int i = 0; i < pcScene->mNumCameras; ++i) {
  ------------------
  |  Branch (396:34): [True: 4, False: 4]
  ------------------
  397|      4|            aiCamera *out = pcScene->mCameras[i] = new aiCamera();
  398|      4|            ASE::Camera &in = mParser->m_vCameras[i];
  399|       |
  400|       |            // copy members
  401|      4|            out->mClipPlaneFar = in.mFar;
  402|      4|            out->mClipPlaneNear = (in.mNear ? in.mNear : 0.1f);
  ------------------
  |  Branch (402:36): [True: 0, False: 4]
  ------------------
  403|      4|            out->mHorizontalFOV = in.mFOV;
  404|       |
  405|      4|            out->mName.Set(in.mName);
  406|      4|        }
  407|      4|    }
  408|     17|}
_ZN6Assimp11ASEImporter11BuildLightsEv:
  412|     17|void ASEImporter::BuildLights() {
  413|     17|    if (!mParser->m_vLights.empty()) {
  ------------------
  |  Branch (413:9): [True: 1, False: 16]
  ------------------
  414|      1|        pcScene->mNumLights = (unsigned int)mParser->m_vLights.size();
  415|      1|        pcScene->mLights = new aiLight *[pcScene->mNumLights];
  416|       |
  417|      4|        for (unsigned int i = 0; i < pcScene->mNumLights; ++i) {
  ------------------
  |  Branch (417:34): [True: 3, False: 1]
  ------------------
  418|      3|            aiLight *out = pcScene->mLights[i] = new aiLight();
  419|      3|            ASE::Light &in = mParser->m_vLights[i];
  420|       |
  421|       |            // The direction is encoded in the transformation matrix of the node.
  422|       |            // In 3DS MAX the light source points into negative Z direction if
  423|       |            // the node transformation is the identity.
  424|      3|            out->mDirection = aiVector3D(0.f, 0.f, -1.f);
  425|       |
  426|      3|            out->mName.Set(in.mName);
  427|      3|            switch (in.mLightType) {
  428|      0|            case ASE::Light::TARGET:
  ------------------
  |  Branch (428:13): [True: 0, False: 3]
  ------------------
  429|      0|                out->mType = aiLightSource_SPOT;
  430|      0|                out->mAngleInnerCone = AI_DEG_TO_RAD(in.mAngle);
  431|      0|                out->mAngleOuterCone = (in.mFalloff ? AI_DEG_TO_RAD(in.mFalloff) : out->mAngleInnerCone);
  ------------------
  |  Branch (431:41): [True: 0, False: 0]
  ------------------
  432|      0|                break;
  433|       |
  434|      2|            case ASE::Light::DIRECTIONAL:
  ------------------
  |  Branch (434:13): [True: 2, False: 1]
  ------------------
  435|      2|                out->mType = aiLightSource_DIRECTIONAL;
  436|      2|                break;
  437|       |
  438|      1|            default:
  ------------------
  |  Branch (438:13): [True: 1, False: 2]
  ------------------
  439|       |                //case ASE::Light::OMNI:
  440|      1|                out->mType = aiLightSource_POINT;
  441|      1|                break;
  442|      3|            };
  443|      3|            out->mColorDiffuse = out->mColorSpecular = in.mColor * in.mIntensity;
  444|      3|        }
  445|      1|    }
  446|     17|}
_ZN6Assimp11ASEImporter8AddNodesERKNSt3__16vectorIPNS_3ASE8BaseNodeENS1_9allocatorIS5_EEEEP6aiNodeRKNS1_12basic_stringIcNS1_11char_traitsIcEENS6_IcEEEE:
  449|     17|void ASEImporter::AddNodes(const std::vector<BaseNode *> &nodes, aiNode *pcParent, const std::string &name) {
  450|     17|    aiMatrix4x4 m;
  451|     17|    AddNodes(nodes, pcParent, name, m);
  452|     17|}
_ZN6Assimp11ASEImporter9AddMeshesEPKNS_3ASE8BaseNodeEP6aiNode:
  456|     22|void ASEImporter::AddMeshes(const ASE::BaseNode *snode, aiNode *node) {
  457|     64|    for (unsigned int i = 0; i < pcScene->mNumMeshes; ++i) {
  ------------------
  |  Branch (457:30): [True: 42, False: 22]
  ------------------
  458|       |        // Get the name of the mesh (the mesh instance has been temporarily stored in the third vertex color)
  459|     42|        const aiMesh *pcMesh = pcScene->mMeshes[i];
  460|     42|        const ASE::Mesh *mesh = (const ASE::Mesh *)pcMesh->mColors[2];
  461|       |
  462|     42|        if (mesh == snode) {
  ------------------
  |  Branch (462:13): [True: 16, False: 26]
  ------------------
  463|     16|            ++node->mNumMeshes;
  464|     16|        }
  465|     42|    }
  466|       |
  467|     22|    if (node->mNumMeshes) {
  ------------------
  |  Branch (467:9): [True: 16, False: 6]
  ------------------
  468|     16|        node->mMeshes = new unsigned int[node->mNumMeshes];
  469|     58|        for (unsigned int i = 0, p = 0; i < pcScene->mNumMeshes; ++i) {
  ------------------
  |  Branch (469:41): [True: 42, False: 16]
  ------------------
  470|       |
  471|     42|            const aiMesh *pcMesh = pcScene->mMeshes[i];
  472|     42|            const ASE::Mesh *mesh = (const ASE::Mesh *)pcMesh->mColors[2];
  473|     42|            if (mesh == snode) {
  ------------------
  |  Branch (473:17): [True: 16, False: 26]
  ------------------
  474|     16|                node->mMeshes[p++] = i;
  475|       |
  476|       |                // Transform all vertices of the mesh back into their local space ->
  477|       |                // at the moment they are pretransformed
  478|     16|                aiMatrix4x4 m = mesh->mTransform;
  479|     16|                m.Inverse();
  480|       |
  481|     16|                aiVector3D *pvCurPtr = pcMesh->mVertices;
  482|     16|                const aiVector3D *pvEndPtr = pvCurPtr + pcMesh->mNumVertices;
  483|    712|                while (pvCurPtr != pvEndPtr) {
  ------------------
  |  Branch (483:24): [True: 696, False: 16]
  ------------------
  484|    696|                    *pvCurPtr = m * (*pvCurPtr);
  485|    696|                    pvCurPtr++;
  486|    696|                }
  487|       |
  488|       |                // Do the same for the normal vectors, if we have them.
  489|       |                // As always, inverse transpose.
  490|     16|                if (pcMesh->mNormals) {
  ------------------
  |  Branch (490:21): [True: 16, False: 0]
  ------------------
  491|     16|                    aiMatrix3x3 m3 = aiMatrix3x3(mesh->mTransform);
  492|     16|                    m3.Transpose();
  493|       |
  494|     16|                    pvCurPtr = pcMesh->mNormals;
  495|     16|                    pvEndPtr = pvCurPtr + pcMesh->mNumVertices;
  496|    712|                    while (pvCurPtr != pvEndPtr) {
  ------------------
  |  Branch (496:28): [True: 696, False: 16]
  ------------------
  497|    696|                        *pvCurPtr = m3 * (*pvCurPtr);
  498|    696|                        pvCurPtr++;
  499|    696|                    }
  500|     16|                }
  501|     16|            }
  502|     42|        }
  503|     16|    }
  504|     22|}
_ZN6Assimp11ASEImporter8AddNodesERKNSt3__16vectorIPNS_3ASE8BaseNodeENS1_9allocatorIS5_EEEEP6aiNodeRKNS1_12basic_stringIcNS1_11char_traitsIcEENS6_IcEEEERK12aiMatrix4x4tIfE:
  509|     46|        const aiMatrix4x4 &mat) {
  510|     46|    const size_t len = name.size();
  511|     46|    ai_assert(4 <= AI_MAX_NUMBER_OF_COLOR_SETS);
  512|       |
  513|       |    // Receives child nodes for the pcParent node
  514|     46|    std::vector<aiNode *> apcNodes;
  515|       |
  516|       |    // Now iterate through all nodes in the scene and search for one
  517|       |    // which has *us* as parent.
  518|    166|    for (std::vector<BaseNode *>::const_iterator it = nodes.begin(), end = nodes.end(); it != end; ++it) {
  ------------------
  |  Branch (518:89): [True: 120, False: 46]
  ------------------
  519|    120|        const BaseNode *snode = *it;
  520|    120|        if (!name.empty()) {
  ------------------
  |  Branch (520:13): [True: 91, False: 29]
  ------------------
  521|     91|            if (len != snode->mParent.length() || name != snode->mParent.c_str()) {
  ------------------
  |  Branch (521:17): [True: 90, False: 1]
  |  Branch (521:51): [True: 0, False: 1]
  ------------------
  522|     90|                continue;
  523|     90|            }
  524|     91|        } else if (snode->mParent.length()) {
  ------------------
  |  Branch (524:20): [True: 1, False: 28]
  ------------------
  525|      1|            continue;
  526|      1|        }
  527|       |
  528|     29|        (*it)->mProcessed = true;
  529|       |
  530|       |        // Allocate a new node and add it to the output data structure
  531|     29|        apcNodes.push_back(new aiNode);
  532|     29|        aiNode *node = apcNodes.back();
  533|       |
  534|     29|        node->mName.Set((snode->mName.length() ? snode->mName.c_str() : "Unnamed_Node"));
  ------------------
  |  Branch (534:26): [True: 29, False: 0]
  ------------------
  535|     29|        node->mParent = pcParent;
  536|       |
  537|       |        // Setup the transformation matrix of the node
  538|     29|        aiMatrix4x4 mParentAdjust = mat;
  539|     29|        mParentAdjust.Inverse();
  540|     29|        node->mTransformation = mParentAdjust * snode->mTransform;
  541|       |
  542|       |        // Add sub nodes - prevent stack overflow due to recursive parenting
  543|     29|        if (node->mName != node->mParent->mName && node->mName != node->mParent->mParent->mName) {
  ------------------
  |  Branch (543:13): [True: 29, False: 0]
  |  Branch (543:52): [True: 29, False: 0]
  ------------------
  544|     29|            AddNodes(nodes, node, node->mName.C_Str(), snode->mTransform);
  545|     29|        }
  546|       |
  547|       |        // Further processing depends on the type of the node
  548|     29|        if (snode->mType == ASE::BaseNode::Mesh) {
  ------------------
  |  Branch (548:13): [True: 22, False: 7]
  ------------------
  549|       |            // If the type of this node is "Mesh" we need to search
  550|       |            // the list of output meshes in the data structure for
  551|       |            // all those that belonged to this node once. This is
  552|       |            // slightly inconvinient here and a better solution should
  553|       |            // be used when this code is refactored next.
  554|     22|            AddMeshes(snode, node);
  555|     22|        } else if (is_not_qnan(snode->mTargetPosition.x)) {
  ------------------
  |  Branch (555:20): [True: 4, False: 3]
  ------------------
  556|       |            // If this is a target camera or light we generate a small
  557|       |            // child node which marks the position of the camera
  558|       |            // target (the direction information is contained in *this*
  559|       |            // node's animation track but the exact target position
  560|       |            // would be lost otherwise)
  561|      4|            if (!node->mNumChildren) {
  ------------------
  |  Branch (561:17): [True: 3, False: 1]
  ------------------
  562|      3|                node->mChildren = new aiNode *[1];
  563|      3|            }
  564|       |
  565|      4|            aiNode *nd = new aiNode();
  566|       |
  567|      4|            nd->mName.Set(snode->mName + ".Target");
  568|       |
  569|      4|            nd->mTransformation.a4 = snode->mTargetPosition.x - snode->mTransform.a4;
  570|      4|            nd->mTransformation.b4 = snode->mTargetPosition.y - snode->mTransform.b4;
  571|      4|            nd->mTransformation.c4 = snode->mTargetPosition.z - snode->mTransform.c4;
  572|       |
  573|      4|            nd->mParent = node;
  574|       |
  575|       |            // The .Target node is always the first child node
  576|      5|            for (unsigned int m = 0; m < node->mNumChildren; ++m)
  ------------------
  |  Branch (576:38): [True: 1, False: 4]
  ------------------
  577|      1|                node->mChildren[m + 1] = node->mChildren[m];
  578|       |
  579|      4|            node->mChildren[0] = nd;
  580|      4|            node->mNumChildren++;
  581|       |
  582|       |            // What we did is so great, it is at least worth a debug message
  583|      4|            ASSIMP_LOG_VERBOSE_DEBUG("ASE: Generating separate target node (", snode->mName, ")");
  584|      4|        }
  585|     29|    }
  586|       |
  587|       |    // Allocate enough space for the child nodes
  588|       |    // We allocate one slot more  in case this is a target camera/light
  589|     46|    pcParent->mNumChildren = (unsigned int)apcNodes.size();
  590|     46|    if (pcParent->mNumChildren) {
  ------------------
  |  Branch (590:9): [True: 16, False: 30]
  ------------------
  591|     16|        pcParent->mChildren = new aiNode *[apcNodes.size() + 1 /* PLUS ONE !!! */];
  592|       |
  593|       |        // now build all nodes for our nice new children
  594|     45|        for (unsigned int p = 0; p < apcNodes.size(); ++p)
  ------------------
  |  Branch (594:34): [True: 29, False: 16]
  ------------------
  595|     29|            pcParent->mChildren[p] = apcNodes[p];
  596|     16|    }
  597|     46|    return;
  598|     46|}
_ZN6Assimp11ASEImporter10BuildNodesERNSt3__16vectorIPNS_3ASE8BaseNodeENS1_9allocatorIS5_EEEE:
  602|     17|void ASEImporter::BuildNodes(std::vector<BaseNode *> &nodes) {
  603|     17|    ai_assert(nullptr != pcScene);
  604|       |
  605|       |    // allocate the one and only root node
  606|     17|    aiNode *root = pcScene->mRootNode = new aiNode();
  607|     17|    root->mName.Set("<ASERoot>");
  608|       |
  609|       |    // Setup the coordinate system transformation
  610|     17|    pcScene->mRootNode->mNumChildren = 1;
  611|     17|    pcScene->mRootNode->mChildren = new aiNode *[1];
  612|     17|    aiNode *ch = pcScene->mRootNode->mChildren[0] = new aiNode();
  613|     17|    ch->mParent = root;
  614|       |
  615|       |    // Change the transformation matrix of all nodes
  616|     29|    for (BaseNode *node : nodes) {
  ------------------
  |  Branch (616:25): [True: 29, False: 17]
  ------------------
  617|     29|        aiMatrix4x4 &m = node->mTransform;
  618|     29|        m.Transpose(); // row-order vs column-order
  619|     29|    }
  620|       |
  621|       |    // add all nodes
  622|     17|    static const std::string none = "";
  623|     17|    AddNodes(nodes, ch, none);
  624|       |
  625|       |    // now iterate through al nodes and find those that have not yet
  626|       |    // been added to the nodegraph (= their parent could not be recognized)
  627|     17|    std::vector<const BaseNode *> aiList;
  628|     46|    for (std::vector<BaseNode *>::iterator it = nodes.begin(), end = nodes.end(); it != end; ++it) {
  ------------------
  |  Branch (628:83): [True: 29, False: 17]
  ------------------
  629|     29|        if ((*it)->mProcessed) {
  ------------------
  |  Branch (629:13): [True: 29, False: 0]
  ------------------
  630|     29|            continue;
  631|     29|        }
  632|       |
  633|       |        // check whether our parent is known
  634|      0|        bool bKnowParent = false;
  635|       |
  636|       |        // search the list another time, starting *here* and try to find out whether
  637|       |        // there is a node that references *us* as a parent
  638|      0|        for (std::vector<BaseNode *>::const_iterator it2 = nodes.begin(); it2 != end; ++it2) {
  ------------------
  |  Branch (638:75): [True: 0, False: 0]
  ------------------
  639|      0|            if (it2 == it) {
  ------------------
  |  Branch (639:17): [True: 0, False: 0]
  ------------------
  640|      0|                continue;
  641|      0|            }
  642|       |
  643|      0|            if ((*it2)->mName == (*it)->mParent) {
  ------------------
  |  Branch (643:17): [True: 0, False: 0]
  ------------------
  644|      0|                bKnowParent = true;
  645|      0|                break;
  646|      0|            }
  647|      0|        }
  648|      0|        if (!bKnowParent) {
  ------------------
  |  Branch (648:13): [True: 0, False: 0]
  ------------------
  649|      0|            aiList.push_back(*it);
  650|      0|        }
  651|      0|    }
  652|       |
  653|       |    // Are there any orphaned nodes?
  654|     17|    if (!aiList.empty()) {
  ------------------
  |  Branch (654:9): [True: 0, False: 17]
  ------------------
  655|      0|        std::vector<aiNode *> apcNodes;
  656|      0|        apcNodes.reserve(aiList.size() + pcScene->mRootNode->mNumChildren);
  657|       |
  658|      0|        for (unsigned int i = 0; i < pcScene->mRootNode->mNumChildren; ++i)
  ------------------
  |  Branch (658:34): [True: 0, False: 0]
  ------------------
  659|      0|            apcNodes.push_back(pcScene->mRootNode->mChildren[i]);
  660|       |
  661|      0|        delete[] pcScene->mRootNode->mChildren;
  662|      0|        for (std::vector<const BaseNode *>::/*const_*/ iterator i = aiList.begin(); i != aiList.end(); ++i) {
  ------------------
  |  Branch (662:85): [True: 0, False: 0]
  ------------------
  663|      0|            const ASE::BaseNode *src = *i;
  664|       |
  665|       |            // The parent is not known, so we can assume that we must add
  666|       |            // this node to the root node of the whole scene
  667|      0|            aiNode *pcNode = new aiNode();
  668|      0|            pcNode->mParent = pcScene->mRootNode;
  669|      0|            pcNode->mName.Set(src->mName);
  670|      0|            AddMeshes(src, pcNode);
  671|      0|            AddNodes(nodes, pcNode, pcNode->mName.data);
  672|      0|            apcNodes.push_back(pcNode);
  673|      0|        }
  674|       |
  675|       |        // Regenerate our output array
  676|      0|        pcScene->mRootNode->mChildren = new aiNode *[apcNodes.size()];
  677|      0|        for (unsigned int i = 0; i < apcNodes.size(); ++i)
  ------------------
  |  Branch (677:34): [True: 0, False: 0]
  ------------------
  678|      0|            pcScene->mRootNode->mChildren[i] = apcNodes[i];
  679|       |
  680|      0|        pcScene->mRootNode->mNumChildren = (unsigned int)apcNodes.size();
  681|      0|    }
  682|       |
  683|       |    // Reset the third color set to nullptr - we used this field to store a temporary pointer
  684|     33|    for (unsigned int i = 0; i < pcScene->mNumMeshes; ++i)
  ------------------
  |  Branch (684:30): [True: 16, False: 17]
  ------------------
  685|     16|        pcScene->mMeshes[i]->mColors[2] = nullptr;
  686|       |
  687|       |    // The root node should not have at least one child or the file is valid
  688|     17|    if (!pcScene->mRootNode->mNumChildren) {
  ------------------
  |  Branch (688:9): [True: 0, False: 17]
  ------------------
  689|      0|        throw DeadlyImportError("ASE: No nodes loaded. The file is either empty or corrupt");
  690|      0|    }
  691|       |
  692|       |    // Now rotate the whole scene 90 degrees around the x axis to convert to internal coordinate system
  693|     17|    pcScene->mRootNode->mTransformation = aiMatrix4x4(1.f, 0.f, 0.f, 0.f,
  694|     17|            0.f, 0.f, 1.f, 0.f, 0.f, -1.f, 0.f, 0.f, 0.f, 0.f, 0.f, 1.f);
  695|     17|}
_ZN6Assimp11ASEImporter25BuildUniqueRepresentationERNS_3ASE4MeshE:
  699|     24|void ASEImporter::BuildUniqueRepresentation(ASE::Mesh &mesh) {
  700|       |    // allocate output storage
  701|     24|    std::vector<aiVector3D> mPositions;
  702|     24|    std::vector<aiVector3D> amTexCoords[AI_MAX_NUMBER_OF_TEXTURECOORDS];
  703|     24|    std::vector<aiColor4D> mVertexColors;
  704|     24|    std::vector<aiVector3D> mNormals;
  705|     24|    std::vector<BoneVertex> mBoneVertices;
  706|       |
  707|     24|    unsigned int iSize = (unsigned int)mesh.mFaces.size() * 3;
  708|     24|    mPositions.resize(iSize);
  709|       |
  710|       |    // optional texture coordinates
  711|    216|    for (unsigned int i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++i) {
  ------------------
  |  Branch (711:30): [True: 192, False: 24]
  ------------------
  712|    192|        if (!mesh.amTexCoords[i].empty()) {
  ------------------
  |  Branch (712:13): [True: 13, False: 179]
  ------------------
  713|     13|            amTexCoords[i].resize(iSize);
  714|     13|        }
  715|    192|    }
  716|       |    // optional vertex colors
  717|     24|    if (!mesh.mVertexColors.empty()) {
  ------------------
  |  Branch (717:9): [True: 0, False: 24]
  ------------------
  718|      0|        mVertexColors.resize(iSize);
  719|      0|    }
  720|       |
  721|       |    // optional vertex normals (vertex normals can simply be copied)
  722|     24|    if (!mesh.mNormals.empty()) {
  ------------------
  |  Branch (722:9): [True: 13, False: 11]
  ------------------
  723|     13|        mNormals.resize(iSize);
  724|     13|    }
  725|       |    // bone vertices. There is no need to change the bone list
  726|     24|    if (!mesh.mBoneVertices.empty()) {
  ------------------
  |  Branch (726:9): [True: 0, False: 24]
  ------------------
  727|      0|        mBoneVertices.resize(iSize);
  728|      0|    }
  729|       |
  730|       |    // iterate through all faces in the mesh
  731|     24|    unsigned int iCurrent = 0, fi = 0;
  732|    266|    for (std::vector<ASE::Face>::iterator i = mesh.mFaces.begin(); i != mesh.mFaces.end(); ++i, ++fi) {
  ------------------
  |  Branch (732:68): [True: 244, False: 22]
  ------------------
  733|    970|        for (unsigned int n = 0; n < 3; ++n, ++iCurrent) {
  ------------------
  |  Branch (733:34): [True: 728, False: 242]
  ------------------
  734|    728|            const uint32_t curIndex = (*i).mIndices[n];
  735|    728|            if (curIndex >= mesh.mPositions.size()) {
  ------------------
  |  Branch (735:17): [True: 2, False: 726]
  ------------------
  736|      2|                throw DeadlyImportError("ASE: Invalid vertex index in face ", fi, ".");
  737|      2|            }
  738|    726|            mPositions[iCurrent] = mesh.mPositions[(*i).mIndices[n]];
  739|       |
  740|       |            // add texture coordinates
  741|  1.27k|            for (unsigned int c = 0; c < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++c) {
  ------------------
  |  Branch (741:38): [True: 1.27k, False: 0]
  ------------------
  742|  1.27k|                if (mesh.amTexCoords[c].empty()) break;
  ------------------
  |  Branch (742:21): [True: 726, False: 546]
  ------------------
  743|    546|                amTexCoords[c][iCurrent] = mesh.amTexCoords[c][(*i).amUVIndices[c][n]];
  744|    546|            }
  745|       |            // add vertex colors
  746|    726|            if (!mesh.mVertexColors.empty()) {
  ------------------
  |  Branch (746:17): [True: 0, False: 726]
  ------------------
  747|      0|                mVertexColors[iCurrent] = mesh.mVertexColors[(*i).mColorIndices[n]];
  748|      0|            }
  749|       |            // add normal vectors
  750|    726|            if (!mesh.mNormals.empty()) {
  ------------------
  |  Branch (750:17): [True: 546, False: 180]
  ------------------
  751|    546|                mNormals[iCurrent] = mesh.mNormals[fi * 3 + n];
  752|    546|                mNormals[iCurrent].Normalize();
  753|    546|            }
  754|       |
  755|       |            // handle bone vertices
  756|    726|            if ((*i).mIndices[n] < mesh.mBoneVertices.size()) {
  ------------------
  |  Branch (756:17): [True: 0, False: 726]
  ------------------
  757|       |                // (sometimes this will cause bone verts to be duplicated
  758|       |                //  however, I' quite sure Schrompf' JoinVerticesStep
  759|       |                //  will fix that again ...)
  760|      0|                mBoneVertices[iCurrent] = mesh.mBoneVertices[(*i).mIndices[n]];
  761|      0|            }
  762|    726|            (*i).mIndices[n] = iCurrent;
  763|    726|        }
  764|    244|    }
  765|       |
  766|       |    // replace the old arrays
  767|     22|    mesh.mNormals = mNormals;
  768|     22|    mesh.mPositions = mPositions;
  769|     22|    mesh.mVertexColors = mVertexColors;
  770|       |
  771|    198|    for (unsigned int c = 0; c < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++c)
  ------------------
  |  Branch (771:30): [True: 176, False: 22]
  ------------------
  772|    176|        mesh.amTexCoords[c] = amTexCoords[c];
  773|     22|}
_ZN6Assimp14CopyASETextureER10aiMaterialRNS_4D3DS7TextureE13aiTextureType:
  777|      4|void CopyASETexture(aiMaterial &mat, ASE::Texture &texture, aiTextureType type) {
  778|       |    // Setup the texture name
  779|      4|    aiString tex;
  780|      4|    tex.Set(texture.mMapName);
  781|      4|    mat.AddProperty(&tex, AI_MATKEY_TEXTURE(type, 0));
  782|       |
  783|       |    // Setup the texture blend factor
  784|      4|    if (is_not_qnan(texture.mTextureBlend))
  ------------------
  |  Branch (784:9): [True: 4, False: 0]
  ------------------
  785|      4|        mat.AddProperty<ai_real>(&texture.mTextureBlend, 1, AI_MATKEY_TEXBLEND(type, 0));
  786|       |
  787|       |    // Setup texture UV transformations
  788|       |    mat.AddProperty<ai_real>(&texture.mOffsetU, 5, AI_MATKEY_UVTRANSFORM(type, 0));
  789|      4|}
_ZN6Assimp11ASEImporter15ConvertMaterialERNS_3ASE8MaterialE:
  793|     19|void ASEImporter::ConvertMaterial(ASE::Material &mat) {
  794|       |    // LARGE TODO: Much code her is copied from 3DS ... join them maybe?
  795|       |
  796|       |    // Allocate the output material
  797|     19|    mat.pcInstance = new aiMaterial();
  798|       |
  799|       |    // At first add the base ambient color of the
  800|       |    // scene to the material
  801|     19|    mat.mAmbient.r += mParser->m_clrAmbient.r;
  802|     19|    mat.mAmbient.g += mParser->m_clrAmbient.g;
  803|     19|    mat.mAmbient.b += mParser->m_clrAmbient.b;
  804|       |
  805|     19|    aiString name;
  806|     19|    name.Set(mat.mName);
  807|     19|    mat.pcInstance->AddProperty(&name, AI_MATKEY_NAME);
  808|       |
  809|       |    // material colors
  810|     19|    mat.pcInstance->AddProperty(&mat.mAmbient, 1, AI_MATKEY_COLOR_AMBIENT);
  811|     19|    mat.pcInstance->AddProperty(&mat.mDiffuse, 1, AI_MATKEY_COLOR_DIFFUSE);
  812|     19|    mat.pcInstance->AddProperty(&mat.mSpecular, 1, AI_MATKEY_COLOR_SPECULAR);
  813|     19|    mat.pcInstance->AddProperty(&mat.mEmissive, 1, AI_MATKEY_COLOR_EMISSIVE);
  814|       |
  815|       |    // shininess
  816|     19|    if (0.0f != mat.mSpecularExponent && 0.0f != mat.mShininessStrength) {
  ------------------
  |  Branch (816:9): [True: 7, False: 12]
  |  Branch (816:42): [True: 0, False: 7]
  ------------------
  817|      0|        mat.pcInstance->AddProperty(&mat.mSpecularExponent, 1, AI_MATKEY_SHININESS);
  818|      0|        mat.pcInstance->AddProperty(&mat.mShininessStrength, 1, AI_MATKEY_SHININESS_STRENGTH);
  819|      0|    }
  820|       |    // If there is no shininess, we can disable phong lighting
  821|     19|    else if (D3DS::Discreet3DS::Metal == mat.mShading ||
  ------------------
  |  Branch (821:14): [True: 0, False: 19]
  ------------------
  822|     19|             D3DS::Discreet3DS::Phong == mat.mShading ||
  ------------------
  |  Branch (822:14): [True: 0, False: 19]
  ------------------
  823|     19|             D3DS::Discreet3DS::Blinn == mat.mShading) {
  ------------------
  |  Branch (823:14): [True: 7, False: 12]
  ------------------
  824|      7|        mat.mShading = D3DS::Discreet3DS::Gouraud;
  825|      7|    }
  826|       |
  827|       |    // opacity
  828|     19|    mat.pcInstance->AddProperty<ai_real>(&mat.mTransparency, 1, AI_MATKEY_OPACITY);
  829|       |
  830|       |    // Two sided rendering?
  831|     19|    if (mat.mTwoSided) {
  ------------------
  |  Branch (831:9): [True: 0, False: 19]
  ------------------
  832|      0|        int i = 1;
  833|      0|        mat.pcInstance->AddProperty<int>(&i, 1, AI_MATKEY_TWOSIDED);
  834|      0|    }
  835|       |
  836|       |    // shading mode
  837|     19|    aiShadingMode eShading = aiShadingMode_NoShading;
  838|     19|    switch (mat.mShading) {
  ------------------
  |  Branch (838:13): [True: 19, False: 0]
  ------------------
  839|      0|    case D3DS::Discreet3DS::Flat:
  ------------------
  |  Branch (839:5): [True: 0, False: 19]
  ------------------
  840|      0|        eShading = aiShadingMode_Flat;
  841|      0|        break;
  842|      0|    case D3DS::Discreet3DS::Phong:
  ------------------
  |  Branch (842:5): [True: 0, False: 19]
  ------------------
  843|      0|        eShading = aiShadingMode_Phong;
  844|      0|        break;
  845|      0|    case D3DS::Discreet3DS::Blinn:
  ------------------
  |  Branch (845:5): [True: 0, False: 19]
  ------------------
  846|      0|        eShading = aiShadingMode_Blinn;
  847|      0|        break;
  848|       |
  849|       |        // I don't know what "Wire" shading should be,
  850|       |        // assume it is simple lambertian diffuse (L dot N) shading
  851|      0|    case D3DS::Discreet3DS::Wire: {
  ------------------
  |  Branch (851:5): [True: 0, False: 19]
  ------------------
  852|       |        // set the wireframe flag
  853|      0|        unsigned int iWire = 1;
  854|      0|        mat.pcInstance->AddProperty<int>((int *)&iWire, 1, AI_MATKEY_ENABLE_WIREFRAME);
  855|      0|    }
  856|       |    // fallthrough
  857|     19|    case D3DS::Discreet3DS::Gouraud:
  ------------------
  |  Branch (857:5): [True: 19, False: 0]
  ------------------
  858|     19|        eShading = aiShadingMode_Gouraud;
  859|     19|        break;
  860|      0|    case D3DS::Discreet3DS::Metal:
  ------------------
  |  Branch (860:5): [True: 0, False: 19]
  ------------------
  861|      0|        eShading = aiShadingMode_CookTorrance;
  862|      0|        break;
  863|     19|    }
  864|     19|    mat.pcInstance->AddProperty<int>((int *)&eShading, 1, AI_MATKEY_SHADING_MODEL);
  865|       |
  866|       |    // DIFFUSE texture
  867|     19|    if (mat.sTexDiffuse.mMapName.length() > 0)
  ------------------
  |  Branch (867:9): [True: 3, False: 16]
  ------------------
  868|      3|        CopyASETexture(*mat.pcInstance, mat.sTexDiffuse, aiTextureType_DIFFUSE);
  869|       |
  870|       |    // SPECULAR texture
  871|     19|    if (mat.sTexSpecular.mMapName.length() > 0)
  ------------------
  |  Branch (871:9): [True: 0, False: 19]
  ------------------
  872|      0|        CopyASETexture(*mat.pcInstance, mat.sTexSpecular, aiTextureType_SPECULAR);
  873|       |
  874|       |    // AMBIENT texture
  875|     19|    if (mat.sTexAmbient.mMapName.length() > 0)
  ------------------
  |  Branch (875:9): [True: 0, False: 19]
  ------------------
  876|      0|        CopyASETexture(*mat.pcInstance, mat.sTexAmbient, aiTextureType_AMBIENT);
  877|       |
  878|       |    // OPACITY texture
  879|     19|    if (mat.sTexOpacity.mMapName.length() > 0)
  ------------------
  |  Branch (879:9): [True: 0, False: 19]
  ------------------
  880|      0|        CopyASETexture(*mat.pcInstance, mat.sTexOpacity, aiTextureType_OPACITY);
  881|       |
  882|       |    // EMISSIVE texture
  883|     19|    if (mat.sTexEmissive.mMapName.length() > 0)
  ------------------
  |  Branch (883:9): [True: 0, False: 19]
  ------------------
  884|      0|        CopyASETexture(*mat.pcInstance, mat.sTexEmissive, aiTextureType_EMISSIVE);
  885|       |
  886|       |    // BUMP texture
  887|     19|    if (mat.sTexBump.mMapName.length() > 0)
  ------------------
  |  Branch (887:9): [True: 0, False: 19]
  ------------------
  888|      0|        CopyASETexture(*mat.pcInstance, mat.sTexBump, aiTextureType_HEIGHT);
  889|       |
  890|       |    // SHININESS texture
  891|     19|    if (mat.sTexShininess.mMapName.length() > 0)
  ------------------
  |  Branch (891:9): [True: 1, False: 18]
  ------------------
  892|      1|        CopyASETexture(*mat.pcInstance, mat.sTexShininess, aiTextureType_SHININESS);
  893|       |
  894|       |    // store the name of the material itself, too
  895|     19|    if (mat.mName.length() > 0) {
  ------------------
  |  Branch (895:9): [True: 19, False: 0]
  ------------------
  896|     19|        aiString tex;
  897|     19|        tex.Set(mat.mName);
  898|       |        mat.pcInstance->AddProperty(&tex, AI_MATKEY_NAME);
  899|     19|    }
  900|     19|    return;
  901|     19|}
_ZN6Assimp11ASEImporter13ConvertMeshesERNS_3ASE4MeshERNSt3__16vectorIP6aiMeshNS4_9allocatorIS7_EEEE:
  905|     22|void ASEImporter::ConvertMeshes(ASE::Mesh &mesh, std::vector<aiMesh *> &avOutMeshes) {
  906|       |    // validate the material index of the mesh
  907|     22|    if (mesh.iMaterialIndex >= mParser->m_vMaterials.size()) {
  ------------------
  |  Branch (907:9): [True: 0, False: 22]
  ------------------
  908|      0|        mesh.iMaterialIndex = (unsigned int)mParser->m_vMaterials.size() - 1;
  909|      0|        ASSIMP_LOG_WARN("Material index is out of range");
  910|      0|    }
  911|       |
  912|       |    // If the material the mesh is assigned to consists of submeshes, split it
  913|     22|    if (!mParser->m_vMaterials[mesh.iMaterialIndex].avSubMaterials.empty()) {
  ------------------
  |  Branch (913:9): [True: 0, False: 22]
  ------------------
  914|      0|        std::vector<ASE::Material> vSubMaterials = mParser->m_vMaterials[mesh.iMaterialIndex].avSubMaterials;
  915|       |
  916|      0|        std::vector<unsigned int> *aiSplit = new std::vector<unsigned int>[vSubMaterials.size()];
  917|       |
  918|       |        // build a list of all faces per sub-material
  919|      0|        for (unsigned int i = 0; i < mesh.mFaces.size(); ++i) {
  ------------------
  |  Branch (919:34): [True: 0, False: 0]
  ------------------
  920|       |            // check range
  921|      0|            if (mesh.mFaces[i].iMaterial >= vSubMaterials.size()) {
  ------------------
  |  Branch (921:17): [True: 0, False: 0]
  ------------------
  922|      0|                ASSIMP_LOG_WARN("Submaterial index is out of range");
  923|       |
  924|       |                // use the last material instead
  925|      0|                aiSplit[vSubMaterials.size() - 1].push_back(i);
  926|      0|            } else
  927|      0|                aiSplit[mesh.mFaces[i].iMaterial].push_back(i);
  928|      0|        }
  929|       |
  930|       |        // now generate submeshes
  931|      0|        for (unsigned int p = 0; p < vSubMaterials.size(); ++p) {
  ------------------
  |  Branch (931:34): [True: 0, False: 0]
  ------------------
  932|      0|            if (!aiSplit[p].empty()) {
  ------------------
  |  Branch (932:17): [True: 0, False: 0]
  ------------------
  933|       |
  934|      0|                aiMesh *p_pcOut = new aiMesh();
  935|      0|                p_pcOut->mPrimitiveTypes = aiPrimitiveType_TRIANGLE;
  936|       |
  937|       |                // let the sub material index
  938|      0|                p_pcOut->mMaterialIndex = p;
  939|       |
  940|       |                // we will need this material
  941|      0|                mParser->m_vMaterials[mesh.iMaterialIndex].avSubMaterials[p].bNeed = true;
  942|       |
  943|       |                // store the real index here ... color channel 3
  944|      0|                p_pcOut->mColors[3] = (aiColor4D *)(uintptr_t)mesh.iMaterialIndex;
  945|       |
  946|       |                // store a pointer to the mesh in color channel 2
  947|      0|                p_pcOut->mColors[2] = (aiColor4D *)&mesh;
  948|      0|                avOutMeshes.push_back(p_pcOut);
  949|       |
  950|       |                // convert vertices
  951|      0|                p_pcOut->mNumVertices = (unsigned int)aiSplit[p].size() * 3;
  952|      0|                p_pcOut->mNumFaces = (unsigned int)aiSplit[p].size();
  953|       |
  954|       |                // receive output vertex weights
  955|      0|                std::vector<std::pair<unsigned int, float>> *avOutputBones = nullptr;
  956|      0|                if (!mesh.mBones.empty()) {
  ------------------
  |  Branch (956:21): [True: 0, False: 0]
  ------------------
  957|      0|                    avOutputBones = new std::vector<std::pair<unsigned int, float>>[mesh.mBones.size()];
  958|      0|                }
  959|       |
  960|       |                // allocate enough storage for faces
  961|      0|                p_pcOut->mFaces = new aiFace[p_pcOut->mNumFaces];
  962|       |
  963|      0|                unsigned int iBase = 0, iIndex;
  964|      0|                if (p_pcOut->mNumVertices) {
  ------------------
  |  Branch (964:21): [True: 0, False: 0]
  ------------------
  965|      0|                    p_pcOut->mVertices = new aiVector3D[p_pcOut->mNumVertices];
  966|      0|                    p_pcOut->mNormals = new aiVector3D[p_pcOut->mNumVertices];
  967|      0|                    for (unsigned int q = 0; q < aiSplit[p].size(); ++q) {
  ------------------
  |  Branch (967:46): [True: 0, False: 0]
  ------------------
  968|       |
  969|      0|                        iIndex = aiSplit[p][q];
  970|       |
  971|      0|                        p_pcOut->mFaces[q].mIndices = new unsigned int[3];
  972|      0|                        p_pcOut->mFaces[q].mNumIndices = 3;
  973|       |
  974|      0|                        for (unsigned int t = 0; t < 3; ++t, ++iBase) {
  ------------------
  |  Branch (974:50): [True: 0, False: 0]
  ------------------
  975|      0|                            const uint32_t iIndex2 = mesh.mFaces[iIndex].mIndices[t];
  976|       |
  977|      0|                            p_pcOut->mVertices[iBase] = mesh.mPositions[iIndex2];
  978|      0|                            p_pcOut->mNormals[iBase] = mesh.mNormals[iIndex2];
  979|       |
  980|       |                            // convert bones, if existing
  981|      0|                            if (!mesh.mBones.empty()) {
  ------------------
  |  Branch (981:33): [True: 0, False: 0]
  ------------------
  982|      0|                                ai_assert(avOutputBones);
  983|       |                                // check whether there is a vertex weight for this vertex index
  984|      0|                                if (iIndex2 < mesh.mBoneVertices.size()) {
  ------------------
  |  Branch (984:37): [True: 0, False: 0]
  ------------------
  985|       |
  986|      0|                                    for (std::vector<std::pair<int, float>>::const_iterator
  987|      0|                                                    blubb = mesh.mBoneVertices[iIndex2].mBoneWeights.begin();
  988|      0|                                            blubb != mesh.mBoneVertices[iIndex2].mBoneWeights.end(); ++blubb) {
  ------------------
  |  Branch (988:45): [True: 0, False: 0]
  ------------------
  989|       |
  990|       |                                        // NOTE: illegal cases have already been filtered out
  991|      0|                                        avOutputBones[(*blubb).first].emplace_back(
  992|      0|                                                iBase, (*blubb).second);
  993|      0|                                    }
  994|      0|                                }
  995|      0|                            }
  996|      0|                            p_pcOut->mFaces[q].mIndices[t] = iBase;
  997|      0|                        }
  998|      0|                    }
  999|      0|                }
 1000|       |                // convert texture coordinates (up to AI_MAX_NUMBER_OF_TEXTURECOORDS sets supported)
 1001|      0|                for (unsigned int c = 0; c < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++c) {
  ------------------
  |  Branch (1001:42): [True: 0, False: 0]
  ------------------
 1002|      0|                    if (!mesh.amTexCoords[c].empty()) {
  ------------------
  |  Branch (1002:25): [True: 0, False: 0]
  ------------------
 1003|      0|                        p_pcOut->mTextureCoords[c] = new aiVector3D[p_pcOut->mNumVertices];
 1004|      0|                        iBase = 0;
 1005|      0|                        for (unsigned int q = 0; q < aiSplit[p].size(); ++q) {
  ------------------
  |  Branch (1005:50): [True: 0, False: 0]
  ------------------
 1006|      0|                            iIndex = aiSplit[p][q];
 1007|      0|                            for (unsigned int t = 0; t < 3; ++t) {
  ------------------
  |  Branch (1007:54): [True: 0, False: 0]
  ------------------
 1008|      0|                                p_pcOut->mTextureCoords[c][iBase++] = mesh.amTexCoords[c][mesh.mFaces[iIndex].mIndices[t]];
 1009|      0|                            }
 1010|      0|                        }
 1011|       |                        // Setup the number of valid vertex components
 1012|      0|                        p_pcOut->mNumUVComponents[c] = mesh.mNumUVComponents[c];
 1013|      0|                    }
 1014|      0|                }
 1015|       |
 1016|       |                // Convert vertex colors (only one set supported)
 1017|      0|                if (!mesh.mVertexColors.empty()) {
  ------------------
  |  Branch (1017:21): [True: 0, False: 0]
  ------------------
 1018|      0|                    p_pcOut->mColors[0] = new aiColor4D[p_pcOut->mNumVertices];
 1019|      0|                    iBase = 0;
 1020|      0|                    for (unsigned int q = 0; q < aiSplit[p].size(); ++q) {
  ------------------
  |  Branch (1020:46): [True: 0, False: 0]
  ------------------
 1021|      0|                        iIndex = aiSplit[p][q];
 1022|      0|                        for (unsigned int t = 0; t < 3; ++t) {
  ------------------
  |  Branch (1022:50): [True: 0, False: 0]
  ------------------
 1023|      0|                            p_pcOut->mColors[0][iBase++] = mesh.mVertexColors[mesh.mFaces[iIndex].mIndices[t]];
 1024|      0|                        }
 1025|      0|                    }
 1026|      0|                }
 1027|       |                // Copy bones
 1028|      0|                if (!mesh.mBones.empty()) {
  ------------------
  |  Branch (1028:21): [True: 0, False: 0]
  ------------------
 1029|      0|                    p_pcOut->mNumBones = 0;
 1030|      0|                    for (unsigned int mrspock = 0; mrspock < mesh.mBones.size(); ++mrspock)
  ------------------
  |  Branch (1030:52): [True: 0, False: 0]
  ------------------
 1031|      0|                        if (!avOutputBones[mrspock].empty()) p_pcOut->mNumBones++;
  ------------------
  |  Branch (1031:29): [True: 0, False: 0]
  ------------------
 1032|       |
 1033|      0|                    p_pcOut->mBones = new aiBone *[p_pcOut->mNumBones];
 1034|      0|                    aiBone **pcBone = p_pcOut->mBones;
 1035|      0|                    for (unsigned int mrspock = 0; mrspock < mesh.mBones.size(); ++mrspock) {
  ------------------
  |  Branch (1035:52): [True: 0, False: 0]
  ------------------
 1036|      0|                        if (!avOutputBones[mrspock].empty()) {
  ------------------
  |  Branch (1036:29): [True: 0, False: 0]
  ------------------
 1037|       |                            // we will need this bone. add it to the output mesh and
 1038|       |                            // add all per-vertex weights
 1039|      0|                            aiBone *pc = *pcBone = new aiBone();
 1040|      0|                            pc->mName.Set(mesh.mBones[mrspock].mName);
 1041|       |
 1042|      0|                            pc->mNumWeights = (unsigned int)avOutputBones[mrspock].size();
 1043|      0|                            pc->mWeights = new aiVertexWeight[pc->mNumWeights];
 1044|       |
 1045|      0|                            for (unsigned int captainkirk = 0; captainkirk < pc->mNumWeights; ++captainkirk) {
  ------------------
  |  Branch (1045:64): [True: 0, False: 0]
  ------------------
 1046|      0|                                const std::pair<unsigned int, float> &ref = avOutputBones[mrspock][captainkirk];
 1047|      0|                                pc->mWeights[captainkirk].mVertexId = ref.first;
 1048|      0|                                pc->mWeights[captainkirk].mWeight = ref.second;
 1049|      0|                            }
 1050|      0|                            ++pcBone;
 1051|      0|                        }
 1052|      0|                    }
 1053|       |                    // delete allocated storage
 1054|      0|                    delete[] avOutputBones;
 1055|      0|                }
 1056|      0|            }
 1057|      0|        }
 1058|       |        // delete storage
 1059|      0|        delete[] aiSplit;
 1060|     22|    } else {
 1061|       |        // Otherwise we can simply copy the data to one output mesh
 1062|       |        // This codepath needs less memory and uses fast memcpy()s
 1063|       |        // to do the actual copying. So I think it is worth the
 1064|       |        // effort here.
 1065|       |
 1066|     22|        aiMesh *p_pcOut = new aiMesh();
 1067|     22|        p_pcOut->mPrimitiveTypes = aiPrimitiveType_TRIANGLE;
 1068|       |
 1069|       |        // set an empty sub material index
 1070|     22|        p_pcOut->mMaterialIndex = ASE::Face::DEFAULT_MATINDEX;
 1071|     22|        mParser->m_vMaterials[mesh.iMaterialIndex].bNeed = true;
 1072|       |
 1073|       |        // store the real index here ... in color channel 3
 1074|     22|        p_pcOut->mColors[3] = (aiColor4D *)(uintptr_t)mesh.iMaterialIndex;
 1075|       |
 1076|       |        // store a pointer to the mesh in color channel 2
 1077|     22|        p_pcOut->mColors[2] = (aiColor4D *)&mesh;
 1078|     22|        avOutMeshes.push_back(p_pcOut);
 1079|       |
 1080|       |        // If the mesh hasn't faces or vertices, there are two cases
 1081|       |        // possible: 1. the model is invalid. 2. This is a dummy
 1082|       |        // helper object which we are going to remove later ...
 1083|     22|        if (mesh.mFaces.empty() || mesh.mPositions.empty()) {
  ------------------
  |  Branch (1083:13): [True: 6, False: 16]
  |  Branch (1083:36): [True: 0, False: 16]
  ------------------
 1084|      6|            return;
 1085|      6|        }
 1086|       |
 1087|       |        // convert vertices
 1088|     16|        p_pcOut->mNumVertices = (unsigned int)mesh.mPositions.size();
 1089|     16|        p_pcOut->mNumFaces = (unsigned int)mesh.mFaces.size();
 1090|       |
 1091|       |        // allocate enough storage for faces
 1092|     16|        p_pcOut->mFaces = new aiFace[p_pcOut->mNumFaces];
 1093|       |
 1094|       |        // copy vertices
 1095|     16|        p_pcOut->mVertices = new aiVector3D[mesh.mPositions.size()];
 1096|     16|        memcpy(p_pcOut->mVertices, &mesh.mPositions[0],
 1097|     16|                mesh.mPositions.size() * sizeof(aiVector3D));
 1098|       |
 1099|       |        // copy normals
 1100|     16|        p_pcOut->mNormals = new aiVector3D[mesh.mNormals.size()];
 1101|     16|        memcpy(p_pcOut->mNormals, &mesh.mNormals[0],
 1102|     16|                mesh.mNormals.size() * sizeof(aiVector3D));
 1103|       |
 1104|       |        // copy texture coordinates
 1105|    144|        for (unsigned int c = 0; c < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++c) {
  ------------------
  |  Branch (1105:34): [True: 128, False: 16]
  ------------------
 1106|    128|            if (!mesh.amTexCoords[c].empty()) {
  ------------------
  |  Branch (1106:17): [True: 11, False: 117]
  ------------------
 1107|     11|                p_pcOut->mTextureCoords[c] = new aiVector3D[mesh.amTexCoords[c].size()];
 1108|     11|                memcpy(p_pcOut->mTextureCoords[c], &mesh.amTexCoords[c][0],
 1109|     11|                        mesh.amTexCoords[c].size() * sizeof(aiVector3D));
 1110|       |
 1111|       |                // setup the number of valid vertex components
 1112|     11|                p_pcOut->mNumUVComponents[c] = mesh.mNumUVComponents[c];
 1113|     11|            }
 1114|    128|        }
 1115|       |
 1116|       |        // copy vertex colors
 1117|     16|        if (!mesh.mVertexColors.empty()) {
  ------------------
  |  Branch (1117:13): [True: 0, False: 16]
  ------------------
 1118|      0|            p_pcOut->mColors[0] = new aiColor4D[mesh.mVertexColors.size()];
 1119|      0|            memcpy(p_pcOut->mColors[0], &mesh.mVertexColors[0],
 1120|      0|                    mesh.mVertexColors.size() * sizeof(aiColor4D));
 1121|      0|        }
 1122|       |
 1123|       |        // copy faces
 1124|    248|        for (unsigned int iFace = 0; iFace < p_pcOut->mNumFaces; ++iFace) {
  ------------------
  |  Branch (1124:38): [True: 232, False: 16]
  ------------------
 1125|    232|            p_pcOut->mFaces[iFace].mNumIndices = 3;
 1126|    232|            p_pcOut->mFaces[iFace].mIndices = new unsigned int[3];
 1127|       |
 1128|       |            // copy indices
 1129|    232|            p_pcOut->mFaces[iFace].mIndices[0] = mesh.mFaces[iFace].mIndices[0];
 1130|    232|            p_pcOut->mFaces[iFace].mIndices[1] = mesh.mFaces[iFace].mIndices[1];
 1131|    232|            p_pcOut->mFaces[iFace].mIndices[2] = mesh.mFaces[iFace].mIndices[2];
 1132|    232|        }
 1133|       |
 1134|       |        // copy vertex bones
 1135|     16|        if (!mesh.mBones.empty() && !mesh.mBoneVertices.empty()) {
  ------------------
  |  Branch (1135:13): [True: 0, False: 16]
  |  Branch (1135:37): [True: 0, False: 0]
  ------------------
 1136|      0|            std::vector<std::vector<aiVertexWeight>> avBonesOut(mesh.mBones.size());
 1137|       |
 1138|       |            // find all vertex weights for this bone
 1139|      0|            unsigned int quak = 0;
 1140|      0|            for (std::vector<BoneVertex>::const_iterator harrypotter = mesh.mBoneVertices.begin();
 1141|      0|                    harrypotter != mesh.mBoneVertices.end(); ++harrypotter, ++quak) {
  ------------------
  |  Branch (1141:21): [True: 0, False: 0]
  ------------------
 1142|       |
 1143|      0|                for (std::vector<std::pair<int, float>>::const_iterator
 1144|      0|                                ronaldweasley = (*harrypotter).mBoneWeights.begin();
 1145|      0|                        ronaldweasley != (*harrypotter).mBoneWeights.end(); ++ronaldweasley) {
  ------------------
  |  Branch (1145:25): [True: 0, False: 0]
  ------------------
 1146|      0|                    aiVertexWeight weight;
 1147|      0|                    weight.mVertexId = quak;
 1148|      0|                    weight.mWeight = (*ronaldweasley).second;
 1149|      0|                    avBonesOut[(*ronaldweasley).first].push_back(weight);
 1150|      0|                }
 1151|      0|            }
 1152|       |
 1153|       |            // now build a final bone list
 1154|      0|            p_pcOut->mNumBones = 0;
 1155|      0|            for (unsigned int jfkennedy = 0; jfkennedy < mesh.mBones.size(); ++jfkennedy)
  ------------------
  |  Branch (1155:46): [True: 0, False: 0]
  ------------------
 1156|      0|                if (!avBonesOut[jfkennedy].empty()) p_pcOut->mNumBones++;
  ------------------
  |  Branch (1156:21): [True: 0, False: 0]
  ------------------
 1157|       |
 1158|      0|            p_pcOut->mBones = new aiBone *[p_pcOut->mNumBones];
 1159|      0|            aiBone **pcBone = p_pcOut->mBones;
 1160|      0|            for (unsigned int jfkennedy = 0; jfkennedy < mesh.mBones.size(); ++jfkennedy) {
  ------------------
  |  Branch (1160:46): [True: 0, False: 0]
  ------------------
 1161|      0|                if (!avBonesOut[jfkennedy].empty()) {
  ------------------
  |  Branch (1161:21): [True: 0, False: 0]
  ------------------
 1162|      0|                    aiBone *pc = *pcBone = new aiBone();
 1163|      0|                    pc->mName.Set(mesh.mBones[jfkennedy].mName);
 1164|      0|                    pc->mNumWeights = (unsigned int)avBonesOut[jfkennedy].size();
 1165|      0|                    pc->mWeights = new aiVertexWeight[pc->mNumWeights];
 1166|      0|                    ::memcpy(pc->mWeights, &avBonesOut[jfkennedy][0],
 1167|      0|                            sizeof(aiVertexWeight) * pc->mNumWeights);
 1168|      0|                    ++pcBone;
 1169|      0|                }
 1170|      0|            }
 1171|      0|        }
 1172|     16|    }
 1173|     22|}
_ZN6Assimp11ASEImporter20BuildMaterialIndicesEv:
 1177|     15|void ASEImporter::BuildMaterialIndices() {
 1178|     15|    ai_assert(nullptr != pcScene);
 1179|       |
 1180|       |    // iterate through all materials and check whether we need them
 1181|     34|    for (unsigned int iMat = 0; iMat < mParser->m_vMaterials.size(); ++iMat) {
  ------------------
  |  Branch (1181:33): [True: 19, False: 15]
  ------------------
 1182|     19|        ASE::Material &mat = mParser->m_vMaterials[iMat];
 1183|     19|        if (mat.bNeed) {
  ------------------
  |  Branch (1183:13): [True: 19, False: 0]
  ------------------
 1184|       |            // Convert it to the aiMaterial layout
 1185|     19|            ConvertMaterial(mat);
 1186|     19|            ++pcScene->mNumMaterials;
 1187|     19|        }
 1188|     19|        for (unsigned int iSubMat = 0; iSubMat < mat.avSubMaterials.size(); ++iSubMat) {
  ------------------
  |  Branch (1188:40): [True: 0, False: 19]
  ------------------
 1189|      0|            ASE::Material &submat = mat.avSubMaterials[iSubMat];
 1190|      0|            if (submat.bNeed) {
  ------------------
  |  Branch (1190:17): [True: 0, False: 0]
  ------------------
 1191|       |                // Convert it to the aiMaterial layout
 1192|      0|                ConvertMaterial(submat);
 1193|      0|                ++pcScene->mNumMaterials;
 1194|      0|            }
 1195|      0|        }
 1196|     19|    }
 1197|       |
 1198|       |    // allocate the output material array
 1199|     15|    pcScene->mMaterials = new aiMaterial *[pcScene->mNumMaterials];
 1200|     15|    D3DS::Material **pcIntMaterials = new D3DS::Material *[pcScene->mNumMaterials];
 1201|       |
 1202|     15|    unsigned int iNum = 0;
 1203|     34|    for (unsigned int iMat = 0; iMat < mParser->m_vMaterials.size(); ++iMat) {
  ------------------
  |  Branch (1203:33): [True: 19, False: 15]
  ------------------
 1204|     19|        ASE::Material &mat = mParser->m_vMaterials[iMat];
 1205|     19|        if (mat.bNeed) {
  ------------------
  |  Branch (1205:13): [True: 19, False: 0]
  ------------------
 1206|     19|            ai_assert(nullptr != mat.pcInstance);
 1207|     19|            pcScene->mMaterials[iNum] = mat.pcInstance;
 1208|       |
 1209|       |            // Store the internal material, too
 1210|     19|            pcIntMaterials[iNum] = &mat;
 1211|       |
 1212|       |            // Iterate through all meshes and search for one which is using
 1213|       |            // this top-level material index
 1214|     55|            for (unsigned int iMesh = 0; iMesh < pcScene->mNumMeshes; ++iMesh) {
  ------------------
  |  Branch (1214:42): [True: 36, False: 19]
  ------------------
 1215|     36|                aiMesh *mesh = pcScene->mMeshes[iMesh];
 1216|     36|                if (ASE::Face::DEFAULT_MATINDEX == mesh->mMaterialIndex &&
  ------------------
  |  Branch (1216:21): [True: 26, False: 10]
  ------------------
 1217|     26|                        iMat == (uintptr_t)mesh->mColors[3]) {
  ------------------
  |  Branch (1217:25): [True: 16, False: 10]
  ------------------
 1218|     16|                    mesh->mMaterialIndex = iNum;
 1219|     16|                    mesh->mColors[3] = nullptr;
 1220|     16|                }
 1221|     36|            }
 1222|     19|            iNum++;
 1223|     19|        }
 1224|     19|        for (unsigned int iSubMat = 0; iSubMat < mat.avSubMaterials.size(); ++iSubMat) {
  ------------------
  |  Branch (1224:40): [True: 0, False: 19]
  ------------------
 1225|      0|            ASE::Material &submat = mat.avSubMaterials[iSubMat];
 1226|      0|            if (submat.bNeed) {
  ------------------
  |  Branch (1226:17): [True: 0, False: 0]
  ------------------
 1227|      0|                ai_assert(nullptr != submat.pcInstance);
 1228|      0|                pcScene->mMaterials[iNum] = submat.pcInstance;
 1229|       |
 1230|       |                // Store the internal material, too
 1231|      0|                pcIntMaterials[iNum] = &submat;
 1232|       |
 1233|       |                // Iterate through all meshes and search for one which is using
 1234|       |                // this sub-level material index
 1235|      0|                for (unsigned int iMesh = 0; iMesh < pcScene->mNumMeshes; ++iMesh) {
  ------------------
  |  Branch (1235:46): [True: 0, False: 0]
  ------------------
 1236|      0|                    aiMesh *mesh = pcScene->mMeshes[iMesh];
 1237|       |
 1238|      0|                    if (iSubMat == mesh->mMaterialIndex && iMat == (uintptr_t)mesh->mColors[3]) {
  ------------------
  |  Branch (1238:25): [True: 0, False: 0]
  |  Branch (1238:60): [True: 0, False: 0]
  ------------------
 1239|      0|                        mesh->mMaterialIndex = iNum;
 1240|      0|                        mesh->mColors[3] = nullptr;
 1241|      0|                    }
 1242|      0|                }
 1243|      0|                iNum++;
 1244|      0|            }
 1245|      0|        }
 1246|     19|    }
 1247|       |
 1248|       |    // Delete our temporary array
 1249|     15|    delete[] pcIntMaterials;
 1250|     15|}
_ZN6Assimp11ASEImporter15GenerateNormalsERNS_3ASE4MeshE:
 1254|     22|bool ASEImporter::GenerateNormals(ASE::Mesh &mesh) {
 1255|       |
 1256|     22|    if (!mesh.mNormals.empty() && !configRecomputeNormals) {
  ------------------
  |  Branch (1256:9): [True: 11, False: 11]
  |  Branch (1256:35): [True: 0, False: 11]
  ------------------
 1257|       |        // Check whether there are only uninitialized normals. If there are
 1258|       |        // some, skip all normals from the file and compute them on our own
 1259|      0|        for (std::vector<aiVector3D>::const_iterator qq = mesh.mNormals.begin(); qq != mesh.mNormals.end(); ++qq) {
  ------------------
  |  Branch (1259:82): [True: 0, False: 0]
  ------------------
 1260|      0|            if ((*qq).x || (*qq).y || (*qq).z) {
  ------------------
  |  Branch (1260:17): [True: 0, False: 0]
  |  Branch (1260:28): [True: 0, False: 0]
  |  Branch (1260:39): [True: 0, False: 0]
  ------------------
 1261|      0|                return true;
 1262|      0|            }
 1263|      0|        }
 1264|      0|    }
 1265|       |    // The array is reused.
 1266|     22|    ComputeNormalsWithSmoothingsGroups<ASE::Face>(mesh);
 1267|     22|    return false;
 1268|     22|}

_ZN6Assimp3ASE6ParserC2EPKcmj:
  115|     43|        mFilePtr(nullptr), mEnd (nullptr) {
  116|     43|    ai_assert(file != nullptr);
  117|       |
  118|     43|    mFilePtr = file;
  119|     43|    mEnd = mFilePtr + fileLen;
  120|     43|    iFileFormat = fileFormatDefault;
  121|       |
  122|       |    // make sure that the color values are invalid
  123|     43|    m_clrBackground.r = get_qnan();
  124|     43|    m_clrAmbient.r = get_qnan();
  125|       |
  126|       |    // setup some default values
  127|     43|    iLineNumber = 0;
  128|     43|    iFirstFrame = 0;
  129|     43|    iLastFrame = 0;
  130|     43|    iFrameSpeed = 30; // use 30 as default value for this property
  131|     43|    iTicksPerFrame = 1; // use 1 as default value for this property
  132|     43|    bLastWasEndLine = false; // need to handle \r\n seqs due to binary file mapping
  133|     43|}
_ZN6Assimp3ASE6Parser10LogWarningEPKc:
  136|  7.77k|void Parser::LogWarning(const char *szWarn) {
  137|  7.77k|    ai_assert(nullptr != szWarn);
  138|       |
  139|  7.77k|    char szTemp[2048];
  140|       |#if _MSC_VER >= 1400
  141|       |    sprintf_s(szTemp, "Line %u: %s", iLineNumber, szWarn);
  142|       |#else
  143|  7.77k|    ai_snprintf(szTemp, sizeof(szTemp), "Line %u: %s", iLineNumber, szWarn);
  144|  7.77k|#endif
  145|       |
  146|       |    // output the warning to the logger ...
  147|       |    ASSIMP_LOG_WARN(szTemp);
  148|  7.77k|}
_ZN6Assimp3ASE6Parser7LogInfoEPKc:
  151|     26|void Parser::LogInfo(const char *szWarn) {
  152|     26|    ai_assert(nullptr != szWarn);
  153|       |
  154|     26|    char szTemp[1024];
  155|       |#if _MSC_VER >= 1400
  156|       |    sprintf_s(szTemp, "Line %u: %s", iLineNumber, szWarn);
  157|       |#else
  158|     26|    ai_snprintf(szTemp, 1024, "Line %u: %s", iLineNumber, szWarn);
  159|     26|#endif
  160|       |
  161|       |    // output the information to the logger ...
  162|       |    ASSIMP_LOG_INFO(szTemp);
  163|     26|}
_ZN6Assimp3ASE6Parser8LogErrorEPKc:
  166|     20|AI_WONT_RETURN void Parser::LogError(const char *szWarn) {
  167|     20|    ai_assert(nullptr != szWarn);
  168|       |
  169|     20|    char szTemp[1024];
  170|       |#if _MSC_VER >= 1400
  171|       |    sprintf_s(szTemp, "Line %u: %s", iLineNumber, szWarn);
  172|       |#else
  173|     20|    ai_snprintf(szTemp, 1024, "Line %u: %s", iLineNumber, szWarn);
  174|     20|#endif
  175|       |
  176|       |    // throw an exception
  177|     20|    throw DeadlyImportError(szTemp);
  178|     20|}
_ZN6Assimp3ASE6Parser15SkipToNextTokenEv:
  181|    940|bool Parser::SkipToNextToken() {
  182|  21.4k|    while (true) {
  ------------------
  |  Branch (182:12): [True: 21.4k, Folded]
  ------------------
  183|  21.4k|        char me = *mFilePtr;
  184|       |
  185|  21.4k|        if (mFilePtr == mEnd) {
  ------------------
  |  Branch (185:13): [True: 0, False: 21.4k]
  ------------------
  186|      0|            return false;
  187|      0|        }
  188|       |
  189|       |        // increase the line number counter if necessary
  190|  21.4k|        if (IsLineEnd(me) && !bLastWasEndLine) {
  ------------------
  |  Branch (190:13): [True: 2.45k, False: 18.9k]
  |  Branch (190:30): [True: 1.66k, False: 789]
  ------------------
  191|  1.66k|            ++iLineNumber;
  192|  1.66k|            bLastWasEndLine = true;
  193|  1.66k|        } else
  194|  19.7k|            bLastWasEndLine = false;
  195|  21.4k|        if ('*' == me || '}' == me || '{' == me) {
  ------------------
  |  Branch (195:13): [True: 643, False: 20.8k]
  |  Branch (195:26): [True: 251, False: 20.5k]
  |  Branch (195:39): [True: 30, False: 20.5k]
  ------------------
  196|    924|            return true;
  197|    924|        }
  198|  20.5k|        if ('\0' == me) {
  ------------------
  |  Branch (198:13): [True: 16, False: 20.5k]
  ------------------
  199|     16|            return false;
  200|     16|        }
  201|       |
  202|  20.5k|        ++mFilePtr;
  203|  20.5k|    }
  204|    940|}
_ZN6Assimp3ASE6Parser11SkipSectionEv:
  207|      5|bool Parser::SkipSection() {
  208|       |    // must handle subsections ...
  209|      5|    int iCnt = 0;
  210|  7.92k|    while (true) {
  ------------------
  |  Branch (210:12): [True: 7.92k, Folded]
  ------------------
  211|  7.92k|        if ('}' == *mFilePtr) {
  ------------------
  |  Branch (211:13): [True: 5, False: 7.91k]
  ------------------
  212|      5|            --iCnt;
  213|      5|            if (0 == iCnt) {
  ------------------
  |  Branch (213:17): [True: 5, False: 0]
  ------------------
  214|       |                // go to the next valid token ...
  215|      5|                ++mFilePtr;
  216|      5|                SkipToNextToken();
  217|      5|                return true;
  218|      5|            }
  219|  7.91k|        } else if ('{' == *mFilePtr) {
  ------------------
  |  Branch (219:20): [True: 5, False: 7.91k]
  ------------------
  220|      5|            ++iCnt;
  221|  7.91k|        } else if ('\0' == *mFilePtr) {
  ------------------
  |  Branch (221:20): [True: 0, False: 7.91k]
  ------------------
  222|      0|            LogWarning("Unable to parse block: Unexpected EOF, closing bracket \'}\' was expected [#1]");
  223|      0|            return false;
  224|  7.91k|        } else if (IsLineEnd(*mFilePtr))
  ------------------
  |  Branch (224:20): [True: 160, False: 7.75k]
  ------------------
  225|    160|            ++iLineNumber;
  226|  7.91k|        ++mFilePtr;
  227|  7.91k|    }
  228|      5|}
_ZN6Assimp3ASE6Parser5ParseEv:
  231|     43|void Parser::Parse() {
  232|     43|    AI_ASE_PARSER_INIT();
  ------------------
  |  |   63|     43|    int iDepth = 0;
  ------------------
  233|  6.07k|    while (true) {
  ------------------
  |  Branch (233:12): [True: 6.04k, Folded]
  ------------------
  234|  6.04k|        if ('*' == *mFilePtr) {
  ------------------
  |  Branch (234:13): [True: 434, False: 5.61k]
  ------------------
  235|    434|            ++mFilePtr;
  236|       |
  237|       |            // Version should be 200. Validate this ...
  238|    434|            if (TokenMatch(mFilePtr, "3DSMAX_ASCIIEXPORT", 18)) {
  ------------------
  |  Branch (238:17): [True: 34, False: 400]
  ------------------
  239|     34|                unsigned int fmt;
  240|     34|                ParseLV4MeshLong(fmt);
  241|       |
  242|     34|                if (fmt > 200) {
  ------------------
  |  Branch (242:21): [True: 0, False: 34]
  ------------------
  243|      0|                    LogWarning("Unknown file format version: *3DSMAX_ASCIIEXPORT should \
  244|      0|                               be <= 200");
  245|      0|                }
  246|       |                // *************************************************************
  247|       |                // - fmt will be 0 if we're unable to read the version number
  248|       |                // there are some faulty files without a version number ...
  249|       |                // in this case we'll guess the exact file format by looking
  250|       |                // at the file extension (ASE, ASK, ASC)
  251|       |                // *************************************************************
  252|       |
  253|     34|                if (fmt) {
  ------------------
  |  Branch (253:21): [True: 27, False: 7]
  ------------------
  254|     27|                    iFileFormat = fmt;
  255|     27|                }
  256|     34|                continue;
  257|     34|            }
  258|       |            // main scene information
  259|    400|            if (TokenMatch(mFilePtr, "SCENE", 5)) {
  ------------------
  |  Branch (259:17): [True: 20, False: 380]
  ------------------
  260|     20|                ParseLV1SceneBlock();
  261|     20|                continue;
  262|     20|            }
  263|       |            // "group" - no implementation yet, in facte
  264|       |            // we're just ignoring them for the moment
  265|    380|            if (TokenMatch(mFilePtr, "GROUP", 5)) {
  ------------------
  |  Branch (265:17): [True: 0, False: 380]
  ------------------
  266|      0|                Parse();
  267|      0|                continue;
  268|      0|            }
  269|       |            // material list
  270|    380|            if (TokenMatch(mFilePtr, "MATERIAL_LIST", 13)) {
  ------------------
  |  Branch (270:17): [True: 31, False: 349]
  ------------------
  271|     31|                ParseLV1MaterialListBlock();
  272|     31|                continue;
  273|     31|            }
  274|       |            // geometric object (mesh)
  275|    349|            if (TokenMatch(mFilePtr, "GEOMOBJECT", 10))
  ------------------
  |  Branch (275:17): [True: 41, False: 308]
  ------------------
  276|       |
  277|     41|            {
  278|     41|                m_vMeshes.emplace_back("UNNAMED");
  279|     41|                ParseLV1ObjectBlock(m_vMeshes.back());
  280|     41|                continue;
  281|     41|            }
  282|       |            // helper object = dummy in the hierarchy
  283|    308|            if (TokenMatch(mFilePtr, "HELPEROBJECT", 12))
  ------------------
  |  Branch (283:17): [True: 0, False: 308]
  ------------------
  284|       |
  285|      0|            {
  286|      0|                m_vDummies.emplace_back();
  287|      0|                ParseLV1ObjectBlock(m_vDummies.back());
  288|      0|                continue;
  289|      0|            }
  290|       |            // light object
  291|    308|            if (TokenMatch(mFilePtr, "LIGHTOBJECT", 11))
  ------------------
  |  Branch (291:17): [True: 5, False: 303]
  ------------------
  292|       |
  293|      5|            {
  294|      5|                m_vLights.emplace_back("UNNAMED");
  295|      5|                ParseLV1ObjectBlock(m_vLights.back());
  296|      5|                continue;
  297|      5|            }
  298|       |            // camera object
  299|    303|            if (TokenMatch(mFilePtr, "CAMERAOBJECT", 12)) {
  ------------------
  |  Branch (299:17): [True: 8, False: 295]
  ------------------
  300|      8|                m_vCameras.emplace_back("UNNAMED");
  301|      8|                ParseLV1ObjectBlock(m_vCameras.back());
  302|      8|                continue;
  303|      8|            }
  304|       |            // comment - print it on the console
  305|    295|            if (TokenMatch(mFilePtr, "COMMENT", 7)) {
  ------------------
  |  Branch (305:17): [True: 26, False: 269]
  ------------------
  306|     26|                std::string out = "<unknown>";
  307|     26|                ParseString(out, "*COMMENT");
  308|     26|                LogInfo(("Comment: " + out).c_str());
  309|     26|                continue;
  310|     26|            }
  311|       |            // ASC bone weights
  312|    269|            if (AI_ASE_IS_OLD_FILE_FORMAT() && TokenMatch(mFilePtr, "MESH_SOFTSKINVERTS", 18)) {
  ------------------
  |  |  380|    538|#define AI_ASE_IS_OLD_FILE_FORMAT() (iFileFormat < 200)
  |  |  ------------------
  |  |  |  Branch (380:37): [True: 1, False: 268]
  |  |  ------------------
  ------------------
  |  Branch (312:48): [True: 1, False: 0]
  ------------------
  313|      1|                ParseLV1SoftSkinBlock();
  314|      1|            }
  315|    269|        }
  316|  11.7k|        AI_ASE_HANDLE_TOP_LEVEL_SECTION();
  ------------------
  |  |   69|  6.04k|    else if ('{' == *mFilePtr)                     \
  |  |  ------------------
  |  |  |  Branch (69:14): [True: 11, False: 5.60k]
  |  |  ------------------
  |  |   70|  5.61k|        ++iDepth;                                  \
  |  |   71|  5.61k|    else if ('}' == *mFilePtr) {                   \
  |  |  ------------------
  |  |  |  Branch (71:14): [True: 25, False: 5.57k]
  |  |  ------------------
  |  |   72|     25|        if (0 == --iDepth) {                       \
  |  |  ------------------
  |  |  |  Branch (72:13): [True: 0, False: 25]
  |  |  ------------------
  |  |   73|      0|            ++mFilePtr;                            \
  |  |   74|      0|            SkipToNextToken();                     \
  |  |   75|      0|            return;                                \
  |  |   76|      0|        }                                          \
  |  |   77|     25|    }                                              \
  |  |   78|  6.04k|    if ('\0' == *mFilePtr) {                       \
  |  |  ------------------
  |  |  |  Branch (78:9): [True: 19, False: 5.86k]
  |  |  ------------------
  |  |   79|     19|        return;                                    \
  |  |   80|     19|    }                                              \
  |  |   81|  5.88k|    if (IsLineEnd(*mFilePtr) && !bLastWasEndLine) {\
  |  |  ------------------
  |  |  |  Branch (81:9): [True: 675, False: 5.19k]
  |  |  |  Branch (81:33): [True: 459, False: 216]
  |  |  ------------------
  |  |   82|    459|        ++iLineNumber;                             \
  |  |   83|    459|        bLastWasEndLine = true;                    \
  |  |   84|    459|    } else                                         \
  |  |   85|  5.86k|        bLastWasEndLine = false;                   \
  |  |   86|  5.86k|    ++mFilePtr;
  ------------------
  317|  11.7k|    }
  318|     43|}
_ZN6Assimp3ASE6Parser21ParseLV1SoftSkinBlockEv:
  321|      1|void Parser::ParseLV1SoftSkinBlock() {
  322|       |    // TODO: fix line counting here
  323|       |
  324|       |    // **************************************************************
  325|       |    // The soft skin block is formatted differently. There are no
  326|       |    // nested sections supported and the single elements aren't
  327|       |    // marked by keywords starting with an asterisk.
  328|       |
  329|       |    /**
  330|       |    FORMAT BEGIN
  331|       |
  332|       |    *MESH_SOFTSKINVERTS {
  333|       |    <nodename>
  334|       |    <number of vertices>
  335|       |
  336|       |    [for <number of vertices> times:]
  337|       |        <number of weights> [for <number of weights> times:] <bone name> <weight>
  338|       |    }
  339|       |
  340|       |    FORMAT END
  341|       |    */
  342|       |    // **************************************************************
  343|    922|    while (true) {
  ------------------
  |  Branch (343:12): [True: 922, Folded]
  ------------------
  344|    922|        if (*mFilePtr == '}') {
  ------------------
  |  Branch (344:13): [True: 0, False: 922]
  ------------------
  345|      0|            ++mFilePtr;
  346|      0|            return;
  347|    922|        } else if (*mFilePtr == '\0')
  ------------------
  |  Branch (347:20): [True: 0, False: 922]
  ------------------
  348|      0|            return;
  349|    922|        else if (*mFilePtr == '{')
  ------------------
  |  Branch (349:18): [True: 0, False: 922]
  ------------------
  350|      0|            ++mFilePtr;
  351|       |
  352|    922|        else // if (!IsSpace(*filePtr) && !IsLineEnd(*filePtr))
  353|    922|        {
  354|    922|            ASE::Mesh *curMesh = nullptr;
  355|    922|            unsigned int numVerts = 0;
  356|       |
  357|    922|            const char *sz = mFilePtr;
  358|  10.7k|            while (!IsSpaceOrNewLine(*mFilePtr)) {
  ------------------
  |  Branch (358:20): [True: 9.85k, False: 922]
  ------------------
  359|  9.85k|                ++mFilePtr;
  360|  9.85k|            }
  361|       |
  362|    922|            const unsigned int diff = (unsigned int)(mFilePtr - sz);
  363|    922|            if (diff) {
  ------------------
  |  Branch (363:17): [True: 910, False: 12]
  ------------------
  364|    910|                std::string name = std::string(sz, diff);
  365|    910|                for (std::vector<ASE::Mesh>::iterator it = m_vMeshes.begin();
  366|    910|                        it != m_vMeshes.end(); ++it) {
  ------------------
  |  Branch (366:25): [True: 0, False: 910]
  ------------------
  367|      0|                    if ((*it).mName == name) {
  ------------------
  |  Branch (367:25): [True: 0, False: 0]
  ------------------
  368|      0|                        curMesh = &(*it);
  369|      0|                        break;
  370|      0|                    }
  371|      0|                }
  372|    910|                if (!curMesh) {
  ------------------
  |  Branch (372:21): [True: 910, False: 0]
  ------------------
  373|    910|                    LogWarning("Encountered unknown mesh in *MESH_SOFTSKINVERTS section");
  374|       |
  375|       |                    // Skip the mesh data - until we find a new mesh
  376|       |                    // or the end of the *MESH_SOFTSKINVERTS section
  377|  1.04k|                    while (true) {
  ------------------
  |  Branch (377:28): [True: 1.04k, Folded]
  ------------------
  378|  1.04k|                        SkipSpacesAndLineEnd(&mFilePtr, mEnd);
  379|  1.04k|                        if (*mFilePtr == '}') {
  ------------------
  |  Branch (379:29): [True: 0, False: 1.04k]
  ------------------
  380|      0|                            ++mFilePtr;
  381|      0|                            return;
  382|  1.04k|                        } else if (!IsNumeric(*mFilePtr))
  ------------------
  |  Branch (382:36): [True: 910, False: 139]
  ------------------
  383|    910|                            break;
  384|       |
  385|    139|                        SkipLine(&mFilePtr, mEnd);
  386|    139|                    }
  387|    910|                } else {
  388|      0|                    SkipSpacesAndLineEnd(&mFilePtr, mEnd);
  389|      0|                    ParseLV4MeshLong(numVerts);
  390|       |
  391|       |                    // Reserve enough storage
  392|      0|                    curMesh->mBoneVertices.reserve(numVerts);
  393|       |
  394|      0|                    for (unsigned int i = 0; i < numVerts; ++i) {
  ------------------
  |  Branch (394:46): [True: 0, False: 0]
  ------------------
  395|      0|                        SkipSpacesAndLineEnd(&mFilePtr, mEnd);
  396|      0|                        unsigned int numWeights;
  397|      0|                        ParseLV4MeshLong(numWeights);
  398|       |
  399|      0|                        curMesh->mBoneVertices.emplace_back();
  400|      0|                        ASE::BoneVertex &vert = curMesh->mBoneVertices.back();
  401|       |
  402|       |                        // Reserve enough storage
  403|      0|                        vert.mBoneWeights.reserve(numWeights);
  404|       |
  405|      0|                        std::string bone;
  406|      0|                        for (unsigned int w = 0; w < numWeights; ++w) {
  ------------------
  |  Branch (406:50): [True: 0, False: 0]
  ------------------
  407|      0|                            bone.clear();
  408|      0|                            ParseString(bone, "*MESH_SOFTSKINVERTS.Bone");
  409|       |
  410|       |                            // Find the bone in the mesh's list
  411|      0|                            std::pair<int, ai_real> me;
  412|      0|                            me.first = -1;
  413|       |
  414|      0|                            for (unsigned int n = 0; n < curMesh->mBones.size(); ++n) {
  ------------------
  |  Branch (414:54): [True: 0, False: 0]
  ------------------
  415|      0|                                if (curMesh->mBones[n].mName == bone) {
  ------------------
  |  Branch (415:37): [True: 0, False: 0]
  ------------------
  416|      0|                                    me.first = n;
  417|      0|                                    break;
  418|      0|                                }
  419|      0|                            }
  420|      0|                            if (-1 == me.first) {
  ------------------
  |  Branch (420:33): [True: 0, False: 0]
  ------------------
  421|       |                                // We don't have this bone yet, so add it to the list
  422|      0|                                me.first = static_cast<int>(curMesh->mBones.size());
  423|      0|                                curMesh->mBones.emplace_back(bone);
  424|      0|                            }
  425|      0|                            ParseLV4MeshReal(me.second);
  426|       |
  427|       |                            // Add the new bone weight to list
  428|      0|                            vert.mBoneWeights.push_back(me);
  429|      0|                        }
  430|      0|                    }
  431|      0|                }
  432|    910|            }
  433|    922|        }
  434|    922|        if (*mFilePtr == '\0')
  ------------------
  |  Branch (434:13): [True: 1, False: 921]
  ------------------
  435|      1|            return;
  436|    921|        ++mFilePtr;
  437|    921|        SkipSpacesAndLineEnd(&mFilePtr, mEnd);
  438|    921|    }
  439|      1|}
_ZN6Assimp3ASE6Parser18ParseLV1SceneBlockEv:
  442|     20|void Parser::ParseLV1SceneBlock() {
  443|     20|    AI_ASE_PARSER_INIT();
  ------------------
  |  |   63|     20|    int iDepth = 0;
  ------------------
  444|  1.11k|    while (true) {
  ------------------
  |  Branch (444:12): [True: 1.11k, Folded]
  ------------------
  445|  1.11k|        if ('*' == *mFilePtr) {
  ------------------
  |  Branch (445:13): [True: 138, False: 980]
  ------------------
  446|    138|            ++mFilePtr;
  447|    138|            if (TokenMatch(mFilePtr, "SCENE_BACKGROUND_STATIC", 23))
  ------------------
  |  Branch (447:17): [True: 18, False: 120]
  ------------------
  448|       |
  449|     18|            {
  450|       |                // parse a color triple and assume it is really the bg color
  451|     18|                ParseLV4MeshFloatTriple(&m_clrBackground.r);
  452|     18|                continue;
  453|     18|            }
  454|    120|            if (TokenMatch(mFilePtr, "SCENE_AMBIENT_STATIC", 20))
  ------------------
  |  Branch (454:17): [True: 20, False: 100]
  ------------------
  455|       |
  456|     20|            {
  457|       |                // parse a color triple and assume it is really the bg color
  458|     20|                ParseLV4MeshFloatTriple(&m_clrAmbient.r);
  459|     20|                continue;
  460|     20|            }
  461|    100|            if (TokenMatch(mFilePtr, "SCENE_FIRSTFRAME", 16)) {
  ------------------
  |  Branch (461:17): [True: 20, False: 80]
  ------------------
  462|     20|                ParseLV4MeshLong(iFirstFrame);
  463|     20|                continue;
  464|     20|            }
  465|     80|            if (TokenMatch(mFilePtr, "SCENE_LASTFRAME", 15)) {
  ------------------
  |  Branch (465:17): [True: 20, False: 60]
  ------------------
  466|     20|                ParseLV4MeshLong(iLastFrame);
  467|     20|                continue;
  468|     20|            }
  469|     60|            if (TokenMatch(mFilePtr, "SCENE_FRAMESPEED", 16)) {
  ------------------
  |  Branch (469:17): [True: 20, False: 40]
  ------------------
  470|     20|                ParseLV4MeshLong(iFrameSpeed);
  471|     20|                continue;
  472|     20|            }
  473|     40|            if (TokenMatch(mFilePtr, "SCENE_TICKSPERFRAME", 19)) {
  ------------------
  |  Branch (473:17): [True: 18, False: 22]
  ------------------
  474|     18|                ParseLV4MeshLong(iTicksPerFrame);
  475|     18|                continue;
  476|     18|            }
  477|     40|        }
  478|  1.96k|        AI_ASE_HANDLE_TOP_LEVEL_SECTION();
  ------------------
  |  |   69|  1.11k|    else if ('{' == *mFilePtr)                     \
  |  |  ------------------
  |  |  |  Branch (69:14): [True: 20, False: 960]
  |  |  ------------------
  |  |   70|    980|        ++iDepth;                                  \
  |  |   71|    980|    else if ('}' == *mFilePtr) {                   \
  |  |  ------------------
  |  |  |  Branch (71:14): [True: 20, False: 940]
  |  |  ------------------
  |  |   72|     20|        if (0 == --iDepth) {                       \
  |  |  ------------------
  |  |  |  Branch (72:13): [True: 20, False: 0]
  |  |  ------------------
  |  |   73|     20|            ++mFilePtr;                            \
  |  |   74|     20|            SkipToNextToken();                     \
  |  |   75|     20|            return;                                \
  |  |   76|     20|        }                                          \
  |  |   77|     20|    }                                              \
  |  |   78|  1.11k|    if ('\0' == *mFilePtr) {                       \
  |  |  ------------------
  |  |  |  Branch (78:9): [True: 0, False: 982]
  |  |  ------------------
  |  |   79|      0|        return;                                    \
  |  |   80|      0|    }                                              \
  |  |   81|    982|    if (IsLineEnd(*mFilePtr) && !bLastWasEndLine) {\
  |  |  ------------------
  |  |  |  Branch (81:9): [True: 158, False: 824]
  |  |  |  Branch (81:33): [True: 158, False: 0]
  |  |  ------------------
  |  |   82|    158|        ++iLineNumber;                             \
  |  |   83|    158|        bLastWasEndLine = true;                    \
  |  |   84|    158|    } else                                         \
  |  |   85|    982|        bLastWasEndLine = false;                   \
  |  |   86|    982|    ++mFilePtr;
  ------------------
  479|  1.96k|    }
  480|     20|}
_ZN6Assimp3ASE6Parser25ParseLV1MaterialListBlockEv:
  483|     31|void Parser::ParseLV1MaterialListBlock() {
  484|     31|    AI_ASE_PARSER_INIT();
  ------------------
  |  |   63|     31|    int iDepth = 0;
  ------------------
  485|       |
  486|     31|    unsigned int iMaterialCount = 0;
  487|     31|    unsigned int iOldMaterialCount = (unsigned int)m_vMaterials.size();
  488|  25.0k|    while (true) {
  ------------------
  |  Branch (488:12): [True: 25.0k, Folded]
  ------------------
  489|  25.0k|        if ('*' == *mFilePtr) {
  ------------------
  |  Branch (489:13): [True: 40, False: 25.0k]
  ------------------
  490|     40|            ++mFilePtr;
  491|     40|            if (TokenMatch(mFilePtr, "MATERIAL_COUNT", 14)) {
  ------------------
  |  Branch (491:17): [True: 27, False: 13]
  ------------------
  492|     27|                ParseLV4MeshLong(iMaterialCount);
  493|       |
  494|     27|                if (UINT_MAX - iOldMaterialCount < iMaterialCount) {
  ------------------
  |  Branch (494:21): [True: 0, False: 27]
  ------------------
  495|      0|                    LogWarning("Out of range: material index is too large");
  496|      0|                    return;
  497|      0|                }
  498|       |
  499|       |                // now allocate enough storage to hold all materials
  500|     27|                m_vMaterials.resize(iOldMaterialCount + iMaterialCount, Material("INVALID"));
  501|     27|                continue;
  502|     27|            }
  503|     13|            if (TokenMatch(mFilePtr, "MATERIAL", 8)) {
  ------------------
  |  Branch (503:17): [True: 12, False: 1]
  ------------------
  504|       |                // ensure we have at least one material allocated
  505|     12|                if (iMaterialCount == 0) {
  ------------------
  |  Branch (505:21): [True: 4, False: 8]
  ------------------
  506|      4|                    LogWarning("*MATERIAL_COUNT unspecified or 0");
  507|      4|                    iMaterialCount = 1;
  508|      4|                    m_vMaterials.resize(iOldMaterialCount + iMaterialCount, Material("INVALID"));
  509|      4|                }
  510|       |
  511|     12|                unsigned int iIndex = 0;
  512|     12|                ParseLV4MeshLong(iIndex);
  513|       |
  514|     12|                if (iIndex >= iMaterialCount) {
  ------------------
  |  Branch (514:21): [True: 0, False: 12]
  ------------------
  515|      0|                    LogWarning("Out of range: material index is too large");
  516|      0|                    iIndex = iMaterialCount - 1;
  517|      0|                }
  518|       |
  519|       |                // get a reference to the material
  520|     12|                Material &sMat = m_vMaterials[iIndex + iOldMaterialCount];
  521|       |                // parse the material block
  522|     12|                ParseLV2MaterialBlock(sMat);
  523|     12|                continue;
  524|     12|            }
  525|      1|            if( iDepth == 1 ){
  ------------------
  |  Branch (525:17): [True: 1, False: 0]
  ------------------
  526|       |                // CRUDE HACK: support missing brace after "Ascii Scene Exporter v2.51"
  527|      1|                LogWarning("Missing closing brace in material list");
  528|      1|                --mFilePtr;
  529|      1|                return;
  530|      1|            }
  531|      1|        }
  532|  49.9k|        AI_ASE_HANDLE_TOP_LEVEL_SECTION();
  ------------------
  |  |   69|  25.0k|    else if ('{' == *mFilePtr)                     \
  |  |  ------------------
  |  |  |  Branch (69:14): [True: 884, False: 24.1k]
  |  |  ------------------
  |  |   70|  25.0k|        ++iDepth;                                  \
  |  |   71|  25.0k|    else if ('}' == *mFilePtr) {                   \
  |  |  ------------------
  |  |  |  Branch (71:14): [True: 26, False: 24.1k]
  |  |  ------------------
  |  |   72|     26|        if (0 == --iDepth) {                       \
  |  |  ------------------
  |  |  |  Branch (72:13): [True: 26, False: 0]
  |  |  ------------------
  |  |   73|     26|            ++mFilePtr;                            \
  |  |   74|     26|            SkipToNextToken();                     \
  |  |   75|     26|            return;                                \
  |  |   76|     26|        }                                          \
  |  |   77|     26|    }                                              \
  |  |   78|  25.0k|    if ('\0' == *mFilePtr) {                       \
  |  |  ------------------
  |  |  |  Branch (78:9): [True: 0, False: 24.9k]
  |  |  ------------------
  |  |   79|      0|        return;                                    \
  |  |   80|      0|    }                                              \
  |  |   81|  24.9k|    if (IsLineEnd(*mFilePtr) && !bLastWasEndLine) {\
  |  |  ------------------
  |  |  |  Branch (81:9): [True: 434, False: 24.5k]
  |  |  |  Branch (81:33): [True: 417, False: 17]
  |  |  ------------------
  |  |   82|    417|        ++iLineNumber;                             \
  |  |   83|    417|        bLastWasEndLine = true;                    \
  |  |   84|    417|    } else                                         \
  |  |   85|  24.9k|        bLastWasEndLine = false;                   \
  |  |   86|  24.9k|    ++mFilePtr;
  ------------------
  533|  49.9k|    }
  534|     31|}
_ZN6Assimp3ASE6Parser21ParseLV2MaterialBlockERNS0_8MaterialE:
  537|     12|void Parser::ParseLV2MaterialBlock(ASE::Material &mat) {
  538|     12|    AI_ASE_PARSER_INIT();
  ------------------
  |  |   63|     12|    int iDepth = 0;
  ------------------
  539|       |
  540|     12|    unsigned int iNumSubMaterials = 0;
  541|  4.20k|    while (true) {
  ------------------
  |  Branch (541:12): [True: 4.20k, Folded]
  ------------------
  542|  4.20k|        if ('*' == *mFilePtr) {
  ------------------
  |  Branch (542:13): [True: 148, False: 4.05k]
  ------------------
  543|    148|            ++mFilePtr;
  544|    148|            if (TokenMatch(mFilePtr, "MATERIAL_NAME", 13)) {
  ------------------
  |  Branch (544:17): [True: 8, False: 140]
  ------------------
  545|      8|                if (!ParseString(mat.mName, "*MATERIAL_NAME"))
  ------------------
  |  Branch (545:21): [True: 0, False: 8]
  ------------------
  546|      0|                    SkipToNextToken();
  547|      8|                continue;
  548|      8|            }
  549|       |            // ambient material color
  550|    140|            if (TokenMatch(mFilePtr, "MATERIAL_AMBIENT", 16)) {
  ------------------
  |  Branch (550:17): [True: 8, False: 132]
  ------------------
  551|      8|                ParseLV4MeshFloatTriple(&mat.mAmbient.r);
  552|      8|                continue;
  553|      8|            }
  554|       |            // diffuse material color
  555|    132|            if (TokenMatch(mFilePtr, "MATERIAL_DIFFUSE", 16)) {
  ------------------
  |  Branch (555:17): [True: 8, False: 124]
  ------------------
  556|      8|                ParseLV4MeshFloatTriple(&mat.mDiffuse.r);
  557|      8|                continue;
  558|      8|            }
  559|       |            // specular material color
  560|    124|            if (TokenMatch(mFilePtr, "MATERIAL_SPECULAR", 17)) {
  ------------------
  |  Branch (560:17): [True: 8, False: 116]
  ------------------
  561|      8|                ParseLV4MeshFloatTriple(&mat.mSpecular.r);
  562|      8|                continue;
  563|      8|            }
  564|       |            // material shading type
  565|    116|            if (TokenMatch(mFilePtr, "MATERIAL_SHADING", 16)) {
  ------------------
  |  Branch (565:17): [True: 8, False: 108]
  ------------------
  566|      8|                if (TokenMatch(mFilePtr, "Blinn", 5)) {
  ------------------
  |  Branch (566:21): [True: 8, False: 0]
  ------------------
  567|      8|                    mat.mShading = Discreet3DS::Blinn;
  568|      8|                } else if (TokenMatch(mFilePtr, "Phong", 5)) {
  ------------------
  |  Branch (568:28): [True: 0, False: 0]
  ------------------
  569|      0|                    mat.mShading = Discreet3DS::Phong;
  570|      0|                } else if (TokenMatch(mFilePtr, "Flat", 4)) {
  ------------------
  |  Branch (570:28): [True: 0, False: 0]
  ------------------
  571|      0|                    mat.mShading = Discreet3DS::Flat;
  572|      0|                } else if (TokenMatch(mFilePtr, "Wire", 4)) {
  ------------------
  |  Branch (572:28): [True: 0, False: 0]
  ------------------
  573|      0|                    mat.mShading = Discreet3DS::Wire;
  574|      0|                } else {
  575|       |                    // assume gouraud shading
  576|      0|                    mat.mShading = Discreet3DS::Gouraud;
  577|      0|                    SkipToNextToken();
  578|      0|                }
  579|      8|                continue;
  580|      8|            }
  581|       |            // material transparency
  582|    108|            if (TokenMatch(mFilePtr, "MATERIAL_TRANSPARENCY", 21)) {
  ------------------
  |  Branch (582:17): [True: 8, False: 100]
  ------------------
  583|      8|                ParseLV4MeshReal(mat.mTransparency);
  584|      8|                mat.mTransparency = ai_real(1.0) - mat.mTransparency;
  585|      8|                continue;
  586|      8|            }
  587|       |            // material self illumination
  588|    100|            if (TokenMatch(mFilePtr, "MATERIAL_SELFILLUM", 18)) {
  ------------------
  |  Branch (588:17): [True: 8, False: 92]
  ------------------
  589|      8|                ai_real f = 0.0;
  590|      8|                ParseLV4MeshReal(f);
  591|       |
  592|      8|                mat.mEmissive.r = f;
  593|      8|                mat.mEmissive.g = f;
  594|      8|                mat.mEmissive.b = f;
  595|      8|                continue;
  596|      8|            }
  597|       |            // material shininess
  598|     92|            if (TokenMatch(mFilePtr, "MATERIAL_SHINE", 14)) {
  ------------------
  |  Branch (598:17): [True: 8, False: 84]
  ------------------
  599|      8|                ParseLV4MeshReal(mat.mSpecularExponent);
  600|      8|                mat.mSpecularExponent *= 15;
  601|      8|                continue;
  602|      8|            }
  603|       |            // two-sided material
  604|     84|            if (TokenMatch(mFilePtr, "MATERIAL_TWOSIDED", 17)) {
  ------------------
  |  Branch (604:17): [True: 0, False: 84]
  ------------------
  605|      0|                mat.mTwoSided = true;
  606|      0|                continue;
  607|      0|            }
  608|       |            // material shininess strength
  609|     84|            if (TokenMatch(mFilePtr, "MATERIAL_SHINESTRENGTH", 22)) {
  ------------------
  |  Branch (609:17): [True: 8, False: 76]
  ------------------
  610|      8|                ParseLV4MeshReal(mat.mShininessStrength);
  611|      8|                continue;
  612|      8|            }
  613|       |            // diffuse color map
  614|     76|            if (TokenMatch(mFilePtr, "MAP_DIFFUSE", 11)) {
  ------------------
  |  Branch (614:17): [True: 4, False: 72]
  ------------------
  615|       |                // parse the texture block
  616|      4|                ParseLV3MapBlock(mat.sTexDiffuse);
  617|      4|                continue;
  618|      4|            }
  619|       |            // ambient color map
  620|     72|            if (TokenMatch(mFilePtr, "MAP_AMBIENT", 11)) {
  ------------------
  |  Branch (620:17): [True: 0, False: 72]
  ------------------
  621|       |                // parse the texture block
  622|      0|                ParseLV3MapBlock(mat.sTexAmbient);
  623|      0|                continue;
  624|      0|            }
  625|       |            // specular color map
  626|     72|            if (TokenMatch(mFilePtr, "MAP_SPECULAR", 12)) {
  ------------------
  |  Branch (626:17): [True: 0, False: 72]
  ------------------
  627|       |                // parse the texture block
  628|      0|                ParseLV3MapBlock(mat.sTexSpecular);
  629|      0|                continue;
  630|      0|            }
  631|       |            // opacity map
  632|     72|            if (TokenMatch(mFilePtr, "MAP_OPACITY", 11)) {
  ------------------
  |  Branch (632:17): [True: 0, False: 72]
  ------------------
  633|       |                // parse the texture block
  634|      0|                ParseLV3MapBlock(mat.sTexOpacity);
  635|      0|                continue;
  636|      0|            }
  637|       |            // emissive map
  638|     72|            if (TokenMatch(mFilePtr, "MAP_SELFILLUM", 13)) {
  ------------------
  |  Branch (638:17): [True: 0, False: 72]
  ------------------
  639|       |                // parse the texture block
  640|      0|                ParseLV3MapBlock(mat.sTexEmissive);
  641|      0|                continue;
  642|      0|            }
  643|       |            // bump map
  644|     72|            if (TokenMatch(mFilePtr, "MAP_BUMP", 8)) {
  ------------------
  |  Branch (644:17): [True: 0, False: 72]
  ------------------
  645|       |                // parse the texture block
  646|      0|                ParseLV3MapBlock(mat.sTexBump);
  647|      0|            }
  648|       |            // specular/shininess map
  649|     72|            if (TokenMatch(mFilePtr, "MAP_SHINESTRENGTH", 17)) {
  ------------------
  |  Branch (649:17): [True: 5, False: 67]
  ------------------
  650|       |                // parse the texture block
  651|      5|                ParseLV3MapBlock(mat.sTexShininess);
  652|      5|                continue;
  653|      5|            }
  654|       |            // number of submaterials
  655|     67|            if (TokenMatch(mFilePtr, "NUMSUBMTLS", 10)) {
  ------------------
  |  Branch (655:17): [True: 6, False: 61]
  ------------------
  656|      6|                ParseLV4MeshLong(iNumSubMaterials);
  657|       |
  658|       |                // allocate enough storage
  659|      6|                mat.avSubMaterials.resize(iNumSubMaterials, Material("INVALID SUBMATERIAL"));
  660|      6|            }
  661|       |            // submaterial chunks
  662|     67|            if (TokenMatch(mFilePtr, "SUBMATERIAL", 11)) {
  ------------------
  |  Branch (662:17): [True: 0, False: 67]
  ------------------
  663|       |                // ensure we have at least one material allocated
  664|      0|                if (iNumSubMaterials == 0) {
  ------------------
  |  Branch (664:21): [True: 0, False: 0]
  ------------------
  665|      0|                    LogWarning("*NUMSUBMTLS unspecified or 0");
  666|      0|                    iNumSubMaterials = 1;
  667|      0|                    mat.avSubMaterials.resize(iNumSubMaterials, Material("INVALID SUBMATERIAL"));
  668|      0|                }
  669|       |
  670|      0|                unsigned int iIndex = 0;
  671|      0|                ParseLV4MeshLong(iIndex);
  672|       |
  673|      0|                if (iIndex >= iNumSubMaterials) {
  ------------------
  |  Branch (673:21): [True: 0, False: 0]
  ------------------
  674|      0|                    LogWarning("Out of range: submaterial index is too large");
  675|      0|                    iIndex = iNumSubMaterials - 1;
  676|      0|                }
  677|       |
  678|       |                // get a reference to the material
  679|      0|                if (iIndex < mat.avSubMaterials.size()) {
  ------------------
  |  Branch (679:21): [True: 0, False: 0]
  ------------------
  680|      0|                    Material &sMat = mat.avSubMaterials[iIndex];
  681|       |
  682|       |                    // parse the material block
  683|      0|                    ParseLV2MaterialBlock(sMat);
  684|      0|                }
  685|       |
  686|      0|                continue;
  687|      0|            }
  688|     67|        }
  689|  8.23k|        AI_ASE_HANDLE_SECTION("2", "*MATERIAL");
  ------------------
  |  |   94|  4.11k|    if ('{' == *mFilePtr)                                          \
  |  |  ------------------
  |  |  |  Branch (94:9): [True: 17, False: 4.10k]
  |  |  ------------------
  |  |   95|  4.11k|        iDepth++;                                                  \
  |  |   96|  4.11k|    else if ('}' == *mFilePtr) {                                   \
  |  |  ------------------
  |  |  |  Branch (96:14): [True: 13, False: 4.08k]
  |  |  ------------------
  |  |   97|     13|        if (0 == --iDepth) {                                       \
  |  |  ------------------
  |  |  |  Branch (97:13): [True: 8, False: 5]
  |  |  ------------------
  |  |   98|      8|            ++mFilePtr;                                            \
  |  |   99|      8|            SkipToNextToken();                                     \
  |  |  100|      8|            return;                                                \
  |  |  101|      8|        }                                                          \
  |  |  102|  4.08k|    } else if ('\0' == *mFilePtr) {                                \
  |  |  ------------------
  |  |  |  Branch (102:16): [True: 1, False: 4.08k]
  |  |  ------------------
  |  |  103|      1|        LogError("Encountered unexpected EOL while parsing a " msg \
  |  |  104|      1|                 " chunk (Level " level ")");                      \
  |  |  105|      1|    }                                                              \
  |  |  106|  4.11k|    if (IsLineEnd(*mFilePtr) && !bLastWasEndLine) {                \
  |  |  ------------------
  |  |  |  Branch (106:9): [True: 433, False: 3.67k]
  |  |  |  Branch (106:33): [True: 321, False: 112]
  |  |  ------------------
  |  |  107|    321|        ++iLineNumber;                                             \
  |  |  108|    321|        bLastWasEndLine = true;                                    \
  |  |  109|    321|    } else                                                         \
  |  |  110|  4.11k|        bLastWasEndLine = false;                                   \
  |  |  111|  4.11k|    ++mFilePtr;
  ------------------
  690|  8.23k|    }
  691|     12|}
_ZN6Assimp3ASE6Parser16ParseLV3MapBlockERNS_4D3DS7TextureE:
  694|      9|void Parser::ParseLV3MapBlock(Texture &map) {
  695|      9|    AI_ASE_PARSER_INIT();
  ------------------
  |  |   63|      9|    int iDepth = 0;
  ------------------
  696|       |
  697|       |    // ***********************************************************
  698|       |    // *BITMAP should not be there if *MAP_CLASS is not BITMAP,
  699|       |    // but we need to expect that case ... if the path is
  700|       |    // empty the texture won't be used later.
  701|       |    // ***********************************************************
  702|      9|    bool parsePath = true;
  703|      9|    std::string temp;
  704|  29.1k|    while (true) {
  ------------------
  |  Branch (704:12): [True: 29.1k, Folded]
  ------------------
  705|  29.1k|        if ('*' == *mFilePtr) {
  ------------------
  |  Branch (705:13): [True: 503, False: 28.6k]
  ------------------
  706|    503|            ++mFilePtr;
  707|       |            // type of map
  708|    503|            if (TokenMatch(mFilePtr, "MAP_CLASS", 9)) {
  ------------------
  |  Branch (708:17): [True: 23, False: 480]
  ------------------
  709|     23|                temp.clear();
  710|     23|                if (!ParseString(temp, "*MAP_CLASS"))
  ------------------
  |  Branch (710:21): [True: 18, False: 5]
  ------------------
  711|     18|                    SkipToNextToken();
  712|     23|                if (temp != "Bitmap" && temp != "Normal Bump") {
  ------------------
  |  Branch (712:21): [True: 18, False: 5]
  |  Branch (712:41): [True: 18, False: 0]
  ------------------
  713|     18|                    ASSIMP_LOG_WARN("ASE: Skipping unknown map type: ", temp);
  714|     18|                    parsePath = false;
  715|     18|                }
  716|     23|                continue;
  717|     23|            }
  718|       |            // path to the texture
  719|    480|            if (parsePath && TokenMatch(mFilePtr, "BITMAP", 6)) {
  ------------------
  |  Branch (719:17): [True: 194, False: 286]
  |  Branch (719:30): [True: 20, False: 174]
  ------------------
  720|     20|                if (!ParseString(map.mMapName, "*BITMAP"))
  ------------------
  |  Branch (720:21): [True: 1, False: 19]
  ------------------
  721|      1|                    SkipToNextToken();
  722|       |
  723|     20|                if (map.mMapName == "None") {
  ------------------
  |  Branch (723:21): [True: 0, False: 20]
  ------------------
  724|       |                    // Files with 'None' as map name are produced by
  725|       |                    // an Maja to ASE exporter which name I forgot ..
  726|      0|                    ASSIMP_LOG_WARN("ASE: Skipping invalid map entry");
  727|      0|                    map.mMapName = std::string();
  728|      0|                }
  729|       |
  730|     20|                continue;
  731|     20|            }
  732|       |            // offset on the u axis
  733|    460|            if (TokenMatch(mFilePtr, "UVW_U_OFFSET", 12)) {
  ------------------
  |  Branch (733:17): [True: 5, False: 455]
  ------------------
  734|      5|                ParseLV4MeshReal(map.mOffsetU);
  735|      5|                continue;
  736|      5|            }
  737|       |            // offset on the v axis
  738|    455|            if (TokenMatch(mFilePtr, "UVW_V_OFFSET", 12)) {
  ------------------
  |  Branch (738:17): [True: 5, False: 450]
  ------------------
  739|      5|                ParseLV4MeshReal(map.mOffsetV);
  740|      5|                continue;
  741|      5|            }
  742|       |            // tiling on the u axis
  743|    450|            if (TokenMatch(mFilePtr, "UVW_U_TILING", 12)) {
  ------------------
  |  Branch (743:17): [True: 5, False: 445]
  ------------------
  744|      5|                ParseLV4MeshReal(map.mScaleU);
  745|      5|                continue;
  746|      5|            }
  747|       |            // tiling on the v axis
  748|    445|            if (TokenMatch(mFilePtr, "UVW_V_TILING", 12)) {
  ------------------
  |  Branch (748:17): [True: 5, False: 440]
  ------------------
  749|      5|                ParseLV4MeshReal(map.mScaleV);
  750|      5|                continue;
  751|      5|            }
  752|       |            // rotation around the z-axis
  753|    440|            if (TokenMatch(mFilePtr, "UVW_ANGLE", 9)) {
  ------------------
  |  Branch (753:17): [True: 7, False: 433]
  ------------------
  754|      7|                ParseLV4MeshReal(map.mRotation);
  755|      7|                continue;
  756|      7|            }
  757|       |            // map blending factor
  758|    433|            if (TokenMatch(mFilePtr, "MAP_AMOUNT", 10)) {
  ------------------
  |  Branch (758:17): [True: 5, False: 428]
  ------------------
  759|      5|                ParseLV4MeshReal(map.mTextureBlend);
  760|      5|                continue;
  761|      5|            }
  762|    433|        }
  763|  58.0k|        AI_ASE_HANDLE_SECTION("3", "*MAP_XXXXXX");
  ------------------
  |  |   94|  29.0k|    if ('{' == *mFilePtr)                                          \
  |  |  ------------------
  |  |  |  Branch (94:9): [True: 152, False: 28.9k]
  |  |  ------------------
  |  |   95|  29.0k|        iDepth++;                                                  \
  |  |   96|  29.0k|    else if ('}' == *mFilePtr) {                                   \
  |  |  ------------------
  |  |  |  Branch (96:14): [True: 59, False: 28.8k]
  |  |  ------------------
  |  |   97|     59|        if (0 == --iDepth) {                                       \
  |  |  ------------------
  |  |  |  Branch (97:13): [True: 6, False: 53]
  |  |  ------------------
  |  |   98|      6|            ++mFilePtr;                                            \
  |  |   99|      6|            SkipToNextToken();                                     \
  |  |  100|      6|            return;                                                \
  |  |  101|      6|        }                                                          \
  |  |  102|  28.8k|    } else if ('\0' == *mFilePtr) {                                \
  |  |  ------------------
  |  |  |  Branch (102:16): [True: 3, False: 28.8k]
  |  |  ------------------
  |  |  103|      3|        LogError("Encountered unexpected EOL while parsing a " msg \
  |  |  104|      3|                 " chunk (Level " level ")");                      \
  |  |  105|      3|    }                                                              \
  |  |  106|  29.0k|    if (IsLineEnd(*mFilePtr) && !bLastWasEndLine) {                \
  |  |  ------------------
  |  |  |  Branch (106:9): [True: 1.96k, False: 27.0k]
  |  |  |  Branch (106:33): [True: 1.66k, False: 306]
  |  |  ------------------
  |  |  107|  1.66k|        ++iLineNumber;                                             \
  |  |  108|  1.66k|        bLastWasEndLine = true;                                    \
  |  |  109|  1.66k|    } else                                                         \
  |  |  110|  29.0k|        bLastWasEndLine = false;                                   \
  |  |  111|  29.0k|    ++mFilePtr;
  ------------------
  764|  58.0k|    }
  765|      9|}
_ZN6Assimp3ASE6Parser11ParseStringERNSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEEPKc:
  768|    217|bool Parser::ParseString(std::string &out, const char *szName) {
  769|    217|    char szBuffer[1024];
  770|    217|    if (!SkipSpaces(&mFilePtr, mEnd)) {
  ------------------
  |  Branch (770:9): [True: 0, False: 217]
  ------------------
  771|       |
  772|      0|        ai_snprintf(szBuffer, 1024, "Unable to parse %s block: Unexpected EOL", szName);
  773|      0|        LogWarning(szBuffer);
  774|      0|        return false;
  775|      0|    }
  776|       |    // there must be '"'
  777|    217|    if ('\"' != *mFilePtr) {
  ------------------
  |  Branch (777:9): [True: 20, False: 197]
  ------------------
  778|       |
  779|     20|        ai_snprintf(szBuffer, 1024, "Unable to parse %s block: Strings are expected "
  780|     20|                                    "to be enclosed in double quotation marks",
  781|     20|                szName);
  782|     20|        LogWarning(szBuffer);
  783|     20|        return false;
  784|     20|    }
  785|    197|    ++mFilePtr;
  786|    197|    const char *sz = mFilePtr;
  787|  8.94k|    while (true) {
  ------------------
  |  Branch (787:12): [True: 8.94k, Folded]
  ------------------
  788|  8.94k|        if ('\"' == *sz)
  ------------------
  |  Branch (788:13): [True: 197, False: 8.74k]
  ------------------
  789|    197|            break;
  790|  8.74k|        else if ('\0' == *sz) {
  ------------------
  |  Branch (790:18): [True: 0, False: 8.74k]
  ------------------
  791|      0|            ai_snprintf(szBuffer, 1024, "Unable to parse %s block: Strings are expected to "
  792|      0|                                        "be enclosed in double quotation marks but EOF was reached before "
  793|      0|                                        "a closing quotation mark was encountered",
  794|      0|                    szName);
  795|      0|            LogWarning(szBuffer);
  796|      0|            return false;
  797|      0|        }
  798|  8.74k|        sz++;
  799|  8.74k|    }
  800|    197|    out = std::string(mFilePtr, (uintptr_t)sz - (uintptr_t)mFilePtr);
  801|    197|    mFilePtr = sz + 1;
  802|    197|    return true;
  803|    197|}
_ZN6Assimp3ASE6Parser19ParseLV1ObjectBlockERNS0_8BaseNodeE:
  806|     54|void Parser::ParseLV1ObjectBlock(ASE::BaseNode &node) {
  807|     54|    AI_ASE_PARSER_INIT();
  ------------------
  |  |   63|     54|    int iDepth = 0;
  ------------------
  808|  20.1k|    while (true) {
  ------------------
  |  Branch (808:12): [True: 20.0k, Folded]
  ------------------
  809|  20.0k|        if ('*' == *mFilePtr) {
  ------------------
  |  Branch (809:13): [True: 729, False: 19.3k]
  ------------------
  810|    729|            ++mFilePtr;
  811|       |
  812|       |            // first process common tokens such as node name and transform
  813|       |            // name of the mesh/node
  814|    729|            if (TokenMatch(mFilePtr, "NODE_NAME", 9)) {
  ------------------
  |  Branch (814:17): [True: 49, False: 680]
  ------------------
  815|     49|                if (!ParseString(node.mName, "*NODE_NAME"))
  ------------------
  |  Branch (815:21): [True: 0, False: 49]
  ------------------
  816|      0|                    SkipToNextToken();
  817|     49|                continue;
  818|     49|            }
  819|       |            // name of the parent of the node
  820|    680|            if (TokenMatch(mFilePtr, "NODE_PARENT", 11)) {
  ------------------
  |  Branch (820:17): [True: 1, False: 679]
  ------------------
  821|      1|                if (!ParseString(node.mParent, "*NODE_PARENT"))
  ------------------
  |  Branch (821:21): [True: 0, False: 1]
  ------------------
  822|      0|                    SkipToNextToken();
  823|      1|                continue;
  824|      1|            }
  825|       |            // transformation matrix of the node
  826|    679|            if (TokenMatch(mFilePtr, "NODE_TM", 7)) {
  ------------------
  |  Branch (826:17): [True: 62, False: 617]
  ------------------
  827|     62|                ParseLV2NodeTransformBlock(node);
  828|     62|                continue;
  829|     62|            }
  830|       |            // animation data of the node
  831|    617|            if (TokenMatch(mFilePtr, "TM_ANIMATION", 12)) {
  ------------------
  |  Branch (831:17): [True: 30, False: 587]
  ------------------
  832|     30|                ParseLV2AnimationBlock(node);
  833|     30|                continue;
  834|     30|            }
  835|       |
  836|    587|            if (node.mType == BaseNode::Light) {
  ------------------
  |  Branch (836:17): [True: 72, False: 515]
  ------------------
  837|       |                // light settings
  838|     72|                if (TokenMatch(mFilePtr, "LIGHT_SETTINGS", 14)) {
  ------------------
  |  Branch (838:21): [True: 3, False: 69]
  ------------------
  839|      3|                    ParseLV2LightSettingsBlock((ASE::Light &)node);
  840|      3|                    continue;
  841|      3|                }
  842|       |                // type of the light source
  843|     69|                if (TokenMatch(mFilePtr, "LIGHT_TYPE", 10)) {
  ------------------
  |  Branch (843:21): [True: 3, False: 66]
  ------------------
  844|      3|                    if (!ASSIMP_strincmp("omni", mFilePtr, 4)) {
  ------------------
  |  Branch (844:25): [True: 0, False: 3]
  ------------------
  845|      0|                        ((ASE::Light &)node).mLightType = ASE::Light::OMNI;
  846|      3|                    } else if (!ASSIMP_strincmp("target", mFilePtr, 6)) {
  ------------------
  |  Branch (846:32): [True: 0, False: 3]
  ------------------
  847|      0|                        ((ASE::Light &)node).mLightType = ASE::Light::TARGET;
  848|      3|                    } else if (!ASSIMP_strincmp("free", mFilePtr, 4)) {
  ------------------
  |  Branch (848:32): [True: 1, False: 2]
  ------------------
  849|      1|                        ((ASE::Light &)node).mLightType = ASE::Light::FREE;
  850|      2|                    } else if (!ASSIMP_strincmp("directional", mFilePtr, 11)) {
  ------------------
  |  Branch (850:32): [True: 2, False: 0]
  ------------------
  851|      2|                        ((ASE::Light &)node).mLightType = ASE::Light::DIRECTIONAL;
  852|      2|                    } else {
  853|      0|                        LogWarning("Unknown kind of light source");
  854|      0|                    }
  855|      3|                    continue;
  856|      3|                }
  857|    515|            } else if (node.mType == BaseNode::Camera) {
  ------------------
  |  Branch (857:24): [True: 64, False: 451]
  ------------------
  858|       |                // Camera settings
  859|     64|                if (TokenMatch(mFilePtr, "CAMERA_SETTINGS", 15)) {
  ------------------
  |  Branch (859:21): [True: 20, False: 44]
  ------------------
  860|     20|                    ParseLV2CameraSettingsBlock((ASE::Camera &)node);
  861|     20|                    continue;
  862|     44|                } else if (TokenMatch(mFilePtr, "CAMERA_TYPE", 11)) {
  ------------------
  |  Branch (862:28): [True: 4, False: 40]
  ------------------
  863|      4|                    if (!ASSIMP_strincmp("target", mFilePtr, 6)) {
  ------------------
  |  Branch (863:25): [True: 4, False: 0]
  ------------------
  864|      4|                        ((ASE::Camera &)node).mCameraType = ASE::Camera::TARGET;
  865|      4|                    } else if (!ASSIMP_strincmp("free", mFilePtr, 4)) {
  ------------------
  |  Branch (865:32): [True: 0, False: 0]
  ------------------
  866|      0|                        ((ASE::Camera &)node).mCameraType = ASE::Camera::FREE;
  867|      0|                    } else {
  868|      0|                        LogWarning("Unknown kind of camera");
  869|      0|                    }
  870|      4|                    continue;
  871|      4|                }
  872|    451|            } else if (node.mType == BaseNode::Mesh) {
  ------------------
  |  Branch (872:24): [True: 451, False: 0]
  ------------------
  873|       |                // mesh data
  874|       |                // FIX: Older files use MESH_SOFTSKIN
  875|    451|                if (TokenMatch(mFilePtr, "MESH", 4) ||
  ------------------
  |  Branch (875:21): [True: 38, False: 413]
  ------------------
  876|    413|                        TokenMatch(mFilePtr, "MESH_SOFTSKIN", 13)) {
  ------------------
  |  Branch (876:25): [True: 1, False: 412]
  ------------------
  877|     39|                    ParseLV2MeshBlock((ASE::Mesh &)node);
  878|     39|                    continue;
  879|     39|                }
  880|       |                // mesh material index
  881|    412|                if (TokenMatch(mFilePtr, "MATERIAL_REF", 12)) {
  ------------------
  |  Branch (881:21): [True: 8, False: 404]
  ------------------
  882|      8|                    ParseLV4MeshLong(((ASE::Mesh &)node).iMaterialIndex);
  883|      8|                    continue;
  884|      8|                }
  885|    412|            }
  886|    587|        }
  887|  39.6k|        AI_ASE_HANDLE_TOP_LEVEL_SECTION();
  ------------------
  |  |   69|  20.0k|    else if ('{' == *mFilePtr)                     \
  |  |  ------------------
  |  |  |  Branch (69:14): [True: 72, False: 19.2k]
  |  |  ------------------
  |  |   70|  19.3k|        ++iDepth;                                  \
  |  |   71|  19.3k|    else if ('}' == *mFilePtr) {                   \
  |  |  ------------------
  |  |  |  Branch (71:14): [True: 1.44k, False: 17.8k]
  |  |  ------------------
  |  |   72|  1.44k|        if (0 == --iDepth) {                       \
  |  |  ------------------
  |  |  |  Branch (72:13): [True: 29, False: 1.42k]
  |  |  ------------------
  |  |   73|     29|            ++mFilePtr;                            \
  |  |   74|     29|            SkipToNextToken();                     \
  |  |   75|     29|            return;                                \
  |  |   76|     29|        }                                          \
  |  |   77|  1.44k|    }                                              \
  |  |   78|  20.0k|    if ('\0' == *mFilePtr) {                       \
  |  |  ------------------
  |  |  |  Branch (78:9): [True: 5, False: 19.8k]
  |  |  ------------------
  |  |   79|      5|        return;                                    \
  |  |   80|      5|    }                                              \
  |  |   81|  19.8k|    if (IsLineEnd(*mFilePtr) && !bLastWasEndLine) {\
  |  |  ------------------
  |  |  |  Branch (81:9): [True: 1.10k, False: 18.7k]
  |  |  |  Branch (81:33): [True: 893, False: 216]
  |  |  ------------------
  |  |   82|    893|        ++iLineNumber;                             \
  |  |   83|    893|        bLastWasEndLine = true;                    \
  |  |   84|    893|    } else                                         \
  |  |   85|  19.8k|        bLastWasEndLine = false;                   \
  |  |   86|  19.8k|    ++mFilePtr;
  ------------------
  888|  39.6k|    }
  889|     54|}
_ZN6Assimp3ASE6Parser27ParseLV2CameraSettingsBlockERNS0_6CameraE:
  892|     20|void Parser::ParseLV2CameraSettingsBlock(ASE::Camera &camera) {
  893|     20|    AI_ASE_PARSER_INIT();
  ------------------
  |  |   63|     20|    int iDepth = 0;
  ------------------
  894|  33.5k|    while (true) {
  ------------------
  |  Branch (894:12): [True: 33.5k, Folded]
  ------------------
  895|  33.5k|        if ('*' == *mFilePtr) {
  ------------------
  |  Branch (895:13): [True: 740, False: 32.8k]
  ------------------
  896|    740|            ++mFilePtr;
  897|    740|            if (TokenMatch(mFilePtr, "CAMERA_NEAR", 11)) {
  ------------------
  |  Branch (897:17): [True: 4, False: 736]
  ------------------
  898|      4|                ParseLV4MeshReal(camera.mNear);
  899|      4|                continue;
  900|      4|            }
  901|    736|            if (TokenMatch(mFilePtr, "CAMERA_FAR", 10)) {
  ------------------
  |  Branch (901:17): [True: 4, False: 732]
  ------------------
  902|      4|                ParseLV4MeshReal(camera.mFar);
  903|      4|                continue;
  904|      4|            }
  905|    732|            if (TokenMatch(mFilePtr, "CAMERA_FOV", 10)) {
  ------------------
  |  Branch (905:17): [True: 4, False: 728]
  ------------------
  906|      4|                ParseLV4MeshReal(camera.mFOV);
  907|      4|                continue;
  908|      4|            }
  909|    732|        }
  910|  67.1k|        AI_ASE_HANDLE_SECTION("2", "CAMERA_SETTINGS");
  ------------------
  |  |   94|  33.5k|    if ('{' == *mFilePtr)                                          \
  |  |  ------------------
  |  |  |  Branch (94:9): [True: 190, False: 33.3k]
  |  |  ------------------
  |  |   95|  33.5k|        iDepth++;                                                  \
  |  |   96|  33.5k|    else if ('}' == *mFilePtr) {                                   \
  |  |  ------------------
  |  |  |  Branch (96:14): [True: 610, False: 32.7k]
  |  |  ------------------
  |  |   97|    610|        if (0 == --iDepth) {                                       \
  |  |  ------------------
  |  |  |  Branch (97:13): [True: 18, False: 592]
  |  |  ------------------
  |  |   98|     18|            ++mFilePtr;                                            \
  |  |   99|     18|            SkipToNextToken();                                     \
  |  |  100|     18|            return;                                                \
  |  |  101|     18|        }                                                          \
  |  |  102|  32.7k|    } else if ('\0' == *mFilePtr) {                                \
  |  |  ------------------
  |  |  |  Branch (102:16): [True: 2, False: 32.7k]
  |  |  ------------------
  |  |  103|      2|        LogError("Encountered unexpected EOL while parsing a " msg \
  |  |  104|      2|                 " chunk (Level " level ")");                      \
  |  |  105|      2|    }                                                              \
  |  |  106|  33.5k|    if (IsLineEnd(*mFilePtr) && !bLastWasEndLine) {                \
  |  |  ------------------
  |  |  |  Branch (106:9): [True: 2.98k, False: 30.5k]
  |  |  |  Branch (106:33): [True: 2.37k, False: 615]
  |  |  ------------------
  |  |  107|  2.37k|        ++iLineNumber;                                             \
  |  |  108|  2.37k|        bLastWasEndLine = true;                                    \
  |  |  109|  2.37k|    } else                                                         \
  |  |  110|  33.5k|        bLastWasEndLine = false;                                   \
  |  |  111|  33.5k|    ++mFilePtr;
  ------------------
  911|  67.1k|    }
  912|     20|}
_ZN6Assimp3ASE6Parser26ParseLV2LightSettingsBlockERNS0_5LightE:
  915|      3|void Parser::ParseLV2LightSettingsBlock(ASE::Light &light) {
  916|      3|    AI_ASE_PARSER_INIT();
  ------------------
  |  |   63|      3|    int iDepth = 0;
  ------------------
  917|    503|    while (true) {
  ------------------
  |  Branch (917:12): [True: 503, Folded]
  ------------------
  918|    503|        if ('*' == *mFilePtr) {
  ------------------
  |  Branch (918:13): [True: 33, False: 470]
  ------------------
  919|     33|            ++mFilePtr;
  920|     33|            if (TokenMatch(mFilePtr, "LIGHT_COLOR", 11)) {
  ------------------
  |  Branch (920:17): [True: 3, False: 30]
  ------------------
  921|      3|                ParseLV4MeshFloatTriple(&light.mColor.r);
  922|      3|                continue;
  923|      3|            }
  924|     30|            if (TokenMatch(mFilePtr, "LIGHT_INTENS", 12)) {
  ------------------
  |  Branch (924:17): [True: 3, False: 27]
  ------------------
  925|      3|                ParseLV4MeshReal(light.mIntensity);
  926|      3|                continue;
  927|      3|            }
  928|     27|            if (TokenMatch(mFilePtr, "LIGHT_HOTSPOT", 13)) {
  ------------------
  |  Branch (928:17): [True: 3, False: 24]
  ------------------
  929|      3|                ParseLV4MeshReal(light.mAngle);
  930|      3|                continue;
  931|      3|            }
  932|     24|            if (TokenMatch(mFilePtr, "LIGHT_FALLOFF", 13)) {
  ------------------
  |  Branch (932:17): [True: 3, False: 21]
  ------------------
  933|      3|                ParseLV4MeshReal(light.mFalloff);
  934|      3|                continue;
  935|      3|            }
  936|     24|        }
  937|    979|        AI_ASE_HANDLE_SECTION("2", "LIGHT_SETTINGS");
  ------------------
  |  |   94|    491|    if ('{' == *mFilePtr)                                          \
  |  |  ------------------
  |  |  |  Branch (94:9): [True: 3, False: 488]
  |  |  ------------------
  |  |   95|    491|        iDepth++;                                                  \
  |  |   96|    491|    else if ('}' == *mFilePtr) {                                   \
  |  |  ------------------
  |  |  |  Branch (96:14): [True: 3, False: 485]
  |  |  ------------------
  |  |   97|      3|        if (0 == --iDepth) {                                       \
  |  |  ------------------
  |  |  |  Branch (97:13): [True: 3, False: 0]
  |  |  ------------------
  |  |   98|      3|            ++mFilePtr;                                            \
  |  |   99|      3|            SkipToNextToken();                                     \
  |  |  100|      3|            return;                                                \
  |  |  101|      3|        }                                                          \
  |  |  102|    485|    } else if ('\0' == *mFilePtr) {                                \
  |  |  ------------------
  |  |  |  Branch (102:16): [True: 0, False: 485]
  |  |  ------------------
  |  |  103|      0|        LogError("Encountered unexpected EOL while parsing a " msg \
  |  |  104|      0|                 " chunk (Level " level ")");                      \
  |  |  105|      0|    }                                                              \
  |  |  106|    491|    if (IsLineEnd(*mFilePtr) && !bLastWasEndLine) {                \
  |  |  ------------------
  |  |  |  Branch (106:9): [True: 36, False: 452]
  |  |  |  Branch (106:33): [True: 36, False: 0]
  |  |  ------------------
  |  |  107|     36|        ++iLineNumber;                                             \
  |  |  108|     36|        bLastWasEndLine = true;                                    \
  |  |  109|     36|    } else                                                         \
  |  |  110|    488|        bLastWasEndLine = false;                                   \
  |  |  111|    488|    ++mFilePtr;
  ------------------
  938|    979|    }
  939|      3|}
_ZN6Assimp3ASE6Parser22ParseLV2AnimationBlockERNS0_8BaseNodeE:
  942|     30|void Parser::ParseLV2AnimationBlock(ASE::BaseNode &mesh) {
  943|     30|    AI_ASE_PARSER_INIT();
  ------------------
  |  |   63|     30|    int iDepth = 0;
  ------------------
  944|       |
  945|     30|    ASE::Animation *anim = &mesh.mAnim;
  946|  6.64k|    while (true) {
  ------------------
  |  Branch (946:12): [True: 6.63k, Folded]
  ------------------
  947|  6.63k|        if ('*' == *mFilePtr) {
  ------------------
  |  Branch (947:13): [True: 189, False: 6.45k]
  ------------------
  948|    189|            ++mFilePtr;
  949|    189|            if (TokenMatch(mFilePtr, "NODE_NAME", 9)) {
  ------------------
  |  Branch (949:17): [True: 25, False: 164]
  ------------------
  950|     25|                std::string temp;
  951|     25|                if (!ParseString(temp, "*NODE_NAME"))
  ------------------
  |  Branch (951:21): [True: 0, False: 25]
  ------------------
  952|      0|                    SkipToNextToken();
  953|       |
  954|       |                // If the name of the node contains .target it
  955|       |                // represents an animated camera or spot light
  956|       |                // target.
  957|     25|                if (std::string::npos != temp.find(".Target")) {
  ------------------
  |  Branch (957:21): [True: 8, False: 17]
  ------------------
  958|      8|                    if ((mesh.mType != BaseNode::Camera || ((ASE::Camera &)mesh).mCameraType != ASE::Camera::TARGET) &&
  ------------------
  |  Branch (958:26): [True: 5, False: 3]
  |  Branch (958:60): [True: 0, False: 3]
  ------------------
  959|      5|                            (mesh.mType != BaseNode::Light || ((ASE::Light &)mesh).mLightType != ASE::Light::TARGET)) {
  ------------------
  |  Branch (959:30): [True: 5, False: 0]
  |  Branch (959:63): [True: 0, False: 0]
  ------------------
  960|       |
  961|      5|                        ASSIMP_LOG_ERROR("ASE: Found target animation channel "
  962|      5|                                         "but the node is neither a camera nor a spot light");
  963|      5|                        anim = nullptr;
  964|      5|                    } else
  965|      3|                        anim = &mesh.mTargetAnim;
  966|      8|                }
  967|     25|                continue;
  968|     25|            }
  969|       |
  970|       |            // position keyframes
  971|    164|            if (TokenMatch(mFilePtr, "CONTROL_POS_TRACK", 17) ||
  ------------------
  |  Branch (971:17): [True: 20, False: 144]
  ------------------
  972|    144|                    TokenMatch(mFilePtr, "CONTROL_POS_BEZIER", 18) ||
  ------------------
  |  Branch (972:21): [True: 0, False: 144]
  ------------------
  973|    144|                    TokenMatch(mFilePtr, "CONTROL_POS_TCB", 15)) {
  ------------------
  |  Branch (973:21): [True: 0, False: 144]
  ------------------
  974|     20|                if (!anim)
  ------------------
  |  Branch (974:21): [True: 5, False: 15]
  ------------------
  975|      5|                    SkipSection();
  976|     15|                else
  977|     15|                    ParseLV3PosAnimationBlock(*anim);
  978|     20|                continue;
  979|     20|            }
  980|       |            // scaling keyframes
  981|    144|            if (TokenMatch(mFilePtr, "CONTROL_SCALE_TRACK", 19) ||
  ------------------
  |  Branch (981:17): [True: 1, False: 143]
  ------------------
  982|    143|                    TokenMatch(mFilePtr, "CONTROL_SCALE_BEZIER", 20) ||
  ------------------
  |  Branch (982:21): [True: 0, False: 143]
  ------------------
  983|    143|                    TokenMatch(mFilePtr, "CONTROL_SCALE_TCB", 17)) {
  ------------------
  |  Branch (983:21): [True: 0, False: 143]
  ------------------
  984|      1|                if (!anim || anim == &mesh.mTargetAnim) {
  ------------------
  |  Branch (984:21): [True: 0, False: 1]
  |  Branch (984:30): [True: 0, False: 1]
  ------------------
  985|       |                    // Target animation channels may have no rotation channels
  986|      0|                    ASSIMP_LOG_ERROR("ASE: Ignoring scaling channel in target animation");
  987|      0|                    SkipSection();
  988|      0|                } else
  989|      1|                    ParseLV3ScaleAnimationBlock(*anim);
  990|      1|                continue;
  991|      1|            }
  992|       |            // rotation keyframes
  993|    143|            if (TokenMatch(mFilePtr, "CONTROL_ROT_TRACK", 17) ||
  ------------------
  |  Branch (993:17): [True: 13, False: 130]
  ------------------
  994|    130|                    TokenMatch(mFilePtr, "CONTROL_ROT_BEZIER", 18) ||
  ------------------
  |  Branch (994:21): [True: 5, False: 125]
  ------------------
  995|    125|                    TokenMatch(mFilePtr, "CONTROL_ROT_TCB", 15)) {
  ------------------
  |  Branch (995:21): [True: 0, False: 125]
  ------------------
  996|     18|                if (!anim || anim == &mesh.mTargetAnim) {
  ------------------
  |  Branch (996:21): [True: 0, False: 18]
  |  Branch (996:30): [True: 0, False: 18]
  ------------------
  997|       |                    // Target animation channels may have no rotation channels
  998|      0|                    ASSIMP_LOG_ERROR("ASE: Ignoring rotation channel in target animation");
  999|      0|                    SkipSection();
 1000|      0|                } else
 1001|     18|                    ParseLV3RotAnimationBlock(*anim);
 1002|     18|                continue;
 1003|     18|            }
 1004|    143|        }
 1005|  13.1k|        AI_ASE_HANDLE_SECTION("2", "TM_ANIMATION");
  ------------------
  |  |   94|  6.57k|    if ('{' == *mFilePtr)                                          \
  |  |  ------------------
  |  |  |  Branch (94:9): [True: 31, False: 6.54k]
  |  |  ------------------
  |  |   95|  6.57k|        iDepth++;                                                  \
  |  |   96|  6.57k|    else if ('}' == *mFilePtr) {                                   \
  |  |  ------------------
  |  |  |  Branch (96:14): [True: 29, False: 6.51k]
  |  |  ------------------
  |  |   97|     29|        if (0 == --iDepth) {                                       \
  |  |  ------------------
  |  |  |  Branch (97:13): [True: 25, False: 4]
  |  |  ------------------
  |  |   98|     25|            ++mFilePtr;                                            \
  |  |   99|     25|            SkipToNextToken();                                     \
  |  |  100|     25|            return;                                                \
  |  |  101|     25|        }                                                          \
  |  |  102|  6.51k|    } else if ('\0' == *mFilePtr) {                                \
  |  |  ------------------
  |  |  |  Branch (102:16): [True: 1, False: 6.51k]
  |  |  ------------------
  |  |  103|      1|        LogError("Encountered unexpected EOL while parsing a " msg \
  |  |  104|      1|                 " chunk (Level " level ")");                      \
  |  |  105|      1|    }                                                              \
  |  |  106|  6.57k|    if (IsLineEnd(*mFilePtr) && !bLastWasEndLine) {                \
  |  |  ------------------
  |  |  |  Branch (106:9): [True: 279, False: 6.27k]
  |  |  |  Branch (106:33): [True: 239, False: 40]
  |  |  ------------------
  |  |  107|    239|        ++iLineNumber;                                             \
  |  |  108|    239|        bLastWasEndLine = true;                                    \
  |  |  109|    239|    } else                                                         \
  |  |  110|  6.55k|        bLastWasEndLine = false;                                   \
  |  |  111|  6.55k|    ++mFilePtr;
  ------------------
 1006|  13.1k|    }
 1007|     30|}
_ZN6Assimp3ASE6Parser27ParseLV3ScaleAnimationBlockERNS0_9AnimationE:
 1009|      1|void Parser::ParseLV3ScaleAnimationBlock(ASE::Animation &anim) {
 1010|      1|    AI_ASE_PARSER_INIT();
  ------------------
  |  |   63|      1|    int iDepth = 0;
  ------------------
 1011|      1|    unsigned int iIndex;
 1012|       |
 1013|  1.47k|    while (true) {
  ------------------
  |  Branch (1013:12): [True: 1.47k, Folded]
  ------------------
 1014|  1.47k|        if ('*' == *mFilePtr) {
  ------------------
  |  Branch (1014:13): [True: 45, False: 1.43k]
  ------------------
 1015|     45|            ++mFilePtr;
 1016|       |
 1017|     45|            bool b = false;
 1018|       |
 1019|       |            // For the moment we're just reading the three floats -
 1020|       |            // we ignore the additional information for bezier's and TCBs
 1021|       |
 1022|       |            // simple scaling keyframe
 1023|     45|            if (TokenMatch(mFilePtr, "CONTROL_SCALE_SAMPLE", 20)) {
  ------------------
  |  Branch (1023:17): [True: 45, False: 0]
  ------------------
 1024|     45|                b = true;
 1025|     45|                anim.mScalingType = ASE::Animation::TRACK;
 1026|     45|            }
 1027|       |
 1028|       |            // Bezier scaling keyframe
 1029|     45|            if (TokenMatch(mFilePtr, "CONTROL_BEZIER_SCALE_KEY", 24)) {
  ------------------
  |  Branch (1029:17): [True: 0, False: 45]
  ------------------
 1030|      0|                b = true;
 1031|      0|                anim.mScalingType = ASE::Animation::BEZIER;
 1032|      0|            }
 1033|       |            // TCB scaling keyframe
 1034|     45|            if (TokenMatch(mFilePtr, "CONTROL_TCB_SCALE_KEY", 21)) {
  ------------------
  |  Branch (1034:17): [True: 0, False: 45]
  ------------------
 1035|      0|                b = true;
 1036|      0|                anim.mScalingType = ASE::Animation::TCB;
 1037|      0|            }
 1038|     45|            if (b) {
  ------------------
  |  Branch (1038:17): [True: 45, False: 0]
  ------------------
 1039|     45|                anim.akeyScaling.emplace_back();
 1040|     45|                aiVectorKey &key = anim.akeyScaling.back();
 1041|     45|                ParseLV4MeshRealTriple(&key.mValue.x, iIndex);
 1042|     45|                key.mTime = (double)iIndex;
 1043|     45|            }
 1044|     45|        }
 1045|  1.47k|        AI_ASE_HANDLE_SECTION("3", "*CONTROL_POS_TRACK");
  ------------------
  |  |   94|  1.47k|    if ('{' == *mFilePtr)                                          \
  |  |  ------------------
  |  |  |  Branch (94:9): [True: 1, False: 1.47k]
  |  |  ------------------
  |  |   95|  1.47k|        iDepth++;                                                  \
  |  |   96|  1.47k|    else if ('}' == *mFilePtr) {                                   \
  |  |  ------------------
  |  |  |  Branch (96:14): [True: 1, False: 1.47k]
  |  |  ------------------
  |  |   97|      1|        if (0 == --iDepth) {                                       \
  |  |  ------------------
  |  |  |  Branch (97:13): [True: 1, False: 0]
  |  |  ------------------
  |  |   98|      1|            ++mFilePtr;                                            \
  |  |   99|      1|            SkipToNextToken();                                     \
  |  |  100|      1|            return;                                                \
  |  |  101|      1|        }                                                          \
  |  |  102|  1.47k|    } else if ('\0' == *mFilePtr) {                                \
  |  |  ------------------
  |  |  |  Branch (102:16): [True: 0, False: 1.47k]
  |  |  ------------------
  |  |  103|      0|        LogError("Encountered unexpected EOL while parsing a " msg \
  |  |  104|      0|                 " chunk (Level " level ")");                      \
  |  |  105|      0|    }                                                              \
  |  |  106|  1.47k|    if (IsLineEnd(*mFilePtr) && !bLastWasEndLine) {                \
  |  |  ------------------
  |  |  |  Branch (106:9): [True: 46, False: 1.43k]
  |  |  |  Branch (106:33): [True: 46, False: 0]
  |  |  ------------------
  |  |  107|     46|        ++iLineNumber;                                             \
  |  |  108|     46|        bLastWasEndLine = true;                                    \
  |  |  109|     46|    } else                                                         \
  |  |  110|  1.47k|        bLastWasEndLine = false;                                   \
  |  |  111|  1.47k|    ++mFilePtr;
  ------------------
 1046|  1.47k|    }
 1047|      1|}
_ZN6Assimp3ASE6Parser25ParseLV3PosAnimationBlockERNS0_9AnimationE:
 1049|     15|void Parser::ParseLV3PosAnimationBlock(ASE::Animation &anim) {
 1050|     15|    AI_ASE_PARSER_INIT();
  ------------------
  |  |   63|     15|    int iDepth = 0;
  ------------------
 1051|     15|    unsigned int iIndex;
 1052|  3.45k|    while (true) {
  ------------------
  |  Branch (1052:12): [True: 3.45k, Folded]
  ------------------
 1053|  3.45k|        if ('*' == *mFilePtr) {
  ------------------
  |  Branch (1053:13): [True: 839, False: 2.61k]
  ------------------
 1054|    839|            ++mFilePtr;
 1055|       |
 1056|    839|            bool b = false;
 1057|       |
 1058|       |            // For the moment we're just reading the three floats -
 1059|       |            // we ignore the additional information for bezier's and TCBs
 1060|       |
 1061|       |            // simple scaling keyframe
 1062|    839|            if (TokenMatch(mFilePtr, "CONTROL_POS_SAMPLE", 18)) {
  ------------------
  |  Branch (1062:17): [True: 837, False: 2]
  ------------------
 1063|    837|                b = true;
 1064|    837|                anim.mPositionType = ASE::Animation::TRACK;
 1065|    837|            }
 1066|       |
 1067|       |            // Bezier scaling keyframe
 1068|    839|            if (TokenMatch(mFilePtr, "CONTROL_BEZIER_POS_KEY", 22)) {
  ------------------
  |  Branch (1068:17): [True: 0, False: 839]
  ------------------
 1069|      0|                b = true;
 1070|      0|                anim.mPositionType = ASE::Animation::BEZIER;
 1071|      0|            }
 1072|       |            // TCB scaling keyframe
 1073|    839|            if (TokenMatch(mFilePtr, "CONTROL_TCB_POS_KEY", 19)) {
  ------------------
  |  Branch (1073:17): [True: 0, False: 839]
  ------------------
 1074|      0|                b = true;
 1075|      0|                anim.mPositionType = ASE::Animation::TCB;
 1076|      0|            }
 1077|    839|            if (b) {
  ------------------
  |  Branch (1077:17): [True: 837, False: 2]
  ------------------
 1078|    837|                anim.akeyPositions.emplace_back();
 1079|    837|                aiVectorKey &key = anim.akeyPositions.back();
 1080|    837|                ParseLV4MeshRealTriple(&key.mValue.x, iIndex);
 1081|    837|                key.mTime = (double)iIndex;
 1082|    837|            }
 1083|    839|        }
 1084|  3.45k|        AI_ASE_HANDLE_SECTION("3", "*CONTROL_POS_TRACK");
  ------------------
  |  |   94|  3.45k|    if ('{' == *mFilePtr)                                          \
  |  |  ------------------
  |  |  |  Branch (94:9): [True: 15, False: 3.43k]
  |  |  ------------------
  |  |   95|  3.45k|        iDepth++;                                                  \
  |  |   96|  3.45k|    else if ('}' == *mFilePtr) {                                   \
  |  |  ------------------
  |  |  |  Branch (96:14): [True: 14, False: 3.42k]
  |  |  ------------------
  |  |   97|     14|        if (0 == --iDepth) {                                       \
  |  |  ------------------
  |  |  |  Branch (97:13): [True: 14, False: 0]
  |  |  ------------------
  |  |   98|     14|            ++mFilePtr;                                            \
  |  |   99|     14|            SkipToNextToken();                                     \
  |  |  100|     14|            return;                                                \
  |  |  101|     14|        }                                                          \
  |  |  102|  3.42k|    } else if ('\0' == *mFilePtr) {                                \
  |  |  ------------------
  |  |  |  Branch (102:16): [True: 1, False: 3.42k]
  |  |  ------------------
  |  |  103|      1|        LogError("Encountered unexpected EOL while parsing a " msg \
  |  |  104|      1|                 " chunk (Level " level ")");                      \
  |  |  105|      1|    }                                                              \
  |  |  106|  3.45k|    if (IsLineEnd(*mFilePtr) && !bLastWasEndLine) {                \
  |  |  ------------------
  |  |  |  Branch (106:9): [True: 851, False: 2.58k]
  |  |  |  Branch (106:33): [True: 851, False: 0]
  |  |  ------------------
  |  |  107|    851|        ++iLineNumber;                                             \
  |  |  108|    851|        bLastWasEndLine = true;                                    \
  |  |  109|    851|    } else                                                         \
  |  |  110|  3.43k|        bLastWasEndLine = false;                                   \
  |  |  111|  3.43k|    ++mFilePtr;
  ------------------
 1085|  3.43k|    }
 1086|     15|}
_ZN6Assimp3ASE6Parser25ParseLV3RotAnimationBlockERNS0_9AnimationE:
 1088|     18|void Parser::ParseLV3RotAnimationBlock(ASE::Animation &anim) {
 1089|     18|    AI_ASE_PARSER_INIT();
  ------------------
  |  |   63|     18|    int iDepth = 0;
  ------------------
 1090|     18|    unsigned int iIndex;
 1091|  48.0k|    while (true) {
  ------------------
  |  Branch (1091:12): [True: 48.0k, Folded]
  ------------------
 1092|  48.0k|        if ('*' == *mFilePtr) {
  ------------------
  |  Branch (1092:13): [True: 2.75k, False: 45.2k]
  ------------------
 1093|  2.75k|            ++mFilePtr;
 1094|       |
 1095|  2.75k|            bool b = false;
 1096|       |
 1097|       |            // For the moment we're just reading the  floats -
 1098|       |            // we ignore the additional information for bezier's and TCBs
 1099|       |
 1100|       |            // simple scaling keyframe
 1101|  2.75k|            if (TokenMatch(mFilePtr, "CONTROL_ROT_SAMPLE", 18)) {
  ------------------
  |  Branch (1101:17): [True: 1.98k, False: 768]
  ------------------
 1102|  1.98k|                b = true;
 1103|  1.98k|                anim.mRotationType = ASE::Animation::TRACK;
 1104|  1.98k|            }
 1105|       |
 1106|       |            // Bezier scaling keyframe
 1107|  2.75k|            if (TokenMatch(mFilePtr, "CONTROL_BEZIER_ROT_KEY", 22)) {
  ------------------
  |  Branch (1107:17): [True: 26, False: 2.72k]
  ------------------
 1108|     26|                b = true;
 1109|     26|                anim.mRotationType = ASE::Animation::BEZIER;
 1110|     26|            }
 1111|       |            // TCB scaling keyframe
 1112|  2.75k|            if (TokenMatch(mFilePtr, "CONTROL_TCB_ROT_KEY", 19)) {
  ------------------
  |  Branch (1112:17): [True: 0, False: 2.75k]
  ------------------
 1113|      0|                b = true;
 1114|      0|                anim.mRotationType = ASE::Animation::TCB;
 1115|      0|            }
 1116|  2.75k|            if (b) {
  ------------------
  |  Branch (1116:17): [True: 2.01k, False: 742]
  ------------------
 1117|  2.01k|                anim.akeyRotations.emplace_back();
 1118|  2.01k|                aiQuatKey &key = anim.akeyRotations.back();
 1119|  2.01k|                aiVector3D v;
 1120|  2.01k|                ai_real f;
 1121|  2.01k|                ParseLV4MeshRealTriple(&v.x, iIndex);
 1122|  2.01k|                ParseLV4MeshReal(f);
 1123|  2.01k|                key.mTime = (double)iIndex;
 1124|  2.01k|                key.mValue = aiQuaternion(v, f);
 1125|  2.01k|            }
 1126|  2.75k|        }
 1127|  48.0k|        AI_ASE_HANDLE_SECTION("3", "*CONTROL_ROT_TRACK");
  ------------------
  |  |   94|  48.0k|    if ('{' == *mFilePtr)                                          \
  |  |  ------------------
  |  |  |  Branch (94:9): [True: 43, False: 48.0k]
  |  |  ------------------
  |  |   95|  48.0k|        iDepth++;                                                  \
  |  |   96|  48.0k|    else if ('}' == *mFilePtr) {                                   \
  |  |  ------------------
  |  |  |  Branch (96:14): [True: 44, False: 47.9k]
  |  |  ------------------
  |  |   97|     44|        if (0 == --iDepth) {                                       \
  |  |  ------------------
  |  |  |  Branch (97:13): [True: 15, False: 29]
  |  |  ------------------
  |  |   98|     15|            ++mFilePtr;                                            \
  |  |   99|     15|            SkipToNextToken();                                     \
  |  |  100|     15|            return;                                                \
  |  |  101|     15|        }                                                          \
  |  |  102|  47.9k|    } else if ('\0' == *mFilePtr) {                                \
  |  |  ------------------
  |  |  |  Branch (102:16): [True: 2, False: 47.9k]
  |  |  ------------------
  |  |  103|      2|        LogError("Encountered unexpected EOL while parsing a " msg \
  |  |  104|      2|                 " chunk (Level " level ")");                      \
  |  |  105|      2|    }                                                              \
  |  |  106|  48.0k|    if (IsLineEnd(*mFilePtr) && !bLastWasEndLine) {                \
  |  |  ------------------
  |  |  |  Branch (106:9): [True: 16.7k, False: 31.2k]
  |  |  |  Branch (106:33): [True: 10.5k, False: 6.23k]
  |  |  ------------------
  |  |  107|  10.5k|        ++iLineNumber;                                             \
  |  |  108|  10.5k|        bLastWasEndLine = true;                                    \
  |  |  109|  10.5k|    } else                                                         \
  |  |  110|  48.0k|        bLastWasEndLine = false;                                   \
  |  |  111|  48.0k|    ++mFilePtr;
  ------------------
 1128|  48.0k|    }
 1129|     18|}
_ZN6Assimp3ASE6Parser26ParseLV2NodeTransformBlockERNS0_8BaseNodeE:
 1131|     62|void Parser::ParseLV2NodeTransformBlock(ASE::BaseNode &mesh) {
 1132|     62|    AI_ASE_PARSER_INIT();
  ------------------
  |  |   63|     62|    int iDepth = 0;
  ------------------
 1133|     62|    int mode = 0;
 1134|  26.3k|    while (true) {
  ------------------
  |  Branch (1134:12): [True: 26.3k, Folded]
  ------------------
 1135|  26.3k|        if ('*' == *mFilePtr) {
  ------------------
  |  Branch (1135:13): [True: 1.08k, False: 25.2k]
  ------------------
 1136|  1.08k|            ++mFilePtr;
 1137|       |            // name of the node
 1138|  1.08k|            if (TokenMatch(mFilePtr, "NODE_NAME", 9)) {
  ------------------
  |  Branch (1138:17): [True: 65, False: 1.01k]
  ------------------
 1139|     65|                std::string temp;
 1140|     65|                if (!ParseString(temp, "*NODE_NAME"))
  ------------------
  |  Branch (1140:21): [True: 0, False: 65]
  ------------------
 1141|      0|                    SkipToNextToken();
 1142|       |
 1143|     65|                std::string::size_type s;
 1144|     65|                if (temp == mesh.mName) {
  ------------------
  |  Branch (1144:21): [True: 47, False: 18]
  ------------------
 1145|     47|                    mode = 1;
 1146|     47|                } else if (std::string::npos != (s = temp.find(".Target")) &&
  ------------------
  |  Branch (1146:28): [True: 14, False: 4]
  |  Branch (1146:28): [True: 12, False: 6]
  ------------------
 1147|     14|                           mesh.mName == temp.substr(0, s)) {
  ------------------
  |  Branch (1147:28): [True: 12, False: 2]
  ------------------
 1148|       |                    // This should be either a target light or a target camera
 1149|     12|                    if ((mesh.mType == BaseNode::Light && ((ASE::Light &)mesh).mLightType == ASE::Light::TARGET) ||
  ------------------
  |  Branch (1149:26): [True: 0, False: 12]
  |  Branch (1149:59): [True: 0, False: 0]
  ------------------
 1150|     12|                            (mesh.mType == BaseNode::Camera && ((ASE::Camera &)mesh).mCameraType == ASE::Camera::TARGET)) {
  ------------------
  |  Branch (1150:30): [True: 4, False: 8]
  |  Branch (1150:64): [True: 4, False: 0]
  ------------------
 1151|      4|                        mode = 2;
 1152|      8|                    } else {
 1153|      8|                        ASSIMP_LOG_ERROR("ASE: Ignoring target transform, "
 1154|      8|                                         "this is no spot light or target camera");
 1155|      8|                    }
 1156|     12|                } else {
 1157|      6|                    ASSIMP_LOG_ERROR("ASE: Unknown node transformation: ", temp);
 1158|       |                    // mode = 0
 1159|      6|                }
 1160|     65|                continue;
 1161|     65|            }
 1162|  1.01k|            if (mode) {
  ------------------
  |  Branch (1162:17): [True: 663, False: 354]
  ------------------
 1163|       |                // fourth row of the transformation matrix - and also the
 1164|       |                // only information here that is interesting for targets
 1165|    663|                if (TokenMatch(mFilePtr, "TM_ROW3", 7)) {
  ------------------
  |  Branch (1165:21): [True: 51, False: 612]
  ------------------
 1166|     51|                    ParseLV4MeshRealTriple((mode == 1 ? mesh.mTransform[3] : &mesh.mTargetPosition.x));
  ------------------
  |  Branch (1166:45): [True: 47, False: 4]
  ------------------
 1167|     51|                    continue;
 1168|     51|                }
 1169|    612|                if (mode == 1) {
  ------------------
  |  Branch (1169:21): [True: 564, False: 48]
  ------------------
 1170|       |                    // first row of the transformation matrix
 1171|    564|                    if (TokenMatch(mFilePtr, "TM_ROW0", 7)) {
  ------------------
  |  Branch (1171:25): [True: 47, False: 517]
  ------------------
 1172|     47|                        ParseLV4MeshRealTriple(mesh.mTransform[0]);
 1173|     47|                        continue;
 1174|     47|                    }
 1175|       |                    // second row of the transformation matrix
 1176|    517|                    if (TokenMatch(mFilePtr, "TM_ROW1", 7)) {
  ------------------
  |  Branch (1176:25): [True: 47, False: 470]
  ------------------
 1177|     47|                        ParseLV4MeshRealTriple(mesh.mTransform[1]);
 1178|     47|                        continue;
 1179|     47|                    }
 1180|       |                    // third row of the transformation matrix
 1181|    470|                    if (TokenMatch(mFilePtr, "TM_ROW2", 7)) {
  ------------------
  |  Branch (1181:25): [True: 47, False: 423]
  ------------------
 1182|     47|                        ParseLV4MeshRealTriple(mesh.mTransform[2]);
 1183|     47|                        continue;
 1184|     47|                    }
 1185|       |                    // inherited position axes
 1186|    423|                    if (TokenMatch(mFilePtr, "INHERIT_POS", 11)) {
  ------------------
  |  Branch (1186:25): [True: 47, False: 376]
  ------------------
 1187|     47|                        unsigned int aiVal[3];
 1188|     47|                        ParseLV4MeshLongTriple(aiVal);
 1189|       |
 1190|    188|                        for (unsigned int i = 0; i < 3; ++i)
  ------------------
  |  Branch (1190:50): [True: 141, False: 47]
  ------------------
 1191|    141|                            mesh.inherit.abInheritPosition[i] = aiVal[i] != 0;
 1192|     47|                        continue;
 1193|     47|                    }
 1194|       |                    // inherited rotation axes
 1195|    376|                    if (TokenMatch(mFilePtr, "INHERIT_ROT", 11)) {
  ------------------
  |  Branch (1195:25): [True: 47, False: 329]
  ------------------
 1196|     47|                        unsigned int aiVal[3];
 1197|     47|                        ParseLV4MeshLongTriple(aiVal);
 1198|       |
 1199|    188|                        for (unsigned int i = 0; i < 3; ++i)
  ------------------
  |  Branch (1199:50): [True: 141, False: 47]
  ------------------
 1200|    141|                            mesh.inherit.abInheritRotation[i] = aiVal[i] != 0;
 1201|     47|                        continue;
 1202|     47|                    }
 1203|       |                    // inherited scaling axes
 1204|    329|                    if (TokenMatch(mFilePtr, "INHERIT_SCL", 11)) {
  ------------------
  |  Branch (1204:25): [True: 47, False: 282]
  ------------------
 1205|     47|                        unsigned int aiVal[3];
 1206|     47|                        ParseLV4MeshLongTriple(aiVal);
 1207|       |
 1208|    188|                        for (unsigned int i = 0; i < 3; ++i)
  ------------------
  |  Branch (1208:50): [True: 141, False: 47]
  ------------------
 1209|    141|                            mesh.inherit.abInheritScaling[i] = aiVal[i] != 0;
 1210|     47|                        continue;
 1211|     47|                    }
 1212|    329|                }
 1213|    612|            }
 1214|  1.01k|        }
 1215|  51.8k|        AI_ASE_HANDLE_SECTION("2", "*NODE_TM");
  ------------------
  |  |   94|  25.9k|    if ('{' == *mFilePtr)                                          \
  |  |  ------------------
  |  |  |  Branch (94:9): [True: 70, False: 25.8k]
  |  |  ------------------
  |  |   95|  25.9k|        iDepth++;                                                  \
  |  |   96|  25.9k|    else if ('}' == *mFilePtr) {                                   \
  |  |  ------------------
  |  |  |  Branch (96:14): [True: 70, False: 25.8k]
  |  |  ------------------
  |  |   97|     70|        if (0 == --iDepth) {                                       \
  |  |  ------------------
  |  |  |  Branch (97:13): [True: 62, False: 8]
  |  |  ------------------
  |  |   98|     62|            ++mFilePtr;                                            \
  |  |   99|     62|            SkipToNextToken();                                     \
  |  |  100|     62|            return;                                                \
  |  |  101|     62|        }                                                          \
  |  |  102|  25.8k|    } else if ('\0' == *mFilePtr) {                                \
  |  |  ------------------
  |  |  |  Branch (102:16): [True: 0, False: 25.8k]
  |  |  ------------------
  |  |  103|      0|        LogError("Encountered unexpected EOL while parsing a " msg \
  |  |  104|      0|                 " chunk (Level " level ")");                      \
  |  |  105|      0|    }                                                              \
  |  |  106|  25.9k|    if (IsLineEnd(*mFilePtr) && !bLastWasEndLine) {                \
  |  |  ------------------
  |  |  |  Branch (106:9): [True: 1.15k, False: 24.7k]
  |  |  |  Branch (106:33): [True: 1.15k, False: 0]
  |  |  ------------------
  |  |  107|  1.15k|        ++iLineNumber;                                             \
  |  |  108|  1.15k|        bLastWasEndLine = true;                                    \
  |  |  109|  1.15k|    } else                                                         \
  |  |  110|  25.8k|        bLastWasEndLine = false;                                   \
  |  |  111|  25.8k|    ++mFilePtr;
  ------------------
 1216|  51.8k|    }
 1217|     62|}
_ZN6Assimp3ASE6Parser17ParseLV2MeshBlockERNS0_4MeshE:
 1219|     39|void Parser::ParseLV2MeshBlock(ASE::Mesh &mesh) {
 1220|     39|    AI_ASE_PARSER_INIT();
  ------------------
  |  |   63|     39|    int iDepth = 0;
  ------------------
 1221|       |
 1222|     39|    unsigned int iNumVertices = 0;
 1223|     39|    unsigned int iNumFaces = 0;
 1224|     39|    unsigned int iNumTVertices = 0;
 1225|     39|    unsigned int iNumTFaces = 0;
 1226|     39|    unsigned int iNumCVertices = 0;
 1227|     39|    unsigned int iNumCFaces = 0;
 1228|  77.8k|    while (true) {
  ------------------
  |  Branch (1228:12): [True: 77.8k, Folded]
  ------------------
 1229|  77.8k|        if ('*' == *mFilePtr) {
  ------------------
  |  Branch (1229:13): [True: 2.61k, False: 75.2k]
  ------------------
 1230|  2.61k|            ++mFilePtr;
 1231|       |            // Number of vertices in the mesh
 1232|  2.61k|            if (TokenMatch(mFilePtr, "MESH_NUMVERTEX", 14)) {
  ------------------
  |  Branch (1232:17): [True: 48, False: 2.56k]
  ------------------
 1233|     48|                ParseLV4MeshLong(iNumVertices);
 1234|     48|                continue;
 1235|     48|            }
 1236|       |            // Number of texture coordinates in the mesh
 1237|  2.56k|            if (TokenMatch(mFilePtr, "MESH_NUMTVERTEX", 15)) {
  ------------------
  |  Branch (1237:17): [True: 22, False: 2.54k]
  ------------------
 1238|     22|                ParseLV4MeshLong(iNumTVertices);
 1239|     22|                continue;
 1240|     22|            }
 1241|       |            // Number of vertex colors in the mesh
 1242|  2.54k|            if (TokenMatch(mFilePtr, "MESH_NUMCVERTEX", 15)) {
  ------------------
  |  Branch (1242:17): [True: 21, False: 2.52k]
  ------------------
 1243|     21|                ParseLV4MeshLong(iNumCVertices);
 1244|     21|                continue;
 1245|     21|            }
 1246|       |            // Number of regular faces in the mesh
 1247|  2.52k|            if (TokenMatch(mFilePtr, "MESH_NUMFACES", 13)) {
  ------------------
  |  Branch (1247:17): [True: 48, False: 2.47k]
  ------------------
 1248|     48|                ParseLV4MeshLong(iNumFaces);
 1249|     48|                continue;
 1250|     48|            }
 1251|       |            // Number of UVWed faces in the mesh
 1252|  2.47k|            if (TokenMatch(mFilePtr, "MESH_NUMTVFACES", 15)) {
  ------------------
  |  Branch (1252:17): [True: 22, False: 2.45k]
  ------------------
 1253|     22|                ParseLV4MeshLong(iNumTFaces);
 1254|     22|                continue;
 1255|     22|            }
 1256|       |            // Number of colored faces in the mesh
 1257|  2.45k|            if (TokenMatch(mFilePtr, "MESH_NUMCVFACES", 15)) {
  ------------------
  |  Branch (1257:17): [True: 0, False: 2.45k]
  ------------------
 1258|      0|                ParseLV4MeshLong(iNumCFaces);
 1259|      0|                continue;
 1260|      0|            }
 1261|       |            // mesh vertex list block
 1262|  2.45k|            if (TokenMatch(mFilePtr, "MESH_VERTEX_LIST", 16)) {
  ------------------
  |  Branch (1262:17): [True: 48, False: 2.40k]
  ------------------
 1263|     48|                ParseLV3MeshVertexListBlock(iNumVertices, mesh);
 1264|     48|                continue;
 1265|     48|            }
 1266|       |            // mesh face list block
 1267|  2.40k|            if (TokenMatch(mFilePtr, "MESH_FACE_LIST", 14)) {
  ------------------
  |  Branch (1267:17): [True: 22, False: 2.38k]
  ------------------
 1268|     22|                ParseLV3MeshFaceListBlock(iNumFaces, mesh);
 1269|     22|                continue;
 1270|     22|            }
 1271|       |            // mesh texture vertex list block
 1272|  2.38k|            if (TokenMatch(mFilePtr, "MESH_TVERTLIST", 14)) {
  ------------------
  |  Branch (1272:17): [True: 22, False: 2.36k]
  ------------------
 1273|     22|                ParseLV3MeshTListBlock(iNumTVertices, mesh);
 1274|     22|                continue;
 1275|     22|            }
 1276|       |            // mesh texture face block
 1277|  2.36k|            if (TokenMatch(mFilePtr, "MESH_TFACELIST", 14)) {
  ------------------
  |  Branch (1277:17): [True: 24, False: 2.33k]
  ------------------
 1278|     24|                ParseLV3MeshTFaceListBlock(iNumTFaces, mesh);
 1279|     24|                continue;
 1280|     24|            }
 1281|       |            // mesh color vertex list block
 1282|  2.33k|            if (TokenMatch(mFilePtr, "MESH_CVERTLIST", 14)) {
  ------------------
  |  Branch (1282:17): [True: 0, False: 2.33k]
  ------------------
 1283|      0|                ParseLV3MeshCListBlock(iNumCVertices, mesh);
 1284|      0|                continue;
 1285|      0|            }
 1286|       |            // mesh color face block
 1287|  2.33k|            if (TokenMatch(mFilePtr, "MESH_CFACELIST", 14)) {
  ------------------
  |  Branch (1287:17): [True: 0, False: 2.33k]
  ------------------
 1288|      0|                ParseLV3MeshCFaceListBlock(iNumCFaces, mesh);
 1289|      0|                continue;
 1290|      0|            }
 1291|       |            // mesh normals
 1292|  2.33k|            if (TokenMatch(mFilePtr, "MESH_NORMALS", 12)) {
  ------------------
  |  Branch (1292:17): [True: 21, False: 2.31k]
  ------------------
 1293|     21|                ParseLV3MeshNormalListBlock(mesh);
 1294|     21|                continue;
 1295|     21|            }
 1296|       |            // another mesh UV channel ...
 1297|  2.31k|            if (TokenMatch(mFilePtr, "MESH_MAPPINGCHANNEL", 19)) {
  ------------------
  |  Branch (1297:17): [True: 0, False: 2.31k]
  ------------------
 1298|      0|                unsigned int iIndex(0);
 1299|      0|                ParseLV4MeshLong(iIndex);
 1300|      0|                if (0 == iIndex) {
  ------------------
  |  Branch (1300:21): [True: 0, False: 0]
  ------------------
 1301|      0|                    LogWarning("Mapping channel has an invalid index. Skipping UV channel");
 1302|       |                    // skip it ...
 1303|      0|                    SkipSection();
 1304|      0|                } else {
 1305|      0|                    if (iIndex < 2) {
  ------------------
  |  Branch (1305:25): [True: 0, False: 0]
  ------------------
 1306|      0|                        LogWarning("Mapping channel has an invalid index. Skipping UV channel");
 1307|       |                        // skip it ...
 1308|      0|                        SkipSection();
 1309|      0|                    }
 1310|      0|                    if (iIndex > AI_MAX_NUMBER_OF_TEXTURECOORDS) {
  ------------------
  |  Branch (1310:25): [True: 0, False: 0]
  ------------------
 1311|      0|                        LogWarning("Too many UV channels specified. Skipping channel ..");
 1312|       |                        // skip it ...
 1313|      0|                        SkipSection();
 1314|      0|                    } else {
 1315|       |                        // parse the mapping channel
 1316|      0|                        ParseLV3MappingChannel(iIndex - 1, mesh);
 1317|      0|                    }
 1318|      0|                    continue;
 1319|      0|                }
 1320|      0|            }
 1321|       |            // mesh animation keyframe. Not supported
 1322|  2.31k|            if (TokenMatch(mFilePtr, "MESH_ANIMATION", 14)) {
  ------------------
  |  Branch (1322:17): [True: 0, False: 2.31k]
  ------------------
 1323|       |
 1324|      0|                LogWarning("Found *MESH_ANIMATION element in ASE/ASK file. "
 1325|      0|                           "Keyframe animation is not supported by Assimp, this element "
 1326|      0|                           "will be ignored");
 1327|       |                //SkipSection();
 1328|      0|                continue;
 1329|      0|            }
 1330|  2.31k|            if (TokenMatch(mFilePtr, "MESH_WEIGHTS", 12)) {
  ------------------
  |  Branch (1330:17): [True: 1, False: 2.31k]
  ------------------
 1331|      1|                ParseLV3MeshWeightsBlock(mesh);
 1332|      1|                continue;
 1333|      1|            }
 1334|  2.31k|        }
 1335|   155k|        AI_ASE_HANDLE_SECTION("2", "*MESH");
  ------------------
  |  |   94|  77.5k|    if ('{' == *mFilePtr)                                          \
  |  |  ------------------
  |  |  |  Branch (94:9): [True: 74, False: 77.4k]
  |  |  ------------------
  |  |   95|  77.5k|        iDepth++;                                                  \
  |  |   96|  77.5k|    else if ('}' == *mFilePtr) {                                   \
  |  |  ------------------
  |  |  |  Branch (96:14): [True: 52, False: 77.4k]
  |  |  ------------------
  |  |   97|     52|        if (0 == --iDepth) {                                       \
  |  |  ------------------
  |  |  |  Branch (97:13): [True: 26, False: 26]
  |  |  ------------------
  |  |   98|     26|            ++mFilePtr;                                            \
  |  |   99|     26|            SkipToNextToken();                                     \
  |  |  100|     26|            return;                                                \
  |  |  101|     26|        }                                                          \
  |  |  102|  77.4k|    } else if ('\0' == *mFilePtr) {                                \
  |  |  ------------------
  |  |  |  Branch (102:16): [True: 1, False: 77.4k]
  |  |  ------------------
  |  |  103|      1|        LogError("Encountered unexpected EOL while parsing a " msg \
  |  |  104|      1|                 " chunk (Level " level ")");                      \
  |  |  105|      1|    }                                                              \
  |  |  106|  77.5k|    if (IsLineEnd(*mFilePtr) && !bLastWasEndLine) {                \
  |  |  ------------------
  |  |  |  Branch (106:9): [True: 3.99k, False: 73.5k]
  |  |  |  Branch (106:33): [True: 2.76k, False: 1.22k]
  |  |  ------------------
  |  |  107|  2.76k|        ++iLineNumber;                                             \
  |  |  108|  2.76k|        bLastWasEndLine = true;                                    \
  |  |  109|  2.76k|    } else                                                         \
  |  |  110|  77.5k|        bLastWasEndLine = false;                                   \
  |  |  111|  77.5k|    ++mFilePtr;
  ------------------
 1336|   155k|    }
 1337|     39|}
_ZN6Assimp3ASE6Parser24ParseLV3MeshWeightsBlockERNS0_4MeshE:
 1339|      1|void Parser::ParseLV3MeshWeightsBlock(ASE::Mesh &mesh) {
 1340|      1|    AI_ASE_PARSER_INIT();
  ------------------
  |  |   63|      1|    int iDepth = 0;
  ------------------
 1341|       |
 1342|      1|    unsigned int iNumVertices = 0, iNumBones = 0;
 1343|     41|    while (true) {
  ------------------
  |  Branch (1343:12): [True: 41, Folded]
  ------------------
 1344|     41|        if ('*' == *mFilePtr) {
  ------------------
  |  Branch (1344:13): [True: 1, False: 40]
  ------------------
 1345|      1|            ++mFilePtr;
 1346|       |
 1347|       |            // Number of bone vertices ...
 1348|      1|            if (TokenMatch(mFilePtr, "MESH_NUMVERTEX", 14)) {
  ------------------
  |  Branch (1348:17): [True: 0, False: 1]
  ------------------
 1349|      0|                ParseLV4MeshLong(iNumVertices);
 1350|      0|                continue;
 1351|      0|            }
 1352|       |            // Number of bones
 1353|      1|            if (TokenMatch(mFilePtr, "MESH_NUMBONE", 12)) {
  ------------------
  |  Branch (1353:17): [True: 0, False: 1]
  ------------------
 1354|      0|                ParseLV4MeshLong(iNumBones);
 1355|      0|                continue;
 1356|      0|            }
 1357|       |            // parse the list of bones
 1358|      1|            if (TokenMatch(mFilePtr, "MESH_BONE_LIST", 14)) {
  ------------------
  |  Branch (1358:17): [True: 0, False: 1]
  ------------------
 1359|      0|                ParseLV4MeshBones(iNumBones, mesh);
 1360|      0|                continue;
 1361|      0|            }
 1362|       |            // parse the list of bones vertices
 1363|      1|            if (TokenMatch(mFilePtr, "MESH_BONE_VERTEX_LIST", 21)) {
  ------------------
  |  Branch (1363:17): [True: 0, False: 1]
  ------------------
 1364|      0|                ParseLV4MeshBonesVertices(iNumVertices, mesh);
 1365|      0|                continue;
 1366|      0|            }
 1367|      1|        }
 1368|     81|        AI_ASE_HANDLE_SECTION("3", "*MESH_WEIGHTS");
  ------------------
  |  |   94|     41|    if ('{' == *mFilePtr)                                          \
  |  |  ------------------
  |  |  |  Branch (94:9): [True: 1, False: 40]
  |  |  ------------------
  |  |   95|     41|        iDepth++;                                                  \
  |  |   96|     41|    else if ('}' == *mFilePtr) {                                   \
  |  |  ------------------
  |  |  |  Branch (96:14): [True: 1, False: 39]
  |  |  ------------------
  |  |   97|      1|        if (0 == --iDepth) {                                       \
  |  |  ------------------
  |  |  |  Branch (97:13): [True: 1, False: 0]
  |  |  ------------------
  |  |   98|      1|            ++mFilePtr;                                            \
  |  |   99|      1|            SkipToNextToken();                                     \
  |  |  100|      1|            return;                                                \
  |  |  101|      1|        }                                                          \
  |  |  102|     39|    } else if ('\0' == *mFilePtr) {                                \
  |  |  ------------------
  |  |  |  Branch (102:16): [True: 0, False: 39]
  |  |  ------------------
  |  |  103|      0|        LogError("Encountered unexpected EOL while parsing a " msg \
  |  |  104|      0|                 " chunk (Level " level ")");                      \
  |  |  105|      0|    }                                                              \
  |  |  106|     41|    if (IsLineEnd(*mFilePtr) && !bLastWasEndLine) {                \
  |  |  ------------------
  |  |  |  Branch (106:9): [True: 2, False: 38]
  |  |  |  Branch (106:33): [True: 1, False: 1]
  |  |  ------------------
  |  |  107|      1|        ++iLineNumber;                                             \
  |  |  108|      1|        bLastWasEndLine = true;                                    \
  |  |  109|      1|    } else                                                         \
  |  |  110|     40|        bLastWasEndLine = false;                                   \
  |  |  111|     40|    ++mFilePtr;
  ------------------
 1369|     81|    }
 1370|      1|}
_ZN6Assimp3ASE6Parser27ParseLV3MeshVertexListBlockEjRNS0_4MeshE:
 1445|     48|        unsigned int iNumVertices, ASE::Mesh &mesh) {
 1446|     48|    AI_ASE_PARSER_INIT();
  ------------------
  |  |   63|     48|    int iDepth = 0;
  ------------------
 1447|       |
 1448|       |    // allocate enough storage in the array
 1449|     48|    mesh.mPositions.resize(iNumVertices);
 1450|   129k|    while (true) {
  ------------------
  |  Branch (1450:12): [True: 129k, Folded]
  ------------------
 1451|   129k|        if ('*' == *mFilePtr) {
  ------------------
  |  Branch (1451:13): [True: 2.70k, False: 127k]
  ------------------
 1452|  2.70k|            ++mFilePtr;
 1453|       |
 1454|       |            // Vertex entry
 1455|  2.70k|            if (TokenMatch(mFilePtr, "MESH_VERTEX", 11)) {
  ------------------
  |  Branch (1455:17): [True: 267, False: 2.43k]
  ------------------
 1456|       |
 1457|    267|                aiVector3D vTemp;
 1458|    267|                unsigned int iIndex;
 1459|    267|                ParseLV4MeshRealTriple(&vTemp.x, iIndex);
 1460|       |
 1461|    267|                if (iIndex >= iNumVertices) {
  ------------------
  |  Branch (1461:21): [True: 0, False: 267]
  ------------------
 1462|      0|                    LogWarning("Invalid vertex index. It will be ignored");
 1463|      0|                } else
 1464|    267|                    mesh.mPositions[iIndex] = vTemp;
 1465|    267|                continue;
 1466|    267|            }
 1467|  2.70k|        }
 1468|   259k|        AI_ASE_HANDLE_SECTION("3", "*MESH_VERTEX_LIST");
  ------------------
  |  |   94|   129k|    if ('{' == *mFilePtr)                                          \
  |  |  ------------------
  |  |  |  Branch (94:9): [True: 77, False: 129k]
  |  |  ------------------
  |  |   95|   129k|        iDepth++;                                                  \
  |  |   96|   129k|    else if ('}' == *mFilePtr) {                                   \
  |  |  ------------------
  |  |  |  Branch (96:14): [True: 77, False: 129k]
  |  |  ------------------
  |  |   97|     77|        if (0 == --iDepth) {                                       \
  |  |  ------------------
  |  |  |  Branch (97:13): [True: 48, False: 29]
  |  |  ------------------
  |  |   98|     48|            ++mFilePtr;                                            \
  |  |   99|     48|            SkipToNextToken();                                     \
  |  |  100|     48|            return;                                                \
  |  |  101|     48|        }                                                          \
  |  |  102|   129k|    } else if ('\0' == *mFilePtr) {                                \
  |  |  ------------------
  |  |  |  Branch (102:16): [True: 0, False: 129k]
  |  |  ------------------
  |  |  103|      0|        LogError("Encountered unexpected EOL while parsing a " msg \
  |  |  104|      0|                 " chunk (Level " level ")");                      \
  |  |  105|      0|    }                                                              \
  |  |  106|   129k|    if (IsLineEnd(*mFilePtr) && !bLastWasEndLine) {                \
  |  |  ------------------
  |  |  |  Branch (106:9): [True: 2.39k, False: 127k]
  |  |  |  Branch (106:33): [True: 2.37k, False: 17]
  |  |  ------------------
  |  |  107|  2.37k|        ++iLineNumber;                                             \
  |  |  108|  2.37k|        bLastWasEndLine = true;                                    \
  |  |  109|  2.37k|    } else                                                         \
  |  |  110|   129k|        bLastWasEndLine = false;                                   \
  |  |  111|   129k|    ++mFilePtr;
  ------------------
 1469|   259k|    }
 1470|     48|}
_ZN6Assimp3ASE6Parser25ParseLV3MeshFaceListBlockEjRNS0_4MeshE:
 1472|     22|void Parser::ParseLV3MeshFaceListBlock(unsigned int iNumFaces, ASE::Mesh &mesh) {
 1473|     22|    AI_ASE_PARSER_INIT();
  ------------------
  |  |   63|     22|    int iDepth = 0;
  ------------------
 1474|       |
 1475|       |    // allocate enough storage in the face array
 1476|     22|    mesh.mFaces.resize(iNumFaces);
 1477|  50.0k|    while (true) {
  ------------------
  |  Branch (1477:12): [True: 50.0k, Folded]
  ------------------
 1478|  50.0k|        if ('*' == *mFilePtr) {
  ------------------
  |  Branch (1478:13): [True: 2.95k, False: 47.0k]
  ------------------
 1479|  2.95k|            ++mFilePtr;
 1480|       |
 1481|       |            // Face entry
 1482|  2.95k|            if (TokenMatch(mFilePtr, "MESH_FACE", 9)) {
  ------------------
  |  Branch (1482:17): [True: 852, False: 2.09k]
  ------------------
 1483|       |
 1484|    852|                ASE::Face mFace;
 1485|    852|                ParseLV4MeshFace(mFace);
 1486|       |
 1487|    852|                if (mFace.iFace >= iNumFaces) {
  ------------------
  |  Branch (1487:21): [True: 578, False: 274]
  ------------------
 1488|    578|                    LogWarning("Face has an invalid index. It will be ignored");
 1489|    578|                } else
 1490|    274|                    mesh.mFaces[mFace.iFace] = mFace;
 1491|    852|                continue;
 1492|    852|            }
 1493|  2.95k|        }
 1494|  98.3k|        AI_ASE_HANDLE_SECTION("3", "*MESH_FACE_LIST");
  ------------------
  |  |   94|  49.1k|    if ('{' == *mFilePtr)                                          \
  |  |  ------------------
  |  |  |  Branch (94:9): [True: 372, False: 48.8k]
  |  |  ------------------
  |  |   95|  49.1k|        iDepth++;                                                  \
  |  |   96|  49.1k|    else if ('}' == *mFilePtr) {                                   \
  |  |  ------------------
  |  |  |  Branch (96:14): [True: 1.06k, False: 47.7k]
  |  |  ------------------
  |  |   97|  1.06k|        if (0 == --iDepth) {                                       \
  |  |  ------------------
  |  |  |  Branch (97:13): [True: 18, False: 1.04k]
  |  |  ------------------
  |  |   98|     18|            ++mFilePtr;                                            \
  |  |   99|     18|            SkipToNextToken();                                     \
  |  |  100|     18|            return;                                                \
  |  |  101|     18|        }                                                          \
  |  |  102|  47.7k|    } else if ('\0' == *mFilePtr) {                                \
  |  |  ------------------
  |  |  |  Branch (102:16): [True: 4, False: 47.7k]
  |  |  ------------------
  |  |  103|      4|        LogError("Encountered unexpected EOL while parsing a " msg \
  |  |  104|      4|                 " chunk (Level " level ")");                      \
  |  |  105|      4|    }                                                              \
  |  |  106|  49.1k|    if (IsLineEnd(*mFilePtr) && !bLastWasEndLine) {                \
  |  |  ------------------
  |  |  |  Branch (106:9): [True: 2.33k, False: 46.8k]
  |  |  |  Branch (106:33): [True: 2.08k, False: 246]
  |  |  ------------------
  |  |  107|  2.08k|        ++iLineNumber;                                             \
  |  |  108|  2.08k|        bLastWasEndLine = true;                                    \
  |  |  109|  2.08k|    } else                                                         \
  |  |  110|  49.1k|        bLastWasEndLine = false;                                   \
  |  |  111|  49.1k|    ++mFilePtr;
  ------------------
 1495|  98.3k|    }
 1496|     22|}
_ZN6Assimp3ASE6Parser22ParseLV3MeshTListBlockEjRNS0_4MeshEj:
 1499|     22|        ASE::Mesh &mesh, unsigned int iChannel) {
 1500|     22|    AI_ASE_PARSER_INIT();
  ------------------
  |  |   63|     22|    int iDepth = 0;
  ------------------
 1501|       |
 1502|       |    // allocate enough storage in the array
 1503|     22|    mesh.amTexCoords[iChannel].resize(iNumVertices);
 1504|  1.77k|    while (true) {
  ------------------
  |  Branch (1504:12): [True: 1.77k, Folded]
  ------------------
 1505|  1.77k|        if ('*' == *mFilePtr) {
  ------------------
  |  Branch (1505:13): [True: 333, False: 1.44k]
  ------------------
 1506|    333|            ++mFilePtr;
 1507|       |
 1508|       |            // Vertex entry
 1509|    333|            if (TokenMatch(mFilePtr, "MESH_TVERT", 10)) {
  ------------------
  |  Branch (1509:17): [True: 333, False: 0]
  ------------------
 1510|    333|                aiVector3D vTemp;
 1511|    333|                unsigned int iIndex;
 1512|    333|                ParseLV4MeshRealTriple(&vTemp.x, iIndex);
 1513|       |
 1514|    333|                if (iIndex >= iNumVertices) {
  ------------------
  |  Branch (1514:21): [True: 0, False: 333]
  ------------------
 1515|      0|                    LogWarning("Tvertex has an invalid index. It will be ignored");
 1516|      0|                } else
 1517|    333|                    mesh.amTexCoords[iChannel][iIndex] = vTemp;
 1518|       |
 1519|    333|                if (0.0f != vTemp.z) {
  ------------------
  |  Branch (1519:21): [True: 0, False: 333]
  ------------------
 1520|       |                    // we need 3 coordinate channels
 1521|      0|                    mesh.mNumUVComponents[iChannel] = 3;
 1522|      0|                }
 1523|    333|                continue;
 1524|    333|            }
 1525|    333|        }
 1526|  2.86k|        AI_ASE_HANDLE_SECTION("3", "*MESH_TVERT_LIST");
  ------------------
  |  |   94|  1.44k|    if ('{' == *mFilePtr)                                          \
  |  |  ------------------
  |  |  |  Branch (94:9): [True: 22, False: 1.42k]
  |  |  ------------------
  |  |   95|  1.44k|        iDepth++;                                                  \
  |  |   96|  1.44k|    else if ('}' == *mFilePtr) {                                   \
  |  |  ------------------
  |  |  |  Branch (96:14): [True: 22, False: 1.39k]
  |  |  ------------------
  |  |   97|     22|        if (0 == --iDepth) {                                       \
  |  |  ------------------
  |  |  |  Branch (97:13): [True: 22, False: 0]
  |  |  ------------------
  |  |   98|     22|            ++mFilePtr;                                            \
  |  |   99|     22|            SkipToNextToken();                                     \
  |  |  100|     22|            return;                                                \
  |  |  101|     22|        }                                                          \
  |  |  102|  1.39k|    } else if ('\0' == *mFilePtr) {                                \
  |  |  ------------------
  |  |  |  Branch (102:16): [True: 0, False: 1.39k]
  |  |  ------------------
  |  |  103|      0|        LogError("Encountered unexpected EOL while parsing a " msg \
  |  |  104|      0|                 " chunk (Level " level ")");                      \
  |  |  105|      0|    }                                                              \
  |  |  106|  1.44k|    if (IsLineEnd(*mFilePtr) && !bLastWasEndLine) {                \
  |  |  ------------------
  |  |  |  Branch (106:9): [True: 355, False: 1.06k]
  |  |  |  Branch (106:33): [True: 355, False: 0]
  |  |  ------------------
  |  |  107|    355|        ++iLineNumber;                                             \
  |  |  108|    355|        bLastWasEndLine = true;                                    \
  |  |  109|    355|    } else                                                         \
  |  |  110|  1.42k|        bLastWasEndLine = false;                                   \
  |  |  111|  1.42k|    ++mFilePtr;
  ------------------
 1527|  2.86k|    }
 1528|     22|}
_ZN6Assimp3ASE6Parser26ParseLV3MeshTFaceListBlockEjRNS0_4MeshEj:
 1531|     24|        ASE::Mesh &mesh, unsigned int iChannel) {
 1532|     24|    AI_ASE_PARSER_INIT();
  ------------------
  |  |   63|     24|    int iDepth = 0;
  ------------------
 1533|  40.5k|    while (true) {
  ------------------
  |  Branch (1533:12): [True: 40.5k, Folded]
  ------------------
 1534|  40.5k|        if ('*' == *mFilePtr) {
  ------------------
  |  Branch (1534:13): [True: 2.41k, False: 38.1k]
  ------------------
 1535|  2.41k|            ++mFilePtr;
 1536|       |
 1537|       |            // Face entry
 1538|  2.41k|            if (TokenMatch(mFilePtr, "MESH_TFACE", 10)) {
  ------------------
  |  Branch (1538:17): [True: 549, False: 1.86k]
  ------------------
 1539|    549|                unsigned int aiValues[3];
 1540|    549|                unsigned int iIndex = 0;
 1541|       |
 1542|    549|                ParseLV4MeshLongTriple(aiValues, iIndex);
 1543|    549|                if (iIndex >= iNumFaces || iIndex >= mesh.mFaces.size()) {
  ------------------
  |  Branch (1543:21): [True: 254, False: 295]
  |  Branch (1543:44): [True: 79, False: 216]
  ------------------
 1544|    333|                    LogWarning("UV-Face has an invalid index. It will be ignored");
 1545|    333|                } else {
 1546|       |                    // copy UV indices
 1547|    216|                    mesh.mFaces[iIndex].amUVIndices[iChannel][0] = aiValues[0];
 1548|    216|                    mesh.mFaces[iIndex].amUVIndices[iChannel][1] = aiValues[1];
 1549|    216|                    mesh.mFaces[iIndex].amUVIndices[iChannel][2] = aiValues[2];
 1550|    216|                }
 1551|    549|                continue;
 1552|    549|            }
 1553|  2.41k|        }
 1554|  79.9k|        AI_ASE_HANDLE_SECTION("3", "*MESH_TFACE_LIST");
  ------------------
  |  |   94|  39.9k|    if ('{' == *mFilePtr)                                          \
  |  |  ------------------
  |  |  |  Branch (94:9): [True: 22, False: 39.9k]
  |  |  ------------------
  |  |   95|  39.9k|        iDepth++;                                                  \
  |  |   96|  39.9k|    else if ('}' == *mFilePtr) {                                   \
  |  |  ------------------
  |  |  |  Branch (96:14): [True: 22, False: 39.9k]
  |  |  ------------------
  |  |   97|     22|        if (0 == --iDepth) {                                       \
  |  |  ------------------
  |  |  |  Branch (97:13): [True: 22, False: 0]
  |  |  ------------------
  |  |   98|     22|            ++mFilePtr;                                            \
  |  |   99|     22|            SkipToNextToken();                                     \
  |  |  100|     22|            return;                                                \
  |  |  101|     22|        }                                                          \
  |  |  102|  39.9k|    } else if ('\0' == *mFilePtr) {                                \
  |  |  ------------------
  |  |  |  Branch (102:16): [True: 2, False: 39.9k]
  |  |  ------------------
  |  |  103|      2|        LogError("Encountered unexpected EOL while parsing a " msg \
  |  |  104|      2|                 " chunk (Level " level ")");                      \
  |  |  105|      2|    }                                                              \
  |  |  106|  39.9k|    if (IsLineEnd(*mFilePtr) && !bLastWasEndLine) {                \
  |  |  ------------------
  |  |  |  Branch (106:9): [True: 3.88k, False: 36.0k]
  |  |  |  Branch (106:33): [True: 2.60k, False: 1.27k]
  |  |  ------------------
  |  |  107|  2.60k|        ++iLineNumber;                                             \
  |  |  108|  2.60k|        bLastWasEndLine = true;                                    \
  |  |  109|  2.60k|    } else                                                         \
  |  |  110|  39.9k|        bLastWasEndLine = false;                                   \
  |  |  111|  39.9k|    ++mFilePtr;
  ------------------
 1555|  79.9k|    }
 1556|     24|}
_ZN6Assimp3ASE6Parser27ParseLV3MeshNormalListBlockERNS0_4MeshE:
 1646|     21|void Parser::ParseLV3MeshNormalListBlock(ASE::Mesh &sMesh) {
 1647|     21|    AI_ASE_PARSER_INIT();
  ------------------
  |  |   63|     21|    int iDepth = 0;
  ------------------
 1648|       |
 1649|       |    // Allocate enough storage for the normals
 1650|     21|    sMesh.mNormals.resize(sMesh.mFaces.size() * 3, aiVector3D(0.f, 0.f, 0.f));
 1651|     21|    unsigned int index, faceIdx = UINT_MAX;
 1652|       |
 1653|       |    // FIXME: rewrite this and find out how to interpret the normals
 1654|       |    // correctly. This is crap.
 1655|       |
 1656|       |    // Smooth the vertex and face normals together. The result
 1657|       |    // will be edgy then, but otherwise everything would be soft ...
 1658|  55.5k|    while (true) {
  ------------------
  |  Branch (1658:12): [True: 55.5k, Folded]
  ------------------
 1659|  55.5k|        if ('*' == *mFilePtr) {
  ------------------
  |  Branch (1659:13): [True: 1.83k, False: 53.7k]
  ------------------
 1660|  1.83k|            ++mFilePtr;
 1661|  1.83k|            if (faceIdx != UINT_MAX && TokenMatch(mFilePtr, "MESH_VERTEXNORMAL", 17)) {
  ------------------
  |  Branch (1661:17): [True: 1.81k, False: 21]
  |  Branch (1661:40): [True: 673, False: 1.14k]
  ------------------
 1662|    673|                aiVector3D vNormal;
 1663|    673|                ParseLV4MeshRealTriple(&vNormal.x, index);
 1664|    673|                if (faceIdx >= sMesh.mFaces.size())
  ------------------
  |  Branch (1664:21): [True: 17, False: 656]
  ------------------
 1665|     17|                    continue;
 1666|       |
 1667|       |                // Make sure we assign it to the correct face
 1668|    656|                const ASE::Face &face = sMesh.mFaces[faceIdx];
 1669|    656|                if (index == face.mIndices[0])
  ------------------
  |  Branch (1669:21): [True: 214, False: 442]
  ------------------
 1670|    214|                    index = 0;
 1671|    442|                else if (index == face.mIndices[1])
  ------------------
  |  Branch (1671:26): [True: 214, False: 228]
  ------------------
 1672|    214|                    index = 1;
 1673|    228|                else if (index == face.mIndices[2])
  ------------------
  |  Branch (1673:26): [True: 212, False: 16]
  ------------------
 1674|    212|                    index = 2;
 1675|     16|                else {
 1676|     16|                    ASSIMP_LOG_ERROR("ASE: Invalid vertex index in MESH_VERTEXNORMAL section");
 1677|     16|                    continue;
 1678|     16|                }
 1679|       |                // We'll renormalize later
 1680|    640|                sMesh.mNormals[faceIdx * 3 + index] += vNormal;
 1681|    640|                continue;
 1682|    656|            }
 1683|  1.16k|            if (TokenMatch(mFilePtr, "MESH_FACENORMAL", 15)) {
  ------------------
  |  Branch (1683:17): [True: 671, False: 491]
  ------------------
 1684|    671|                aiVector3D vNormal;
 1685|    671|                ParseLV4MeshRealTriple(&vNormal.x, faceIdx);
 1686|       |
 1687|    671|                if (faceIdx >= sMesh.mFaces.size()) {
  ------------------
  |  Branch (1687:21): [True: 450, False: 221]
  ------------------
 1688|    450|                    ASSIMP_LOG_ERROR("ASE: Invalid vertex index in MESH_FACENORMAL section");
 1689|    450|                    continue;
 1690|    450|                }
 1691|       |
 1692|       |                // We'll renormalize later
 1693|    221|                sMesh.mNormals[faceIdx * 3] += vNormal;
 1694|    221|                sMesh.mNormals[faceIdx * 3 + 1] += vNormal;
 1695|    221|                sMesh.mNormals[faceIdx * 3 + 2] += vNormal;
 1696|    221|                continue;
 1697|    671|            }
 1698|  1.16k|        }
 1699|   108k|        AI_ASE_HANDLE_SECTION("3", "*MESH_NORMALS");
  ------------------
  |  |   94|  54.2k|    if ('{' == *mFilePtr)                                          \
  |  |  ------------------
  |  |  |  Branch (94:9): [True: 22, False: 54.2k]
  |  |  ------------------
  |  |   95|  54.2k|        iDepth++;                                                  \
  |  |   96|  54.2k|    else if ('}' == *mFilePtr) {                                   \
  |  |  ------------------
  |  |  |  Branch (96:14): [True: 16, False: 54.1k]
  |  |  ------------------
  |  |   97|     16|        if (0 == --iDepth) {                                       \
  |  |  ------------------
  |  |  |  Branch (97:13): [True: 15, False: 1]
  |  |  ------------------
  |  |   98|     15|            ++mFilePtr;                                            \
  |  |   99|     15|            SkipToNextToken();                                     \
  |  |  100|     15|            return;                                                \
  |  |  101|     15|        }                                                          \
  |  |  102|  54.1k|    } else if ('\0' == *mFilePtr) {                                \
  |  |  ------------------
  |  |  |  Branch (102:16): [True: 3, False: 54.1k]
  |  |  ------------------
  |  |  103|      3|        LogError("Encountered unexpected EOL while parsing a " msg \
  |  |  104|      3|                 " chunk (Level " level ")");                      \
  |  |  105|      3|    }                                                              \
  |  |  106|  54.2k|    if (IsLineEnd(*mFilePtr) && !bLastWasEndLine) {                \
  |  |  ------------------
  |  |  |  Branch (106:9): [True: 1.84k, False: 52.3k]
  |  |  |  Branch (106:33): [True: 1.84k, False: 0]
  |  |  ------------------
  |  |  107|  1.84k|        ++iLineNumber;                                             \
  |  |  108|  1.84k|        bLastWasEndLine = true;                                    \
  |  |  109|  1.84k|    } else                                                         \
  |  |  110|  54.2k|        bLastWasEndLine = false;                                   \
  |  |  111|  54.2k|    ++mFilePtr;
  ------------------
 1700|   108k|    }
 1701|     21|}
_ZN6Assimp3ASE6Parser16ParseLV4MeshFaceERNS0_4FaceE:
 1703|    852|void Parser::ParseLV4MeshFace(ASE::Face &out) {
 1704|       |    // skip spaces and tabs
 1705|    852|    if (!SkipSpaces(&mFilePtr, mEnd)) {
  ------------------
  |  Branch (1705:9): [True: 11, False: 841]
  ------------------
 1706|     11|        LogWarning("Unable to parse *MESH_FACE Element: Unexpected EOL [#1]");
 1707|     11|        SkipToNextToken();
 1708|     11|        return;
 1709|     11|    }
 1710|       |
 1711|       |    // parse the face index
 1712|    841|    out.iFace = strtoul10(mFilePtr, &mFilePtr);
 1713|       |
 1714|       |    // next character should be ':'
 1715|    841|    if (!SkipSpaces(&mFilePtr, mEnd)) {
  ------------------
  |  Branch (1715:9): [True: 0, False: 841]
  ------------------
 1716|       |        // FIX: there are some ASE files which haven't got : here ....
 1717|      0|        LogWarning("Unable to parse *MESH_FACE Element: Unexpected EOL. \':\' expected [#2]");
 1718|      0|        SkipToNextToken();
 1719|      0|        return;
 1720|      0|    }
 1721|       |    // FIX: There are some ASE files which haven't got ':' here
 1722|    841|    if (':' == *mFilePtr) ++mFilePtr;
  ------------------
  |  Branch (1722:9): [True: 273, False: 568]
  ------------------
 1723|       |
 1724|       |    // Parse all mesh indices
 1725|  2.13k|    for (unsigned int i = 0; i < 3; ++i) {
  ------------------
  |  Branch (1725:30): [True: 1.80k, False: 328]
  ------------------
 1726|  1.80k|        unsigned int iIndex = 0;
 1727|  1.80k|        if (!SkipSpaces(&mFilePtr, mEnd)) {
  ------------------
  |  Branch (1727:13): [True: 53, False: 1.75k]
  ------------------
 1728|     53|            LogWarning("Unable to parse *MESH_FACE Element: Unexpected EOL");
 1729|     53|            SkipToNextToken();
 1730|     53|            return;
 1731|     53|        }
 1732|  1.75k|        switch (*mFilePtr) {
 1733|    807|        case 'A':
  ------------------
  |  Branch (1733:9): [True: 807, False: 947]
  ------------------
 1734|    816|        case 'a':
  ------------------
  |  Branch (1734:9): [True: 9, False: 1.74k]
  ------------------
 1735|    816|            break;
 1736|    336|        case 'B':
  ------------------
  |  Branch (1736:9): [True: 336, False: 1.41k]
  ------------------
 1737|    432|        case 'b':
  ------------------
  |  Branch (1737:9): [True: 96, False: 1.65k]
  ------------------
 1738|    432|            iIndex = 1;
 1739|    432|            break;
 1740|    280|        case 'C':
  ------------------
  |  Branch (1740:9): [True: 280, False: 1.47k]
  ------------------
 1741|    355|        case 'c':
  ------------------
  |  Branch (1741:9): [True: 75, False: 1.67k]
  ------------------
 1742|    355|            iIndex = 2;
 1743|    355|            break;
 1744|    151|        default:
  ------------------
  |  Branch (1744:9): [True: 151, False: 1.60k]
  ------------------
 1745|    151|            LogWarning("Unable to parse *MESH_FACE Element: Unexpected EOL. "
 1746|    151|                       "A,B or C expected [#3]");
 1747|    151|            SkipToNextToken();
 1748|    151|            return;
 1749|  1.75k|        };
 1750|  1.60k|        ++mFilePtr;
 1751|       |
 1752|       |        // next character should be ':'
 1753|  1.60k|        if (!SkipSpaces(&mFilePtr, mEnd) || ':' != *mFilePtr) {
  ------------------
  |  Branch (1753:13): [True: 96, False: 1.50k]
  |  Branch (1753:45): [True: 163, False: 1.34k]
  ------------------
 1754|    259|            LogWarning("Unable to parse *MESH_FACE Element: "
 1755|    259|                       "Unexpected EOL. \':\' expected [#2]");
 1756|    259|            SkipToNextToken();
 1757|    259|            return;
 1758|    259|        }
 1759|       |
 1760|  1.34k|        ++mFilePtr;
 1761|  1.34k|        if (!SkipSpaces(&mFilePtr, mEnd)) {
  ------------------
  |  Branch (1761:13): [True: 50, False: 1.29k]
  ------------------
 1762|     50|            LogWarning("Unable to parse *MESH_FACE Element: Unexpected EOL. "
 1763|     50|                       "Vertex index expected [#4]");
 1764|     50|            SkipToNextToken();
 1765|     50|            return;
 1766|     50|        }
 1767|  1.29k|        out.mIndices[iIndex] = strtoul10(mFilePtr, &mFilePtr);
 1768|  1.29k|    }
 1769|       |
 1770|       |    // now we need to skip the AB, BC, CA blocks.
 1771|  8.28k|    while (true) {
  ------------------
  |  Branch (1771:12): [True: 8.28k, Folded]
  ------------------
 1772|  8.28k|        if ('*' == *mFilePtr) break;
  ------------------
  |  Branch (1772:13): [True: 328, False: 7.95k]
  ------------------
 1773|  7.95k|        if (IsLineEnd(*mFilePtr)) {
  ------------------
  |  Branch (1773:13): [True: 0, False: 7.95k]
  ------------------
 1774|       |            //iLineNumber++;
 1775|      0|            return;
 1776|      0|        }
 1777|  7.95k|        mFilePtr++;
 1778|  7.95k|    }
 1779|       |
 1780|       |    // parse the smoothing group of the face
 1781|    328|    if (TokenMatch(mFilePtr, "*MESH_SMOOTHING", 15)) {
  ------------------
  |  Branch (1781:9): [True: 312, False: 16]
  ------------------
 1782|    312|        if (!SkipSpaces(&mFilePtr, mEnd)) {
  ------------------
  |  Branch (1782:13): [True: 0, False: 312]
  ------------------
 1783|      0|            LogWarning("Unable to parse *MESH_SMOOTHING Element: "
 1784|      0|                       "Unexpected EOL. Smoothing group(s) expected [#5]");
 1785|      0|            SkipToNextToken();
 1786|      0|            return;
 1787|      0|        }
 1788|       |
 1789|       |        // Parse smoothing groups until we don't anymore see commas
 1790|       |        // FIX: There needn't always be a value, sad but true
 1791|    336|        while (true) {
  ------------------
  |  Branch (1791:16): [True: 336, Folded]
  ------------------
 1792|    336|            if (*mFilePtr < '9' && *mFilePtr >= '0') {
  ------------------
  |  Branch (1792:17): [True: 321, False: 15]
  |  Branch (1792:36): [True: 287, False: 34]
  ------------------
 1793|    287|                uint32_t value = strtoul10(mFilePtr, &mFilePtr);
 1794|    287|                if (value < 32) {
  ------------------
  |  Branch (1794:21): [True: 287, False: 0]
  ------------------
 1795|    287|                    out.iSmoothGroup |= (1 << strtoul10(mFilePtr, &mFilePtr));
 1796|    287|                } else {
 1797|      0|                    const std::string message = std::string("Unable to set smooth group, value with ") + ai_to_string(value) + std::string(" out of range");
 1798|      0|                    LogWarning(message.c_str());
 1799|      0|                }
 1800|    287|            }
 1801|    336|            SkipSpaces(&mFilePtr, mEnd);
 1802|    336|            if (',' != *mFilePtr) {
  ------------------
  |  Branch (1802:17): [True: 312, False: 24]
  ------------------
 1803|    312|                break;
 1804|    312|            }
 1805|     24|            ++mFilePtr;
 1806|     24|            SkipSpaces(&mFilePtr, mEnd);
 1807|     24|        }
 1808|    312|    }
 1809|       |
 1810|       |    // *MESH_MTLID  is optional, too
 1811|    534|    while (true) {
  ------------------
  |  Branch (1811:12): [True: 534, Folded]
  ------------------
 1812|    534|        if ('*' == *mFilePtr) {
  ------------------
  |  Branch (1812:13): [True: 328, False: 206]
  ------------------
 1813|    328|            break;
 1814|    328|        }
 1815|    206|        if (IsLineEnd(*mFilePtr)) {
  ------------------
  |  Branch (1815:13): [True: 0, False: 206]
  ------------------
 1816|      0|            return;
 1817|      0|        }
 1818|    206|        mFilePtr++;
 1819|    206|    }
 1820|       |
 1821|    328|    if (TokenMatch(mFilePtr, "*MESH_MTLID", 11)) {
  ------------------
  |  Branch (1821:9): [True: 287, False: 41]
  ------------------
 1822|    287|        if (!SkipSpaces(&mFilePtr, mEnd)) {
  ------------------
  |  Branch (1822:13): [True: 13, False: 274]
  ------------------
 1823|     13|            LogWarning("Unable to parse *MESH_MTLID Element: Unexpected EOL. "
 1824|     13|                       "Material index expected [#6]");
 1825|     13|            SkipToNextToken();
 1826|     13|            return;
 1827|     13|        }
 1828|    274|        out.iMaterial = strtoul10(mFilePtr, &mFilePtr);
 1829|    274|    }
 1830|    315|    return;
 1831|    328|}
_ZN6Assimp3ASE6Parser22ParseLV4MeshLongTripleEPj:
 1833|    690|void Parser::ParseLV4MeshLongTriple(unsigned int *apOut) {
 1834|    690|    ai_assert(nullptr != apOut);
 1835|       |
 1836|  2.76k|    for (unsigned int i = 0; i < 3; ++i)
  ------------------
  |  Branch (1836:30): [True: 2.07k, False: 690]
  ------------------
 1837|  2.07k|        ParseLV4MeshLong(apOut[i]);
 1838|    690|}
_ZN6Assimp3ASE6Parser22ParseLV4MeshLongTripleEPjRj:
 1840|    549|void Parser::ParseLV4MeshLongTriple(unsigned int *apOut, unsigned int &rIndexOut) {
 1841|    549|    ai_assert(nullptr != apOut);
 1842|       |
 1843|       |    // parse the index
 1844|    549|    ParseLV4MeshLong(rIndexOut);
 1845|       |
 1846|       |    // parse the three others
 1847|    549|    ParseLV4MeshLongTriple(apOut);
 1848|    549|}
_ZN6Assimp3ASE6Parser22ParseLV4MeshRealTripleEPfRj:
 1850|  4.83k|void Parser::ParseLV4MeshRealTriple(ai_real *apOut, unsigned int &rIndexOut) {
 1851|  4.83k|    ai_assert(nullptr != apOut);
 1852|       |
 1853|       |    // parse the index
 1854|  4.83k|    ParseLV4MeshLong(rIndexOut);
 1855|       |
 1856|       |    // parse the three others
 1857|  4.83k|    ParseLV4MeshRealTriple(apOut);
 1858|  4.83k|}
_ZN6Assimp3ASE6Parser22ParseLV4MeshRealTripleEPf:
 1870|  5.02k|void Parser::ParseLV4MeshRealTriple(ai_real *apOut) {
 1871|  5.02k|    ai_assert(nullptr != apOut);
 1872|       |
 1873|  20.1k|    for (unsigned int i = 0; i < 3; ++i) {
  ------------------
  |  Branch (1873:30): [True: 15.0k, False: 5.02k]
  ------------------
 1874|  15.0k|        ParseLV4MeshReal(apOut[i]);
 1875|  15.0k|    }
 1876|  5.02k|}
_ZN6Assimp3ASE6Parser23ParseLV4MeshFloatTripleEPf:
 1878|     65|void Parser::ParseLV4MeshFloatTriple(float* apOut) {
 1879|     65|    ai_assert(nullptr != apOut);
 1880|       |
 1881|    260|    for (unsigned int i = 0; i < 3; ++i) {
  ------------------
  |  Branch (1881:30): [True: 195, False: 65]
  ------------------
 1882|    195|        ParseLV4MeshFloat(apOut[i]);
 1883|    195|    }
 1884|     65|}
_ZN6Assimp3ASE6Parser16ParseLV4MeshRealERf:
 1886|  17.1k|void Parser::ParseLV4MeshReal(ai_real &fOut) {
 1887|       |    // skip spaces and tabs
 1888|  17.1k|    if (!SkipSpaces(&mFilePtr, mEnd)) {
  ------------------
  |  Branch (1888:9): [True: 3.60k, False: 13.5k]
  ------------------
 1889|       |        // LOG
 1890|  3.60k|        LogWarning("Unable to parse float: unexpected EOL [#1]");
 1891|  3.60k|        fOut = 0.0;
 1892|  3.60k|        ++iLineNumber;
 1893|  3.60k|        return;
 1894|  3.60k|    }
 1895|       |    // parse the first float
 1896|  13.5k|    mFilePtr = fast_atoreal_move(mFilePtr, fOut);
 1897|  13.5k|}
_ZN6Assimp3ASE6Parser17ParseLV4MeshFloatERf:
 1899|    195|void Parser::ParseLV4MeshFloat(float &fOut) {
 1900|       |    // skip spaces and tabs
 1901|    195|    if (!SkipSpaces(&mFilePtr, mEnd)) {
  ------------------
  |  Branch (1901:9): [True: 0, False: 195]
  ------------------
 1902|       |        // LOG
 1903|      0|        LogWarning("Unable to parse float: unexpected EOL [#1]");
 1904|      0|        fOut = 0.0;
 1905|      0|        ++iLineNumber;
 1906|      0|        return;
 1907|      0|    }
 1908|       |    // parse the first float
 1909|    195|    mFilePtr = fast_atoreal_move(mFilePtr, fOut);
 1910|    195|}
_ZN6Assimp3ASE6Parser16ParseLV4MeshLongERj:
 1912|  7.78k|void Parser::ParseLV4MeshLong(unsigned int &iOut) {
 1913|       |    // Skip spaces and tabs
 1914|  7.78k|    if (!SkipSpaces(&mFilePtr, mEnd)) {
  ------------------
  |  Branch (1914:9): [True: 1.78k, False: 5.99k]
  ------------------
 1915|       |        // LOG
 1916|  1.78k|        LogWarning("Unable to parse long: unexpected EOL [#1]");
 1917|  1.78k|        iOut = 0;
 1918|  1.78k|        ++iLineNumber;
 1919|  1.78k|        return;
 1920|  1.78k|    }
 1921|       |    // parse the value
 1922|  5.99k|    iOut = strtoul10(mFilePtr, &mFilePtr);
 1923|  5.99k|}

_ZN6Assimp3ASE8MaterialC2ERKNSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEE:
   72|     50|            D3DS::Material(name),
   73|     50|            pcInstance(nullptr),
   74|     50|            bNeed(false) {
   75|       |        // empty
   76|     50|    }
_ZN6Assimp3ASE4FaceC2Ev:
  134|  1.12k|            : iMaterial(DEFAULT_MATINDEX),
  135|  1.12k|              iFace(0) {
  136|       |        // empty
  137|  1.12k|    }
_ZN6Assimp3ASE9AnimationC2Ev:
  194|    108|            : mRotationType(TRACK),
  195|    108|              mScalingType(TRACK),
  196|    108|              mPositionType(TRACK) {
  197|       |        // empty
  198|    108|    }
_ZN6Assimp3ASE15InheritanceInfoC2Ev:
  214|     54|    InheritanceInfo() AI_NO_EXCEPT {
  215|    216|        for (size_t i = 0; i < 3; ++i) {
  ------------------
  |  Branch (215:28): [True: 162, False: 54]
  ------------------
  216|    162|            abInheritPosition[i] = abInheritRotation[i] = abInheritScaling[i] = true;
  217|    162|        }
  218|     54|    }
_ZN6Assimp3ASE8BaseNodeC2ENS1_4TypeERKNSt3__112basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEE:
  242|     54|            mType(_mType), mName(name), mProcessed(false) {
  243|       |        // Set mTargetPosition to qnan
  244|     54|        const ai_real qnan = get_qnan();
  245|     54|        mTargetPosition.x = qnan;
  246|     54|    }
_ZN6Assimp3ASE4MeshC2ERKNSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEE:
  283|     41|            BaseNode(BaseNode::Mesh, name), mVertexColors(), mBoneVertices(), mBones(), iMaterialIndex(Face::DEFAULT_MATINDEX), bSkip(false) {
  284|    369|        for (unsigned int c = 0; c < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++c) {
  ------------------
  |  Branch (284:34): [True: 328, False: 41]
  ------------------
  285|    328|            this->mNumUVComponents[c] = 2;
  286|    328|        }
  287|     41|    }
_ZN6Assimp3ASE5LightC2ERKNSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEE:
  326|      5|            BaseNode(BaseNode::Light, name), mLightType(OMNI), mColor(1.f, 1.f, 1.f), mIntensity(1.f) // light is white by default
  327|       |            ,
  328|      5|            mAngle(45.f),
  329|      5|            mFalloff(0.f) {
  330|      5|    }
_ZN6Assimp3ASE6CameraC2ERKNSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEE:
  352|      8|            BaseNode(BaseNode::Camera, name), mFOV(0.75f) // in radians
  353|       |            ,
  354|      8|            mNear(0.1f),
  355|      8|            mFar(1000.f) // could be zero
  356|       |            ,
  357|      8|            mCameraType(FREE) {
  358|      8|    }
_ZN6Assimp3ASE8MaterialD2Ev:
  117|     77|    ~Material() override = default;
_ZN6Assimp3ASE8MaterialC2ERKS1_:
   78|     27|    Material(const Material &other) = default;

_ZNK6Assimp14AssbinImporter7GetInfoEv:
   82|    634|const aiImporterDesc *AssbinImporter::GetInfo() const {
   83|    634|    return &desc;
   84|    634|}
_ZNK6Assimp14AssbinImporter7CanReadERKNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEPNS_8IOSystemEb:
   87|     49|bool AssbinImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool /*checkSig*/) const {
   88|     49|    IOStream *in = pIOHandler->Open(pFile);
   89|     49|    if (nullptr == in) {
  ------------------
  |  Branch (89:9): [True: 0, False: 49]
  ------------------
   90|      0|        return false;
   91|      0|    }
   92|       |
   93|     49|    char s[32];
   94|     49|    const size_t read = in->Read(s, sizeof(char), 32);
   95|       |
   96|     49|    pIOHandler->Close(in);
   97|       |
   98|     49|    if (read < 19) {
  ------------------
  |  Branch (98:9): [True: 0, False: 49]
  ------------------
   99|      0|      return false;
  100|      0|    }
  101|       |
  102|     49|    return strncmp(s, "ASSIMP.binary-dump.", 19) == 0;
  103|     49|}

_ZN6Assimp11B3DImporterD2Ev:
   91|    624|B3DImporter::~B3DImporter() = default;
_ZNK6Assimp11B3DImporter7CanReadERKNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEPNS_8IOSystemEb:
   94|    320|bool B3DImporter::CanRead(const std::string &pFile, IOSystem * /*pIOHandler*/, bool /*checkSig*/) const {
   95|    320|    size_t pos = pFile.find_last_of('.');
   96|    320|    if (pos == string::npos) {
  ------------------
  |  Branch (96:9): [True: 17, False: 303]
  ------------------
   97|     17|        return false;
   98|     17|    }
   99|       |
  100|    303|    string ext = pFile.substr(pos + 1);
  101|    303|    if (ext.size() != 3) {
  ------------------
  |  Branch (101:9): [True: 303, False: 0]
  ------------------
  102|    303|        return false;
  103|    303|    }
  104|       |
  105|      0|    return (ext[0] == 'b' || ext[0] == 'B') && (ext[1] == '3') && (ext[2] == 'd' || ext[2] == 'D');
  ------------------
  |  Branch (105:13): [True: 0, False: 0]
  |  Branch (105:30): [True: 0, False: 0]
  |  Branch (105:48): [True: 0, False: 0]
  |  Branch (105:68): [True: 0, False: 0]
  |  Branch (105:85): [True: 0, False: 0]
  ------------------
  106|    303|}
_ZNK6Assimp11B3DImporter7GetInfoEv:
  110|    634|const aiImporterDesc *B3DImporter::GetInfo() const {
  111|    634|    return &desc;
  112|    634|}

_ZN6Assimp11B3DImporterC2Ev:
   66|    624|    B3DImporter() = default;

_ZN6Assimp9BVHLoaderC2Ev:
   86|    624|        noSkeletonMesh() {
   87|       |    // empty
   88|    624|}
_ZNK6Assimp9BVHLoader7CanReadERKNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEPNS_8IOSystemEb:
   92|    347|bool BVHLoader::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool /*checkSig*/) const {
   93|    347|    static const char *tokens[] = { "HIERARCHY" };
   94|       |    return SearchFileHeaderForToken(pIOHandler, pFile, tokens, AI_COUNT_OF(tokens));
   95|    347|}
_ZNK6Assimp9BVHLoader7GetInfoEv:
  104|    634|const aiImporterDesc *BVHLoader::GetInfo() const {
  105|    634|    return &desc;
  106|    634|}

_ZN6Assimp9BVHLoaderD2Ev:
   88|    624|    ~BVHLoader() override = default;

_ZN6Assimp7Blender9readMVertEPNS0_8ElemBaseEmRKNS0_12FileDatabaseE:
   30|     42|    bool read##ty(ElemBase *v, const size_t cnt, const FileDatabase &db) { \
   31|     42|        ty *ptr = dynamic_cast<ty *>(v);                                   \
   32|     42|        if (nullptr == ptr) {                                              \
  ------------------
  |  Branch (32:13): [True: 0, False: 42]
  ------------------
   33|      0|            return false;                                                  \
   34|      0|        }                                                                  \
   35|     42|        return read<ty>(db.dna[#ty], ptr, cnt, db);                        \
   36|     42|    }
_ZN6Assimp7Blender11createMVertEm:
   39|     42|    ElemBase *create##ty(const size_t cnt) { \
   40|     42|        return new ty[cnt];                  \
   41|     42|    }
_ZN6Assimp7Blender12destroyMVertEPNS0_8ElemBaseE:
   44|     42|    void destroy##ty(ElemBase *pE) {    \
   45|     42|        ty *p = dynamic_cast<ty *>(pE); \
   46|     42|        delete[] p;                     \
   47|     42|    }
_ZN6Assimp7Blender9readMEdgeEPNS0_8ElemBaseEmRKNS0_12FileDatabaseE:
   30|     42|    bool read##ty(ElemBase *v, const size_t cnt, const FileDatabase &db) { \
   31|     42|        ty *ptr = dynamic_cast<ty *>(v);                                   \
   32|     42|        if (nullptr == ptr) {                                              \
  ------------------
  |  Branch (32:13): [True: 0, False: 42]
  ------------------
   33|      0|            return false;                                                  \
   34|      0|        }                                                                  \
   35|     42|        return read<ty>(db.dna[#ty], ptr, cnt, db);                        \
   36|     42|    }
_ZN6Assimp7Blender11createMEdgeEm:
   39|     42|    ElemBase *create##ty(const size_t cnt) { \
   40|     42|        return new ty[cnt];                  \
   41|     42|    }
_ZN6Assimp7Blender12destroyMEdgeEPNS0_8ElemBaseE:
   44|     42|    void destroy##ty(ElemBase *pE) {    \
   45|     42|        ty *p = dynamic_cast<ty *>(pE); \
   46|     42|        delete[] p;                     \
   47|     42|    }
_ZN6Assimp7Blender9readMFaceEPNS0_8ElemBaseEmRKNS0_12FileDatabaseE:
   30|     31|    bool read##ty(ElemBase *v, const size_t cnt, const FileDatabase &db) { \
   31|     31|        ty *ptr = dynamic_cast<ty *>(v);                                   \
   32|     31|        if (nullptr == ptr) {                                              \
  ------------------
  |  Branch (32:13): [True: 0, False: 31]
  ------------------
   33|      0|            return false;                                                  \
   34|      0|        }                                                                  \
   35|     31|        return read<ty>(db.dna[#ty], ptr, cnt, db);                        \
   36|     31|    }
_ZN6Assimp7Blender11createMFaceEm:
   39|     31|    ElemBase *create##ty(const size_t cnt) { \
   40|     31|        return new ty[cnt];                  \
   41|     31|    }
_ZN6Assimp7Blender12destroyMFaceEPNS0_8ElemBaseE:
   44|     31|    void destroy##ty(ElemBase *pE) {    \
   45|     31|        ty *p = dynamic_cast<ty *>(pE); \
   46|     31|        delete[] p;                     \
   47|     31|    }
_ZN6Assimp7Blender10readMTFaceEPNS0_8ElemBaseEmRKNS0_12FileDatabaseE:
   30|      4|    bool read##ty(ElemBase *v, const size_t cnt, const FileDatabase &db) { \
   31|      4|        ty *ptr = dynamic_cast<ty *>(v);                                   \
   32|      4|        if (nullptr == ptr) {                                              \
  ------------------
  |  Branch (32:13): [True: 0, False: 4]
  ------------------
   33|      0|            return false;                                                  \
   34|      0|        }                                                                  \
   35|      4|        return read<ty>(db.dna[#ty], ptr, cnt, db);                        \
   36|      4|    }
_ZN6Assimp7Blender12createMTFaceEm:
   39|      4|    ElemBase *create##ty(const size_t cnt) { \
   40|      4|        return new ty[cnt];                  \
   41|      4|    }
_ZN6Assimp7Blender13destroyMTFaceEPNS0_8ElemBaseE:
   44|      4|    void destroy##ty(ElemBase *pE) {    \
   45|      4|        ty *p = dynamic_cast<ty *>(pE); \
   46|      4|        delete[] p;                     \
   47|      4|    }
_ZN6Assimp7Blender12readMTexPolyEPNS0_8ElemBaseEmRKNS0_12FileDatabaseE:
   30|      3|    bool read##ty(ElemBase *v, const size_t cnt, const FileDatabase &db) { \
   31|      3|        ty *ptr = dynamic_cast<ty *>(v);                                   \
   32|      3|        if (nullptr == ptr) {                                              \
  ------------------
  |  Branch (32:13): [True: 0, False: 3]
  ------------------
   33|      0|            return false;                                                  \
   34|      0|        }                                                                  \
   35|      3|        return read<ty>(db.dna[#ty], ptr, cnt, db);                        \
   36|      3|    }
_ZN6Assimp7Blender14createMTexPolyEm:
   39|      3|    ElemBase *create##ty(const size_t cnt) { \
   40|      3|        return new ty[cnt];                  \
   41|      3|    }
_ZN6Assimp7Blender15destroyMTexPolyEPNS0_8ElemBaseE:
   44|      3|    void destroy##ty(ElemBase *pE) {    \
   45|      3|        ty *p = dynamic_cast<ty *>(pE); \
   46|      3|        delete[] p;                     \
   47|      3|    }
_ZN6Assimp7Blender11readMLoopUVEPNS0_8ElemBaseEmRKNS0_12FileDatabaseE:
   30|      4|    bool read##ty(ElemBase *v, const size_t cnt, const FileDatabase &db) { \
   31|      4|        ty *ptr = dynamic_cast<ty *>(v);                                   \
   32|      4|        if (nullptr == ptr) {                                              \
  ------------------
  |  Branch (32:13): [True: 0, False: 4]
  ------------------
   33|      0|            return false;                                                  \
   34|      0|        }                                                                  \
   35|      4|        return read<ty>(db.dna[#ty], ptr, cnt, db);                        \
   36|      4|    }
_ZN6Assimp7Blender13createMLoopUVEm:
   39|      4|    ElemBase *create##ty(const size_t cnt) { \
   40|      4|        return new ty[cnt];                  \
   41|      4|    }
_ZN6Assimp7Blender14destroyMLoopUVEPNS0_8ElemBaseE:
   44|      4|    void destroy##ty(ElemBase *pE) {    \
   45|      4|        ty *p = dynamic_cast<ty *>(pE); \
   46|      4|        delete[] p;                     \
   47|      4|    }
_ZN6Assimp7Blender9readMPolyEPNS0_8ElemBaseEmRKNS0_12FileDatabaseE:
   30|     11|    bool read##ty(ElemBase *v, const size_t cnt, const FileDatabase &db) { \
   31|     11|        ty *ptr = dynamic_cast<ty *>(v);                                   \
   32|     11|        if (nullptr == ptr) {                                              \
  ------------------
  |  Branch (32:13): [True: 0, False: 11]
  ------------------
   33|      0|            return false;                                                  \
   34|      0|        }                                                                  \
   35|     11|        return read<ty>(db.dna[#ty], ptr, cnt, db);                        \
   36|     11|    }
_ZN6Assimp7Blender11createMPolyEm:
   39|     11|    ElemBase *create##ty(const size_t cnt) { \
   40|     11|        return new ty[cnt];                  \
   41|     11|    }
_ZN6Assimp7Blender12destroyMPolyEPNS0_8ElemBaseE:
   44|     11|    void destroy##ty(ElemBase *pE) {    \
   45|     11|        ty *p = dynamic_cast<ty *>(pE); \
   46|     11|        delete[] p;                     \
   47|     11|    }
_ZN6Assimp7Blender9readMLoopEPNS0_8ElemBaseEmRKNS0_12FileDatabaseE:
   30|     11|    bool read##ty(ElemBase *v, const size_t cnt, const FileDatabase &db) { \
   31|     11|        ty *ptr = dynamic_cast<ty *>(v);                                   \
   32|     11|        if (nullptr == ptr) {                                              \
  ------------------
  |  Branch (32:13): [True: 0, False: 11]
  ------------------
   33|      0|            return false;                                                  \
   34|      0|        }                                                                  \
   35|     11|        return read<ty>(db.dna[#ty], ptr, cnt, db);                        \
   36|     11|    }
_ZN6Assimp7Blender11createMLoopEm:
   39|     11|    ElemBase *create##ty(const size_t cnt) { \
   40|     11|        return new ty[cnt];                  \
   41|     11|    }
_ZN6Assimp7Blender12destroyMLoopEPNS0_8ElemBaseE:
   44|     11|    void destroy##ty(ElemBase *pE) {    \
   45|     11|        ty *p = dynamic_cast<ty *>(pE); \
   46|     11|        delete[] p;                     \
   47|     11|    }
_ZN6Assimp7Blender21isValidCustomDataTypeEi:
  148|    151|bool isValidCustomDataType(const int cdtype) {
  149|    151|    return cdtype >= 0 && cdtype < CD_NUMTYPES;
  ------------------
  |  Branch (149:12): [True: 151, False: 0]
  |  Branch (149:27): [True: 150, False: 1]
  ------------------
  150|    151|}
_ZN6Assimp7Blender14readCustomDataERNSt3__110shared_ptrINS0_8ElemBaseEEEimRKNS0_12FileDatabaseE:
  152|    151|bool readCustomData(std::shared_ptr<ElemBase> &out, const int cdtype, const size_t cnt, const FileDatabase &db) {
  153|    151|    if (!isValidCustomDataType(cdtype)) {
  ------------------
  |  Branch (153:9): [True: 1, False: 150]
  ------------------
  154|      1|        throw Error("CustomData.type ", cdtype, " out of index");
  155|      1|    }
  156|       |
  157|    150|    const CustomDataTypeDescription cdtd = customDataTypeDescriptions[cdtype];
  158|    150|    if (cdtd.Read && cdtd.Create && cdtd.Destroy && cnt > 0) {
  ------------------
  |  Branch (158:9): [True: 148, False: 2]
  |  Branch (158:22): [True: 148, False: 0]
  |  Branch (158:37): [True: 148, False: 0]
  |  Branch (158:53): [True: 148, False: 0]
  ------------------
  159|       |        // allocate cnt elements and parse them from file
  160|    148|        out.reset(cdtd.Create(cnt), cdtd.Destroy);
  161|    148|        return cdtd.Read(out.get(), cnt, db);
  162|    148|    }
  163|      2|    return false;
  164|    150|}
_ZN6Assimp7Blender18getCustomDataLayerERKNS0_10CustomDataENS0_14CustomDataTypeERKNSt3__112basic_stringIcNS5_11char_traitsIcEENS5_9allocatorIcEEEE:
  166|      2|std::shared_ptr<CustomDataLayer> getCustomDataLayer(const CustomData &customdata, const CustomDataType cdtype, const std::string &name) {
  167|      3|    for (auto it = customdata.layers.begin(); it != customdata.layers.end(); ++it) {
  ------------------
  |  Branch (167:47): [True: 3, False: 0]
  ------------------
  168|      3|        if (it->get()->type == cdtype && name == it->get()->name) {
  ------------------
  |  Branch (168:13): [True: 3, False: 0]
  |  Branch (168:42): [True: 2, False: 1]
  ------------------
  169|      2|            return *it;
  170|      2|        }
  171|      3|    }
  172|      0|    return nullptr;
  173|      2|}
_ZN6Assimp7Blender22getCustomDataLayerDataERKNS0_10CustomDataENS0_14CustomDataTypeERKNSt3__112basic_stringIcNS5_11char_traitsIcEENS5_9allocatorIcEEEE:
  175|      2|const ElemBase *getCustomDataLayerData(const CustomData &customdata, const CustomDataType cdtype, const std::string &name) {
  176|      2|    const std::shared_ptr<CustomDataLayer> pLayer = getCustomDataLayer(customdata, cdtype, name);
  177|      2|    if (pLayer && pLayer->data) {
  ------------------
  |  Branch (177:9): [True: 2, False: 0]
  |  Branch (177:19): [True: 2, False: 0]
  ------------------
  178|      2|        return pLayer->data.get();
  179|      2|    }
  180|      0|    return nullptr;
  181|      2|}
_ZN6Assimp7Blender25CustomDataTypeDescriptionC2EPFbPNS0_8ElemBaseEmRKNS0_12FileDatabaseEEPFS3_mEPFvS3_E:
   77|     84|            Read(read), Create(create), Destroy(destroy) {}
_ZN6Assimp7Blender4readINS0_5MVertEEEbRKNS0_9StructureEPT_mRKNS0_12FileDatabaseE:
   12|     42|bool read(const Structure &s, T *p, const size_t cnt, const FileDatabase &db) {
   13|  9.05k|    for (size_t i = 0; i < cnt; ++i) {
  ------------------
  |  Branch (13:24): [True: 9.01k, False: 42]
  ------------------
   14|  9.01k|        T read;
   15|  9.01k|        s.Convert(read, db);
   16|  9.01k|        *p = read;
   17|  9.01k|        p++;
   18|  9.01k|    }
   19|     42|    return true;
   20|     42|}
_ZN6Assimp7Blender4readINS0_5MEdgeEEEbRKNS0_9StructureEPT_mRKNS0_12FileDatabaseE:
   12|     42|bool read(const Structure &s, T *p, const size_t cnt, const FileDatabase &db) {
   13|  17.0k|    for (size_t i = 0; i < cnt; ++i) {
  ------------------
  |  Branch (13:24): [True: 16.9k, False: 42]
  ------------------
   14|  16.9k|        T read;
   15|  16.9k|        s.Convert(read, db);
   16|  16.9k|        *p = read;
   17|  16.9k|        p++;
   18|  16.9k|    }
   19|     42|    return true;
   20|     42|}
_ZN6Assimp7Blender4readINS0_5MFaceEEEbRKNS0_9StructureEPT_mRKNS0_12FileDatabaseE:
   12|     31|bool read(const Structure &s, T *p, const size_t cnt, const FileDatabase &db) {
   13|  7.54k|    for (size_t i = 0; i < cnt; ++i) {
  ------------------
  |  Branch (13:24): [True: 7.51k, False: 31]
  ------------------
   14|  7.51k|        T read;
   15|  7.51k|        s.Convert(read, db);
   16|  7.51k|        *p = read;
   17|  7.51k|        p++;
   18|  7.51k|    }
   19|     31|    return true;
   20|     31|}
_ZN6Assimp7Blender4readINS0_6MTFaceEEEbRKNS0_9StructureEPT_mRKNS0_12FileDatabaseE:
   12|      4|bool read(const Structure &s, T *p, const size_t cnt, const FileDatabase &db) {
   13|     18|    for (size_t i = 0; i < cnt; ++i) {
  ------------------
  |  Branch (13:24): [True: 14, False: 4]
  ------------------
   14|     14|        T read;
   15|     14|        s.Convert(read, db);
   16|     14|        *p = read;
   17|     14|        p++;
   18|     14|    }
   19|      4|    return true;
   20|      4|}
_ZN6Assimp7Blender4readINS0_8MTexPolyEEEbRKNS0_9StructureEPT_mRKNS0_12FileDatabaseE:
   12|      3|bool read(const Structure &s, T *p, const size_t cnt, const FileDatabase &db) {
   13|     49|    for (size_t i = 0; i < cnt; ++i) {
  ------------------
  |  Branch (13:24): [True: 46, False: 3]
  ------------------
   14|     46|        T read;
   15|     46|        s.Convert(read, db);
   16|     46|        *p = read;
   17|     46|        p++;
   18|     46|    }
   19|      3|    return true;
   20|      3|}
_ZN6Assimp7Blender4readINS0_7MLoopUVEEEbRKNS0_9StructureEPT_mRKNS0_12FileDatabaseE:
   12|      4|bool read(const Structure &s, T *p, const size_t cnt, const FileDatabase &db) {
   13|    168|    for (size_t i = 0; i < cnt; ++i) {
  ------------------
  |  Branch (13:24): [True: 164, False: 4]
  ------------------
   14|    164|        T read;
   15|    164|        s.Convert(read, db);
   16|    164|        *p = read;
   17|    164|        p++;
   18|    164|    }
   19|      4|    return true;
   20|      4|}
_ZN6Assimp7Blender4readINS0_5MPolyEEEbRKNS0_9StructureEPT_mRKNS0_12FileDatabaseE:
   12|     11|bool read(const Structure &s, T *p, const size_t cnt, const FileDatabase &db) {
   13|    694|    for (size_t i = 0; i < cnt; ++i) {
  ------------------
  |  Branch (13:24): [True: 683, False: 11]
  ------------------
   14|    683|        T read;
   15|    683|        s.Convert(read, db);
   16|    683|        *p = read;
   17|    683|        p++;
   18|    683|    }
   19|     11|    return true;
   20|     11|}
_ZN6Assimp7Blender4readINS0_5MLoopEEEbRKNS0_9StructureEPT_mRKNS0_12FileDatabaseE:
   12|     11|bool read(const Structure &s, T *p, const size_t cnt, const FileDatabase &db) {
   13|  2.66k|    for (size_t i = 0; i < cnt; ++i) {
  ------------------
  |  Branch (13:24): [True: 2.65k, False: 11]
  ------------------
   14|  2.65k|        T read;
   15|  2.65k|        s.Convert(read, db);
   16|  2.65k|        *p = read;
   17|  2.65k|        p++;
   18|  2.65k|    }
   19|     11|    return true;
   20|     11|}

_ZN6Assimp7Blender9DNAParser5ParseEv:
   73|     28|void DNAParser::Parse() {
   74|     28|    StreamReaderAny &stream = *db.reader;
   75|     28|    DNA &dna = db.dna;
   76|       |
   77|     28|    if (!match4(stream, "SDNA")) {
  ------------------
  |  Branch (77:9): [True: 0, False: 28]
  ------------------
   78|      0|        throw DeadlyImportError("BlenderDNA: Expected SDNA chunk");
   79|      0|    }
   80|       |
   81|       |    // name dictionary
   82|     28|    if (!match4(stream, "NAME")) {
  ------------------
  |  Branch (82:9): [True: 0, False: 28]
  ------------------
   83|      0|        throw DeadlyImportError("BlenderDNA: Expected NAME field");
   84|      0|    }
   85|       |
   86|     28|    std::vector<std::string> names(stream.GetI4());
   87|  87.9k|    for (std::string &s : names) {
  ------------------
  |  Branch (87:25): [True: 87.9k, False: 28]
  ------------------
   88|   891k|        while (char c = stream.GetI1()) {
  ------------------
  |  Branch (88:21): [True: 803k, False: 87.9k]
  ------------------
   89|   803k|            s += c;
   90|   803k|        }
   91|  87.9k|    }
   92|       |
   93|       |    // type dictionary
   94|     76|    for (; stream.GetCurrentPos() & 0x3; stream.GetI1())
  ------------------
  |  Branch (94:12): [True: 48, False: 28]
  ------------------
   95|     48|        ;
   96|     28|    if (!match4(stream, "TYPE")) {
  ------------------
  |  Branch (96:9): [True: 0, False: 28]
  ------------------
   97|      0|        throw DeadlyImportError("BlenderDNA: Expected TYPE field");
   98|      0|    }
   99|       |
  100|     28|    std::vector<Type> types(stream.GetI4());
  101|  13.8k|    for (Type &s : types) {
  ------------------
  |  Branch (101:18): [True: 13.8k, False: 28]
  ------------------
  102|   189k|        while (char c = stream.GetI1()) {
  ------------------
  |  Branch (102:21): [True: 175k, False: 13.8k]
  ------------------
  103|   175k|            s.name += c;
  104|   175k|        }
  105|  13.8k|    }
  106|       |
  107|       |    // type length dictionary
  108|     60|    for (; stream.GetCurrentPos() & 0x3; stream.GetI1())
  ------------------
  |  Branch (108:12): [True: 32, False: 28]
  ------------------
  109|     32|        ;
  110|     28|    if (!match4(stream, "TLEN")) {
  ------------------
  |  Branch (110:9): [True: 0, False: 28]
  ------------------
  111|      0|        throw DeadlyImportError("BlenderDNA: Expected TLEN field");
  112|      0|    }
  113|       |
  114|  13.8k|    for (Type &s : types) {
  ------------------
  |  Branch (114:18): [True: 13.8k, False: 28]
  ------------------
  115|  13.8k|        s.size = stream.GetI2();
  116|  13.8k|    }
  117|       |
  118|       |    // structures dictionary
  119|     58|    for (; stream.GetCurrentPos() & 0x3; stream.GetI1())
  ------------------
  |  Branch (119:12): [True: 30, False: 28]
  ------------------
  120|     30|        ;
  121|     28|    if (!match4(stream, "STRC")) {
  ------------------
  |  Branch (121:9): [True: 0, False: 28]
  ------------------
  122|      0|        throw DeadlyImportError("BlenderDNA: Expected STRC field");
  123|      0|    }
  124|       |
  125|     28|    size_t end = stream.GetI4(), fields = 0;
  126|       |
  127|     28|    dna.structures.reserve(end);
  128|  11.9k|    for (size_t i = 0; i != end; ++i) {
  ------------------
  |  Branch (128:24): [True: 11.8k, False: 26]
  ------------------
  129|       |
  130|  11.8k|        uint16_t n = stream.GetI2();
  131|  11.8k|        if (n >= types.size()) {
  ------------------
  |  Branch (131:13): [True: 1, False: 11.8k]
  ------------------
  132|      1|            throw DeadlyImportError("BlenderDNA: Invalid type index in structure name", n, " (there are only ", types.size(), " entries)");
  133|      1|        }
  134|       |
  135|       |        // maintain separate indexes
  136|  11.8k|        dna.indices[types[n].name] = dna.structures.size();
  137|       |
  138|  11.8k|        dna.structures.push_back(Structure());
  139|  11.8k|        Structure &s = dna.structures.back();
  140|  11.8k|        s.name = types[n].name;
  141|       |
  142|  11.8k|        n = stream.GetI2();
  143|  11.8k|        s.fields.reserve(n);
  144|       |
  145|  11.8k|        size_t offset = 0;
  146|   153k|        for (size_t m = 0; m < n; ++m, ++fields) {
  ------------------
  |  Branch (146:28): [True: 141k, False: 11.8k]
  ------------------
  147|       |
  148|   141k|            uint16_t j = stream.GetI2();
  149|   141k|            if (j >= types.size()) {
  ------------------
  |  Branch (149:17): [True: 0, False: 141k]
  ------------------
  150|      0|                throw DeadlyImportError("BlenderDNA: Invalid type index in structure field ", j, " (there are only ", types.size(), " entries)");
  151|      0|            }
  152|   141k|            s.fields.push_back(Field());
  153|   141k|            Field &f = s.fields.back();
  154|   141k|            f.offset = offset;
  155|       |
  156|   141k|            f.type = types[j].name;
  157|   141k|            f.size = types[j].size;
  158|       |
  159|   141k|            j = stream.GetI2();
  160|   141k|            if (j >= names.size()) {
  ------------------
  |  Branch (160:17): [True: 1, False: 141k]
  ------------------
  161|      1|                throw DeadlyImportError("BlenderDNA: Invalid name index in structure field ", j, " (there are only ", names.size(), " entries)");
  162|      1|            }
  163|       |
  164|   141k|            f.name = names[j];
  165|   141k|            f.flags = 0u;
  166|       |
  167|       |            // pointers always specify the size of the pointee instead of their own.
  168|       |            // The pointer asterisk remains a property of the lookup name.
  169|   141k|            if (f.name[0] == '*') {
  ------------------
  |  Branch (169:17): [True: 23.9k, False: 117k]
  ------------------
  170|  23.9k|                f.size = db.i64bit ? 8 : 4;
  ------------------
  |  Branch (170:26): [True: 15.9k, False: 7.99k]
  ------------------
  171|  23.9k|                f.flags |= FieldFlag_Pointer;
  172|  23.9k|            }
  173|       |
  174|       |            // arrays, however, specify the size of a single element so we
  175|       |            // need to parse the (possibly multi-dimensional) array declaration
  176|       |            // in order to obtain the actual size of the array in the file.
  177|       |            // Also we need to alter the lookup name to include no array
  178|       |            // brackets anymore or size fixup won't work (if our size does
  179|       |            // not match the size read from the DNA).
  180|   141k|            if (*f.name.rbegin() == ']') {
  ------------------
  |  Branch (180:17): [True: 19.3k, False: 122k]
  ------------------
  181|  19.3k|                const std::string::size_type rb = f.name.find('[');
  182|  19.3k|                if (rb == std::string::npos) {
  ------------------
  |  Branch (182:21): [True: 0, False: 19.3k]
  ------------------
  183|      0|                    throw DeadlyImportError("BlenderDNA: Encountered invalid array declaration ", f.name);
  184|      0|                }
  185|       |
  186|  19.3k|                f.flags |= FieldFlag_Array;
  187|  19.3k|                DNA::ExtractArraySize(f.name, f.array_sizes);
  188|  19.3k|                f.name = f.name.substr(0, rb);
  189|       |
  190|  19.3k|                f.size *= f.array_sizes[0] * f.array_sizes[1];
  191|  19.3k|            }
  192|       |
  193|       |            // maintain separate indexes
  194|   141k|            s.indices[f.name] = s.fields.size() - 1;
  195|   141k|            offset += f.size;
  196|   141k|        }
  197|  11.8k|        s.size = offset;
  198|  11.8k|    }
  199|       |
  200|     28|    ASSIMP_LOG_DEBUG("BlenderDNA: Got ", dna.structures.size(), " structures with totally ", fields, " fields");
  201|       |
  202|       |#if ASSIMP_BUILD_BLENDER_DEBUG_DNA
  203|       |    dna.DumpToFile();
  204|       |#endif
  205|       |
  206|     26|    dna.AddPrimitiveStructures();
  207|     26|    dna.RegisterConverters();
  208|     26|}
_ZN6Assimp7Blender3DNA16ExtractArraySizeERKNSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEEPm:
  244|  19.3k|        size_t array_sizes[2]) {
  245|  19.3k|    array_sizes[0] = array_sizes[1] = 1;
  246|  19.3k|    std::string::size_type pos = out.find('[');
  247|  19.3k|    if (pos++ == std::string::npos) {
  ------------------
  |  Branch (247:9): [True: 0, False: 19.3k]
  ------------------
  248|      0|        return;
  249|      0|    }
  250|  19.3k|    array_sizes[0] = strtoul10(&out[pos]);
  251|       |
  252|  19.3k|    pos = out.find('[', pos);
  253|  19.3k|    if (pos++ == std::string::npos) {
  ------------------
  |  Branch (253:9): [True: 18.0k, False: 1.23k]
  ------------------
  254|  18.0k|        return;
  255|  18.0k|    }
  256|  1.23k|    array_sizes[1] = strtoul10(&out[pos]);
  257|  1.23k|}
_ZNK6Assimp7Blender3DNA27GetBlobToStructureConverterERKNS0_9StructureERKNS0_12FileDatabaseE:
  278|    116|) const {
  279|    116|    std::map<std::string, FactoryPair>::const_iterator it = converters.find(structure.name);
  280|    116|    return it == converters.end() ? FactoryPair() : (*it).second;
  ------------------
  |  Branch (280:12): [True: 0, False: 116]
  ------------------
  281|    116|}
_ZN6Assimp7Blender3DNA22AddPrimitiveStructuresEv:
  285|     26|void DNA ::AddPrimitiveStructures() {
  286|       |    // NOTE: these are just dummies. Their presence enforces
  287|       |    // Structure::Convert<target_type> to be called on these
  288|       |    // empty structures. These converters are special
  289|       |    // overloads which scan the name of the structure and
  290|       |    // perform the required data type conversion if one
  291|       |    // of these special names is found in the structure
  292|       |    // in question.
  293|       |
  294|     26|    indices["int"] = structures.size();
  295|     26|    structures.push_back(Structure());
  296|     26|    structures.back().name = "int";
  297|     26|    structures.back().size = 4;
  298|       |
  299|     26|    indices["short"] = structures.size();
  300|     26|    structures.push_back(Structure());
  301|     26|    structures.back().name = "short";
  302|     26|    structures.back().size = 2;
  303|       |
  304|     26|    indices["char"] = structures.size();
  305|     26|    structures.push_back(Structure());
  306|     26|    structures.back().name = "char";
  307|     26|    structures.back().size = 1;
  308|       |
  309|     26|    indices["float"] = structures.size();
  310|     26|    structures.push_back(Structure());
  311|     26|    structures.back().name = "float";
  312|     26|    structures.back().size = 4;
  313|       |
  314|     26|    indices["double"] = structures.size();
  315|     26|    structures.push_back(Structure());
  316|     26|    structures.back().name = "double";
  317|     26|    structures.back().size = 8;
  318|       |
  319|       |    // no long, seemingly.
  320|     26|}
_ZN6Assimp7Blender13SectionParser4NextEv:
  323|  21.5k|void SectionParser ::Next() {
  324|  21.5k|    stream.SetCurrentPos(current.start + current.size);
  325|       |
  326|  21.5k|    const char tmp[] = {
  327|  21.5k|        (char)stream.GetI1(),
  328|  21.5k|        (char)stream.GetI1(),
  329|  21.5k|        (char)stream.GetI1(),
  330|  21.5k|        (char)stream.GetI1()
  331|  21.5k|    };
  332|  21.5k|    current.id = std::string(tmp, tmp[3] ? 4 : tmp[2] ? 3 : tmp[1] ? 2 : 1);
  ------------------
  |  Branch (332:35): [True: 20.4k, False: 1.08k]
  |  Branch (332:48): [True: 3, False: 1.07k]
  |  Branch (332:61): [True: 1.07k, False: 9]
  ------------------
  333|       |
  334|  21.5k|    current.size = stream.GetI4();
  335|  21.5k|    current.address.val = ptr64 ? stream.GetU8() : stream.GetU4();
  ------------------
  |  Branch (335:27): [True: 14.6k, False: 6.86k]
  ------------------
  336|       |
  337|  21.5k|    current.dna_index = stream.GetI4();
  338|  21.5k|    current.num = stream.GetI4();
  339|       |
  340|  21.5k|    current.start = stream.GetCurrentPos();
  341|  21.5k|    if (stream.GetRemainingSizeToLimit() < current.size) {
  ------------------
  |  Branch (341:9): [True: 4, False: 21.5k]
  ------------------
  342|      4|        throw DeadlyImportError("BLEND: invalid size of file block");
  343|      4|    }
  344|       |
  345|  21.5k|#ifdef ASSIMP_BUILD_BLENDER_DEBUG
  346|  21.5k|    ASSIMP_LOG_VERBOSE_DEBUG(current.id);
  347|  21.5k|#endif
  348|  21.5k|}
BlenderDNA.cpp:_ZL6match4RN6Assimp12StreamReaderILb1ELb1EEEPKc:
   57|    140|static bool match4(StreamReaderAny &stream, const char *string) {
   58|    140|    ai_assert(nullptr != string);
   59|    140|    char tmp[4];
   60|    140|    tmp[0] = (stream).GetI1();
   61|    140|    tmp[1] = (stream).GetI1();
   62|    140|    tmp[2] = (stream).GetI1();
   63|    140|    tmp[3] = (stream).GetI1();
   64|    140|    return (tmp[0] == string[0] && tmp[1] == string[1] && tmp[2] == string[2] && tmp[3] == string[3]);
  ------------------
  |  Branch (64:13): [True: 140, False: 0]
  |  Branch (64:36): [True: 140, False: 0]
  |  Branch (64:59): [True: 140, False: 0]
  |  Branch (64:82): [True: 140, False: 0]
  ------------------
   65|    140|}

_ZN6Assimp7Blender12FileDatabaseC2Ev:
  703|     32|            _cacheArrays(*this), _cache(*this), next_cache_idx() {}
_ZN6Assimp7Blender11ObjectCacheINS0_6vectorEEC2ERKNS0_12FileDatabaseE:
  681|     32|    explicit ObjectCache(const FileDatabase &) {}
_ZN6Assimp7Blender11ObjectCacheINSt3__110shared_ptrEEC2ERKNS0_12FileDatabaseE:
  642|     32|    explicit ObjectCache(const FileDatabase &db) : db(db) {
  643|       |        // currently there are only ~400 structure records per blend file.
  644|       |        // we read only a small part of them and don't cache objects
  645|       |        // which we don't need, so this should suffice.
  646|     32|        caches.reserve(64);
  647|     32|    }
_ZN6Assimp7Blender8ElemBaseC2Ev:
  104|   112k|            dna_type(nullptr) {
  105|       |        // empty
  106|   112k|    }
_ZN6Assimp7Blender8ElemBaseD2Ev:
  108|   112k|    virtual ~ElemBase() = default;
_ZN6Assimp7Blender9DNAParserC2ERNS0_12FileDatabaseE:
  753|     32|    explicit DNAParser(FileDatabase &db) : db(db) {
  754|       |        // empty
  755|     32|    }
_ZN6Assimp7Blender13SectionParserC2ERNS_12StreamReaderILb1ELb1EEEb:
  586|     32|            stream(stream), ptr64(ptr64) {
  587|     32|        current.size = current.start = 0;
  588|     32|    }
_ZNK6Assimp7Blender13SectionParser10GetCurrentEv:
  592|  21.5k|    const FileBlockHead &GetCurrent() const {
  593|  21.5k|        return current;
  594|  21.5k|    }
_ZNK6Assimp7Blender9DNAParser6GetDNAEv:
  768|     26|    const Blender::DNA &GetDNA() const {
  769|     26|        return db.dna;
  770|     26|    }
_ZNK6Assimp7Blender12FileDatabase5statsEv:
  705|   366k|    Statistics &stats() const {
  706|   366k|        return _stats;
  707|   366k|    }
_ZNK6Assimp7Blender13FileBlockHeadltERKS1_:
  560|   220k|    bool operator<(const FileBlockHead &o) const {
  561|   220k|        return address.val < o.address.val;
  562|   220k|    }
_ZNK6Assimp7Blender6vectorINSt3__110shared_ptrINS0_8MaterialEEEEcvbEv:
  153|     39|    operator bool() const {
  154|     39|        return !empty();
  155|     39|    }
_ZNK6Assimp7Blender6vectorINS0_6MTFaceEEcvbEv:
  153|     46|    operator bool() const {
  154|     46|        return !empty();
  155|     46|    }
_ZNK6Assimp7Blender6vectorINS0_7MLoopUVEEcvbEv:
  153|     40|    operator bool() const {
  154|     40|        return !empty();
  155|     40|    }
_ZNK6Assimp7Blender6vectorINS0_5TFaceEEcvbEv:
  153|     38|    operator bool() const {
  154|     38|        return !empty();
  155|     38|    }
_ZNK6Assimp7Blender6vectorINS0_4MColEEcvbEv:
  153|     40|    operator bool() const {
  154|     40|        return !empty();
  155|     40|    }
_ZNK6Assimp7Blender6vectorINS0_8MLoopColEEcvbEv:
  153|     37|    operator bool() const {
  154|     37|        return !empty();
  155|     37|    }
_ZN6Assimp7Blender9StructureC2Ev:
  216|  12.0k|            cache_idx(static_cast<size_t>(-1)) {
  217|       |        // empty
  218|  12.0k|    }
_ZNK6Assimp7Blender9StructureneERKS1_:
  243|    602|    inline bool operator!=(const Structure &other) const {
  244|    602|        return name != other.name;
  245|    602|    }
_ZNK6Assimp7Blender13FileBlockHeadcvRKNS0_7PointerEEv:
  565|  10.3k|    operator const Pointer &() const {
  566|  10.3k|        return address;
  567|  10.3k|    }
_ZN6Assimp7BlenderltERKNS0_7PointerES3_:
  571|  11.8k|inline bool operator<(const Pointer &a, const Pointer &b) {
  572|  11.8k|    return a.val < b.val;
  573|  11.8k|}
_ZNK6Assimp7Blender12FileDatabase5cacheINS0_8ElemBaseEEERNS0_11ObjectCacheINSt3__110shared_ptrEEERNS6_IT_EE:
  714|    280|    ObjectCache<std::shared_ptr> &cache(std::shared_ptr<T> & /*in*/) const {
  715|    280|        return _cache;
  716|    280|    }
_ZN6Assimp7Blender5ErrorC2IJRA39_KcRKNSt3__112basic_stringIcNS6_11char_traitsIcEENS6_9allocatorIcEEEERA17_S3_SE_RA2_S3_EEEDpOT_:
   94|  1.94k|            DeadlyImportError(args...) {
   95|  1.94k|    }
_ZN6Assimp7Blender9Structure19_defaultInitializerILi1EEclIfEEvRT_PKc:
  395|    289|    void operator()(T &out, const char *reason = "<add reason>") {
  396|    289|        ASSIMP_LOG_WARN(reason);
  397|       |
  398|       |        // ... and let the show go on
  399|    289|        _defaultInitializer<0 /*ErrorPolicy_Igno*/>()(out);
  400|    289|    }
_ZN6Assimp7Blender9Structure19_defaultInitializerILi0EEclIfEEvRT_PKc:
  382|    289|        void operator()(T &out, const char * = nullptr) {
  383|    289|            out = T();
  384|    289|        }
_ZN6Assimp7Blender9Structure19_defaultInitializerILi1EEclIcEEvRT_PKc:
  395|   299k|    void operator()(T &out, const char *reason = "<add reason>") {
  396|   299k|        ASSIMP_LOG_WARN(reason);
  397|       |
  398|       |        // ... and let the show go on
  399|   299k|        _defaultInitializer<0 /*ErrorPolicy_Igno*/>()(out);
  400|   299k|    }
_ZN6Assimp7Blender9Structure19_defaultInitializerILi0EEclIcEEvRT_PKc:
  382|   299k|        void operator()(T &out, const char * = nullptr) {
  383|   299k|            out = T();
  384|   299k|        }
_ZNK6Assimp7Blender12FileDatabase5cacheINS0_6ObjectEEERNS0_11ObjectCacheINSt3__110shared_ptrEEERNS6_IT_EE:
  714|    235|    ObjectCache<std::shared_ptr> &cache(std::shared_ptr<T> & /*in*/) const {
  715|    235|        return _cache;
  716|    235|    }
_ZNK6Assimp7Blender9Structure9_allocateINS0_6ObjectEEEPT_RNSt3__110shared_ptrIS4_EERm:
  349|    100|    T *_allocate(std::shared_ptr<T> &out, size_t &s) const {
  350|    100|        out = std::shared_ptr<T>(new T());
  351|    100|        s = 1;
  352|    100|        return out.get();
  353|    100|    }
_ZN6Assimp7Blender9Structure19_defaultInitializerILi1EEclINSt3__110shared_ptrINS0_5GroupEEEEEvRT_PKc:
  395|      1|    void operator()(T &out, const char *reason = "<add reason>") {
  396|      1|        ASSIMP_LOG_WARN(reason);
  397|       |
  398|       |        // ... and let the show go on
  399|      1|        _defaultInitializer<0 /*ErrorPolicy_Igno*/>()(out);
  400|      1|    }
_ZN6Assimp7Blender9Structure19_defaultInitializerILi0EEclINSt3__110shared_ptrINS0_5GroupEEEEEvRT_PKc:
  382|      1|        void operator()(T &out, const char * = nullptr) {
  383|      1|            out = T();
  384|      1|        }
_ZN6Assimp7Blender9Structure19_defaultInitializerILi1EEclIiEEvRT_PKc:
  395|  1.30k|    void operator()(T &out, const char *reason = "<add reason>") {
  396|  1.30k|        ASSIMP_LOG_WARN(reason);
  397|       |
  398|       |        // ... and let the show go on
  399|  1.30k|        _defaultInitializer<0 /*ErrorPolicy_Igno*/>()(out);
  400|  1.30k|    }
_ZN6Assimp7Blender9Structure19_defaultInitializerILi0EEclIiEEvRT_PKc:
  382|  1.30k|        void operator()(T &out, const char * = nullptr) {
  383|  1.30k|            out = T();
  384|  1.30k|        }
_ZNK6Assimp7Blender12FileDatabase5cacheINS0_16CollectionObjectEEERNS0_11ObjectCacheINSt3__110shared_ptrEEERNS6_IT_EE:
  714|      4|    ObjectCache<std::shared_ptr> &cache(std::shared_ptr<T> & /*in*/) const {
  715|      4|        return _cache;
  716|      4|    }
_ZNK6Assimp7Blender9Structure9_allocateINS0_16CollectionObjectEEEPT_RNSt3__110shared_ptrIS4_EERm:
  349|      2|    T *_allocate(std::shared_ptr<T> &out, size_t &s) const {
  350|      2|        out = std::shared_ptr<T>(new T());
  351|      2|        s = 1;
  352|      2|        return out.get();
  353|      2|    }
_ZN6Assimp7Blender9Structure19_defaultInitializerILi1EEclINSt3__110shared_ptrINS0_10CollectionEEEEEvRT_PKc:
  395|     24|    void operator()(T &out, const char *reason = "<add reason>") {
  396|     24|        ASSIMP_LOG_WARN(reason);
  397|       |
  398|       |        // ... and let the show go on
  399|     24|        _defaultInitializer<0 /*ErrorPolicy_Igno*/>()(out);
  400|     24|    }
_ZN6Assimp7Blender9Structure19_defaultInitializerILi0EEclINSt3__110shared_ptrINS0_10CollectionEEEEEvRT_PKc:
  382|     24|        void operator()(T &out, const char * = nullptr) {
  383|     24|            out = T();
  384|     24|        }
_ZNK6Assimp7Blender12FileDatabase5cacheINS0_10CollectionEEERNS0_11ObjectCacheINSt3__110shared_ptrEEERNS6_IT_EE:
  714|      4|    ObjectCache<std::shared_ptr> &cache(std::shared_ptr<T> & /*in*/) const {
  715|      4|        return _cache;
  716|      4|    }
_ZNK6Assimp7Blender9Structure9_allocateINS0_10CollectionEEEPT_RNSt3__110shared_ptrIS4_EERm:
  349|      2|    T *_allocate(std::shared_ptr<T> &out, size_t &s) const {
  350|      2|        out = std::shared_ptr<T>(new T());
  351|      2|        s = 1;
  352|      2|        return out.get();
  353|      2|    }
_ZNK6Assimp7Blender12FileDatabase5cacheINS0_3TexEEERNS0_11ObjectCacheINSt3__110shared_ptrEEERNS6_IT_EE:
  714|     52|    ObjectCache<std::shared_ptr> &cache(std::shared_ptr<T> & /*in*/) const {
  715|     52|        return _cache;
  716|     52|    }
_ZNK6Assimp7Blender9Structure9_allocateINS0_3TexEEEPT_RNSt3__110shared_ptrIS4_EERm:
  349|     24|    T *_allocate(std::shared_ptr<T> &out, size_t &s) const {
  350|     24|        out = std::shared_ptr<T>(new T());
  351|     24|        s = 1;
  352|     24|        return out.get();
  353|     24|    }
_ZN6Assimp7Blender9Structure19_defaultInitializerILi1EEclIsEEvRT_PKc:
  395|    117|    void operator()(T &out, const char *reason = "<add reason>") {
  396|    117|        ASSIMP_LOG_WARN(reason);
  397|       |
  398|       |        // ... and let the show go on
  399|    117|        _defaultInitializer<0 /*ErrorPolicy_Igno*/>()(out);
  400|    117|    }
_ZN6Assimp7Blender9Structure19_defaultInitializerILi0EEclIsEEvRT_PKc:
  382|    117|        void operator()(T &out, const char * = nullptr) {
  383|    117|            out = T();
  384|    117|        }
_ZNK6Assimp7Blender12FileDatabase5cacheINS0_4BaseEEERNS0_11ObjectCacheINSt3__110shared_ptrEEERNS6_IT_EE:
  714|    182|    ObjectCache<std::shared_ptr> &cache(std::shared_ptr<T> & /*in*/) const {
  715|    182|        return _cache;
  716|    182|    }
_ZNK6Assimp7Blender9Structure9_allocateINS0_4BaseEEEPT_RNSt3__110shared_ptrIS4_EERm:
  349|     88|    T *_allocate(std::shared_ptr<T> &out, size_t &s) const {
  350|     88|        out = std::shared_ptr<T>(new T());
  351|     88|        s = 1;
  352|     88|        return out.get();
  353|     88|    }
_ZN6Assimp7Blender9Structure19_defaultInitializerILi1EEclIA18_NSt3__110shared_ptrINS0_4MTexEEEEEvRT_PKc:
  395|      1|    void operator()(T &out, const char *reason = "<add reason>") {
  396|      1|        ASSIMP_LOG_WARN(reason);
  397|       |
  398|       |        // ... and let the show go on
  399|      1|        _defaultInitializer<0 /*ErrorPolicy_Igno*/>()(out);
  400|      1|    }
_ZN6Assimp7Blender9Structure19_defaultInitializerILi0EEclINSt3__110shared_ptrINS0_4MTexEEELj18EEEvRAT0__T_PKc:
  366|      1|        void operator()(T (&out)[N], const char * = nullptr) {
  367|     19|            for (unsigned int i = 0; i < N; ++i) {
  ------------------
  |  Branch (367:38): [True: 18, False: 1]
  ------------------
  368|     18|                out[i] = T();
  369|     18|            }
  370|      1|        }
_ZNK6Assimp7Blender12FileDatabase5cacheINS0_4MTexEEERNS0_11ObjectCacheINSt3__110shared_ptrEEERNS6_IT_EE:
  714|     56|    ObjectCache<std::shared_ptr> &cache(std::shared_ptr<T> & /*in*/) const {
  715|     56|        return _cache;
  716|     56|    }
_ZNK6Assimp7Blender9Structure9_allocateINS0_4MTexEEEPT_RNSt3__110shared_ptrIS4_EERm:
  349|     28|    T *_allocate(std::shared_ptr<T> &out, size_t &s) const {
  350|     28|        out = std::shared_ptr<T>(new T());
  351|     28|        s = 1;
  352|     28|        return out.get();
  353|     28|    }
_ZNK6Assimp7Blender12FileDatabase5cacheINS0_5ImageEEERNS0_11ObjectCacheINSt3__110shared_ptrEEERNS6_IT_EE:
  714|    108|    ObjectCache<std::shared_ptr> &cache(std::shared_ptr<T> & /*in*/) const {
  715|    108|        return _cache;
  716|    108|    }
_ZNK6Assimp7Blender9Structure9_allocateINS0_5ImageEEEPT_RNSt3__110shared_ptrIS4_EERm:
  349|      8|    T *_allocate(std::shared_ptr<T> &out, size_t &s) const {
  350|      8|        out = std::shared_ptr<T>(new T());
  351|      8|        s = 1;
  352|      8|        return out.get();
  353|      8|    }
_ZN6Assimp7Blender6vectorINS0_5MFaceEE5resetEv:
  149|     42|    void reset() {
  150|     42|        resize(0);
  151|     42|    }
_ZNK6Assimp7Blender12FileDatabase5cacheINS0_5MFaceEEERNS0_11ObjectCacheINS0_6vectorEEERNS5_IT_EE:
  719|     62|    ObjectCache<vector> &cache(vector<T> & /*in*/) const {
  720|     62|        return _cacheArrays;
  721|     62|    }
_ZN6Assimp7Blender11ObjectCacheINS0_6vectorEE3getINS0_5MFaceEEEvRKNS0_9StructureERNS2_IT_EERKNS0_7PointerE:
  684|     31|    void get(const Structure &, vector<T> &, const Pointer &) {}
_ZNK6Assimp7Blender6vectorINS0_5MFaceEEcvbEv:
  153|     62|    operator bool() const {
  154|     62|        return !empty();
  155|     62|    }
_ZNK6Assimp7Blender9Structure9_allocateINS0_5MFaceEEEPT_RNS0_6vectorIS4_EERm:
  356|     31|    T *_allocate(vector<T> &out, size_t &s) const {
  357|     31|        out.resize(s);
  358|     31|        return s ? &out.front() : nullptr;
  ------------------
  |  Branch (358:16): [True: 31, False: 0]
  ------------------
  359|     31|    }
_ZN6Assimp7Blender11ObjectCacheINS0_6vectorEE3setINS0_5MFaceEEEvRKNS0_9StructureERKNS2_IT_EERKNS0_7PointerE:
  686|     31|    void set(const Structure &, const vector<T> &, const Pointer &) {}
_ZN6Assimp7Blender6vectorINS0_6MTFaceEE5resetEv:
  149|     42|    void reset() {
  150|     42|        resize(0);
  151|     42|    }
_ZNK6Assimp7Blender12FileDatabase5cacheINS0_6MTFaceEEERNS0_11ObjectCacheINS0_6vectorEEERNS5_IT_EE:
  719|      8|    ObjectCache<vector> &cache(vector<T> & /*in*/) const {
  720|      8|        return _cacheArrays;
  721|      8|    }
_ZN6Assimp7Blender11ObjectCacheINS0_6vectorEE3getINS0_6MTFaceEEEvRKNS0_9StructureERNS2_IT_EERKNS0_7PointerE:
  684|      4|    void get(const Structure &, vector<T> &, const Pointer &) {}
_ZNK6Assimp7Blender9Structure9_allocateINS0_6MTFaceEEEPT_RNS0_6vectorIS4_EERm:
  356|      4|    T *_allocate(vector<T> &out, size_t &s) const {
  357|      4|        out.resize(s);
  358|      4|        return s ? &out.front() : nullptr;
  ------------------
  |  Branch (358:16): [True: 4, False: 0]
  ------------------
  359|      4|    }
_ZN6Assimp7Blender11ObjectCacheINS0_6vectorEE3setINS0_6MTFaceEEEvRKNS0_9StructureERKNS2_IT_EERKNS0_7PointerE:
  686|      4|    void set(const Structure &, const vector<T> &, const Pointer &) {}
_ZN6Assimp7Blender6vectorINS0_5TFaceEE5resetEv:
  149|     42|    void reset() {
  150|     42|        resize(0);
  151|     42|    }
_ZN6Assimp7Blender6vectorINS0_5MVertEE5resetEv:
  149|     42|    void reset() {
  150|     42|        resize(0);
  151|     42|    }
_ZNK6Assimp7Blender12FileDatabase5cacheINS0_5MVertEEERNS0_11ObjectCacheINS0_6vectorEEERNS5_IT_EE:
  719|     84|    ObjectCache<vector> &cache(vector<T> & /*in*/) const {
  720|     84|        return _cacheArrays;
  721|     84|    }
_ZN6Assimp7Blender11ObjectCacheINS0_6vectorEE3getINS0_5MVertEEEvRKNS0_9StructureERNS2_IT_EERKNS0_7PointerE:
  684|     42|    void get(const Structure &, vector<T> &, const Pointer &) {}
_ZNK6Assimp7Blender6vectorINS0_5MVertEEcvbEv:
  153|     84|    operator bool() const {
  154|     84|        return !empty();
  155|     84|    }
_ZNK6Assimp7Blender9Structure9_allocateINS0_5MVertEEEPT_RNS0_6vectorIS4_EERm:
  356|     42|    T *_allocate(vector<T> &out, size_t &s) const {
  357|     42|        out.resize(s);
  358|     42|        return s ? &out.front() : nullptr;
  ------------------
  |  Branch (358:16): [True: 42, False: 0]
  ------------------
  359|     42|    }
_ZN6Assimp7Blender11ObjectCacheINS0_6vectorEE3setINS0_5MVertEEEvRKNS0_9StructureERKNS2_IT_EERKNS0_7PointerE:
  686|     42|    void set(const Structure &, const vector<T> &, const Pointer &) {}
_ZN6Assimp7Blender6vectorINS0_5MEdgeEE5resetEv:
  149|     42|    void reset() {
  150|     42|        resize(0);
  151|     42|    }
_ZNK6Assimp7Blender12FileDatabase5cacheINS0_5MEdgeEEERNS0_11ObjectCacheINS0_6vectorEEERNS5_IT_EE:
  719|     84|    ObjectCache<vector> &cache(vector<T> & /*in*/) const {
  720|     84|        return _cacheArrays;
  721|     84|    }
_ZN6Assimp7Blender11ObjectCacheINS0_6vectorEE3getINS0_5MEdgeEEEvRKNS0_9StructureERNS2_IT_EERKNS0_7PointerE:
  684|     42|    void get(const Structure &, vector<T> &, const Pointer &) {}
_ZNK6Assimp7Blender6vectorINS0_5MEdgeEEcvbEv:
  153|     84|    operator bool() const {
  154|     84|        return !empty();
  155|     84|    }
_ZNK6Assimp7Blender9Structure9_allocateINS0_5MEdgeEEEPT_RNS0_6vectorIS4_EERm:
  356|     42|    T *_allocate(vector<T> &out, size_t &s) const {
  357|     42|        out.resize(s);
  358|     42|        return s ? &out.front() : nullptr;
  ------------------
  |  Branch (358:16): [True: 42, False: 0]
  ------------------
  359|     42|    }
_ZN6Assimp7Blender11ObjectCacheINS0_6vectorEE3setINS0_5MEdgeEEEvRKNS0_9StructureERKNS2_IT_EERKNS0_7PointerE:
  686|     42|    void set(const Structure &, const vector<T> &, const Pointer &) {}
_ZN6Assimp7Blender9Structure19_defaultInitializerILi1EEclINS0_6vectorINS0_5MLoopEEEEEvRT_PKc:
  395|     30|    void operator()(T &out, const char *reason = "<add reason>") {
  396|     30|        ASSIMP_LOG_WARN(reason);
  397|       |
  398|       |        // ... and let the show go on
  399|     30|        _defaultInitializer<0 /*ErrorPolicy_Igno*/>()(out);
  400|     30|    }
_ZN6Assimp7Blender9Structure19_defaultInitializerILi0EEclINS0_6vectorINS0_5MLoopEEEEEvRT_PKc:
  382|     30|        void operator()(T &out, const char * = nullptr) {
  383|     30|            out = T();
  384|     30|        }
_ZN6Assimp7Blender6vectorINS0_5MLoopEE5resetEv:
  149|     42|    void reset() {
  150|     42|        resize(0);
  151|     42|    }
_ZNK6Assimp7Blender12FileDatabase5cacheINS0_5MLoopEEERNS0_11ObjectCacheINS0_6vectorEEERNS5_IT_EE:
  719|     22|    ObjectCache<vector> &cache(vector<T> & /*in*/) const {
  720|     22|        return _cacheArrays;
  721|     22|    }
_ZN6Assimp7Blender11ObjectCacheINS0_6vectorEE3getINS0_5MLoopEEEvRKNS0_9StructureERNS2_IT_EERKNS0_7PointerE:
  684|     11|    void get(const Structure &, vector<T> &, const Pointer &) {}
_ZNK6Assimp7Blender6vectorINS0_5MLoopEEcvbEv:
  153|     22|    operator bool() const {
  154|     22|        return !empty();
  155|     22|    }
_ZNK6Assimp7Blender9Structure9_allocateINS0_5MLoopEEEPT_RNS0_6vectorIS4_EERm:
  356|     11|    T *_allocate(vector<T> &out, size_t &s) const {
  357|     11|        out.resize(s);
  358|     11|        return s ? &out.front() : nullptr;
  ------------------
  |  Branch (358:16): [True: 11, False: 0]
  ------------------
  359|     11|    }
_ZN6Assimp7Blender11ObjectCacheINS0_6vectorEE3setINS0_5MLoopEEEvRKNS0_9StructureERKNS2_IT_EERKNS0_7PointerE:
  686|     11|    void set(const Structure &, const vector<T> &, const Pointer &) {}
_ZN6Assimp7Blender9Structure19_defaultInitializerILi1EEclINS0_6vectorINS0_7MLoopUVEEEEEvRT_PKc:
  395|     30|    void operator()(T &out, const char *reason = "<add reason>") {
  396|     30|        ASSIMP_LOG_WARN(reason);
  397|       |
  398|       |        // ... and let the show go on
  399|     30|        _defaultInitializer<0 /*ErrorPolicy_Igno*/>()(out);
  400|     30|    }
_ZN6Assimp7Blender9Structure19_defaultInitializerILi0EEclINS0_6vectorINS0_7MLoopUVEEEEEvRT_PKc:
  382|     30|        void operator()(T &out, const char * = nullptr) {
  383|     30|            out = T();
  384|     30|        }
_ZN6Assimp7Blender6vectorINS0_7MLoopUVEE5resetEv:
  149|     42|    void reset() {
  150|     42|        resize(0);
  151|     42|    }
_ZNK6Assimp7Blender12FileDatabase5cacheINS0_7MLoopUVEEERNS0_11ObjectCacheINS0_6vectorEEERNS5_IT_EE:
  719|      6|    ObjectCache<vector> &cache(vector<T> & /*in*/) const {
  720|      6|        return _cacheArrays;
  721|      6|    }
_ZN6Assimp7Blender11ObjectCacheINS0_6vectorEE3getINS0_7MLoopUVEEEvRKNS0_9StructureERNS2_IT_EERKNS0_7PointerE:
  684|      3|    void get(const Structure &, vector<T> &, const Pointer &) {}
_ZNK6Assimp7Blender9Structure9_allocateINS0_7MLoopUVEEEPT_RNS0_6vectorIS4_EERm:
  356|      3|    T *_allocate(vector<T> &out, size_t &s) const {
  357|      3|        out.resize(s);
  358|      3|        return s ? &out.front() : nullptr;
  ------------------
  |  Branch (358:16): [True: 3, False: 0]
  ------------------
  359|      3|    }
_ZN6Assimp7Blender11ObjectCacheINS0_6vectorEE3setINS0_7MLoopUVEEEvRKNS0_9StructureERKNS2_IT_EERKNS0_7PointerE:
  686|      3|    void set(const Structure &, const vector<T> &, const Pointer &) {}
_ZN6Assimp7Blender9Structure19_defaultInitializerILi1EEclINS0_6vectorINS0_8MLoopColEEEEEvRT_PKc:
  395|     30|    void operator()(T &out, const char *reason = "<add reason>") {
  396|     30|        ASSIMP_LOG_WARN(reason);
  397|       |
  398|       |        // ... and let the show go on
  399|     30|        _defaultInitializer<0 /*ErrorPolicy_Igno*/>()(out);
  400|     30|    }
_ZN6Assimp7Blender9Structure19_defaultInitializerILi0EEclINS0_6vectorINS0_8MLoopColEEEEEvRT_PKc:
  382|     30|        void operator()(T &out, const char * = nullptr) {
  383|     30|            out = T();
  384|     30|        }
_ZN6Assimp7Blender6vectorINS0_8MLoopColEE5resetEv:
  149|     42|    void reset() {
  150|     42|        resize(0);
  151|     42|    }
_ZN6Assimp7Blender9Structure19_defaultInitializerILi1EEclINS0_6vectorINS0_5MPolyEEEEEvRT_PKc:
  395|     30|    void operator()(T &out, const char *reason = "<add reason>") {
  396|     30|        ASSIMP_LOG_WARN(reason);
  397|       |
  398|       |        // ... and let the show go on
  399|     30|        _defaultInitializer<0 /*ErrorPolicy_Igno*/>()(out);
  400|     30|    }
_ZN6Assimp7Blender9Structure19_defaultInitializerILi0EEclINS0_6vectorINS0_5MPolyEEEEEvRT_PKc:
  382|     30|        void operator()(T &out, const char * = nullptr) {
  383|     30|            out = T();
  384|     30|        }
_ZN6Assimp7Blender6vectorINS0_5MPolyEE5resetEv:
  149|     42|    void reset() {
  150|     42|        resize(0);
  151|     42|    }
_ZNK6Assimp7Blender12FileDatabase5cacheINS0_5MPolyEEERNS0_11ObjectCacheINS0_6vectorEEERNS5_IT_EE:
  719|     22|    ObjectCache<vector> &cache(vector<T> & /*in*/) const {
  720|     22|        return _cacheArrays;
  721|     22|    }
_ZN6Assimp7Blender11ObjectCacheINS0_6vectorEE3getINS0_5MPolyEEEvRKNS0_9StructureERNS2_IT_EERKNS0_7PointerE:
  684|     11|    void get(const Structure &, vector<T> &, const Pointer &) {}
_ZNK6Assimp7Blender6vectorINS0_5MPolyEEcvbEv:
  153|     22|    operator bool() const {
  154|     22|        return !empty();
  155|     22|    }
_ZNK6Assimp7Blender9Structure9_allocateINS0_5MPolyEEEPT_RNS0_6vectorIS4_EERm:
  356|     11|    T *_allocate(vector<T> &out, size_t &s) const {
  357|     11|        out.resize(s);
  358|     11|        return s ? &out.front() : nullptr;
  ------------------
  |  Branch (358:16): [True: 11, False: 0]
  ------------------
  359|     11|    }
_ZN6Assimp7Blender11ObjectCacheINS0_6vectorEE3setINS0_5MPolyEEEvRKNS0_9StructureERKNS2_IT_EERKNS0_7PointerE:
  686|     11|    void set(const Structure &, const vector<T> &, const Pointer &) {}
_ZN6Assimp7Blender9Structure19_defaultInitializerILi1EEclINS0_6vectorINS0_8MTexPolyEEEEEvRT_PKc:
  395|     31|    void operator()(T &out, const char *reason = "<add reason>") {
  396|     31|        ASSIMP_LOG_WARN(reason);
  397|       |
  398|       |        // ... and let the show go on
  399|     31|        _defaultInitializer<0 /*ErrorPolicy_Igno*/>()(out);
  400|     31|    }
_ZN6Assimp7Blender9Structure19_defaultInitializerILi0EEclINS0_6vectorINS0_8MTexPolyEEEEEvRT_PKc:
  382|     31|        void operator()(T &out, const char * = nullptr) {
  383|     31|            out = T();
  384|     31|        }
_ZN6Assimp7Blender6vectorINS0_8MTexPolyEE5resetEv:
  149|     42|    void reset() {
  150|     42|        resize(0);
  151|     42|    }
_ZNK6Assimp7Blender12FileDatabase5cacheINS0_8MTexPolyEEERNS0_11ObjectCacheINS0_6vectorEEERNS5_IT_EE:
  719|      4|    ObjectCache<vector> &cache(vector<T> & /*in*/) const {
  720|      4|        return _cacheArrays;
  721|      4|    }
_ZN6Assimp7Blender11ObjectCacheINS0_6vectorEE3getINS0_8MTexPolyEEEvRKNS0_9StructureERNS2_IT_EERKNS0_7PointerE:
  684|      2|    void get(const Structure &, vector<T> &, const Pointer &) {}
_ZNK6Assimp7Blender6vectorINS0_8MTexPolyEEcvbEv:
  153|      4|    operator bool() const {
  154|      4|        return !empty();
  155|      4|    }
_ZNK6Assimp7Blender9Structure9_allocateINS0_8MTexPolyEEEPT_RNS0_6vectorIS4_EERm:
  356|      2|    T *_allocate(vector<T> &out, size_t &s) const {
  357|      2|        out.resize(s);
  358|      2|        return s ? &out.front() : nullptr;
  ------------------
  |  Branch (358:16): [True: 2, False: 0]
  ------------------
  359|      2|    }
_ZN6Assimp7Blender11ObjectCacheINS0_6vectorEE3setINS0_8MTexPolyEEEvRKNS0_9StructureERKNS2_IT_EERKNS0_7PointerE:
  686|      2|    void set(const Structure &, const vector<T> &, const Pointer &) {}
_ZN6Assimp7Blender6vectorINS0_11MDeformVertEE5resetEv:
  149|     42|    void reset() {
  150|     42|        resize(0);
  151|     42|    }
_ZN6Assimp7Blender6vectorINS0_4MColEE5resetEv:
  149|     42|    void reset() {
  150|     42|        resize(0);
  151|     42|    }
_ZNK6Assimp7Blender12FileDatabase5cacheINS0_4MColEEERNS0_11ObjectCacheINS0_6vectorEEERNS5_IT_EE:
  719|      2|    ObjectCache<vector> &cache(vector<T> & /*in*/) const {
  720|      2|        return _cacheArrays;
  721|      2|    }
_ZN6Assimp7Blender11ObjectCacheINS0_6vectorEE3getINS0_4MColEEEvRKNS0_9StructureERNS2_IT_EERKNS0_7PointerE:
  684|      1|    void get(const Structure &, vector<T> &, const Pointer &) {}
_ZNK6Assimp7Blender9Structure9_allocateINS0_4MColEEEPT_RNS0_6vectorIS4_EERm:
  356|      1|    T *_allocate(vector<T> &out, size_t &s) const {
  357|      1|        out.resize(s);
  358|      1|        return s ? &out.front() : nullptr;
  ------------------
  |  Branch (358:16): [True: 1, False: 0]
  ------------------
  359|      1|    }
_ZN6Assimp7Blender11ObjectCacheINS0_6vectorEE3setINS0_4MColEEEvRKNS0_9StructureERKNS2_IT_EERKNS0_7PointerE:
  686|      1|    void set(const Structure &, const vector<T> &, const Pointer &) {}
_ZN6Assimp7Blender6vectorINSt3__110shared_ptrINS0_8MaterialEEEE5resetEv:
  149|     42|    void reset() {
  150|     42|        resize(0);
  151|     42|    }
_ZNK6Assimp7Blender12FileDatabase5cacheINS0_8MaterialEEERNS0_11ObjectCacheINSt3__110shared_ptrEEERNS6_IT_EE:
  714|     67|    ObjectCache<std::shared_ptr> &cache(std::shared_ptr<T> & /*in*/) const {
  715|     67|        return _cache;
  716|     67|    }
_ZNK6Assimp7Blender9Structure9_allocateINS0_8MaterialEEEPT_RNSt3__110shared_ptrIS4_EERm:
  349|     28|    T *_allocate(std::shared_ptr<T> &out, size_t &s) const {
  350|     28|        out = std::shared_ptr<T>(new T());
  351|     28|        s = 1;
  352|     28|        return out.get();
  353|     28|    }
_ZN6Assimp7Blender9Structure19_defaultInitializerILi1EEclINS0_10CustomDataEEEvRT_PKc:
  395|     61|    void operator()(T &out, const char *reason = "<add reason>") {
  396|     61|        ASSIMP_LOG_WARN(reason);
  397|       |
  398|       |        // ... and let the show go on
  399|     61|        _defaultInitializer<0 /*ErrorPolicy_Igno*/>()(out);
  400|     61|    }
_ZN6Assimp7Blender9Structure19_defaultInitializerILi0EEclINS0_10CustomDataEEEvRT_PKc:
  382|     61|        void operator()(T &out, const char * = nullptr) {
  383|     61|            out = T();
  384|     61|        }
_ZNK6Assimp7Blender12FileDatabase5cacheINS0_5WorldEEERNS0_11ObjectCacheINSt3__110shared_ptrEEERNS6_IT_EE:
  714|     52|    ObjectCache<std::shared_ptr> &cache(std::shared_ptr<T> & /*in*/) const {
  715|     52|        return _cache;
  716|     52|    }
_ZNK6Assimp7Blender9Structure9_allocateINS0_5WorldEEEPT_RNSt3__110shared_ptrIS4_EERm:
  349|     26|    T *_allocate(std::shared_ptr<T> &out, size_t &s) const {
  350|     26|        out = std::shared_ptr<T>(new T());
  351|     26|        s = 1;
  352|     26|        return out.get();
  353|     26|    }
_ZNK6Assimp7Blender12FileDatabase5cacheINS0_10PackedFileEEERNS0_11ObjectCacheINSt3__110shared_ptrEEERNS6_IT_EE:
  714|      2|    ObjectCache<std::shared_ptr> &cache(std::shared_ptr<T> & /*in*/) const {
  715|      2|        return _cache;
  716|      2|    }
_ZNK6Assimp7Blender9Structure9_allocateINS0_10PackedFileEEEPT_RNSt3__110shared_ptrIS4_EERm:
  349|      1|    T *_allocate(std::shared_ptr<T> &out, size_t &s) const {
  350|      1|        out = std::shared_ptr<T>(new T());
  351|      1|        s = 1;
  352|      1|        return out.get();
  353|      1|    }
_ZN6Assimp7Blender9Structure19_defaultInitializerILi1EEclIA42_iEEvRT_PKc:
  395|     90|    void operator()(T &out, const char *reason = "<add reason>") {
  396|     90|        ASSIMP_LOG_WARN(reason);
  397|       |
  398|       |        // ... and let the show go on
  399|     90|        _defaultInitializer<0 /*ErrorPolicy_Igno*/>()(out);
  400|     90|    }
_ZN6Assimp7Blender9Structure19_defaultInitializerILi0EEclIiLj42EEEvRAT0__T_PKc:
  366|     90|        void operator()(T (&out)[N], const char * = nullptr) {
  367|  3.87k|            for (unsigned int i = 0; i < N; ++i) {
  ------------------
  |  Branch (367:38): [True: 3.78k, False: 90]
  ------------------
  368|  3.78k|                out[i] = T();
  369|  3.78k|            }
  370|     90|        }
_ZN6Assimp7Blender5ErrorC2IJRA17_KcRKiRA14_S3_EEEDpOT_:
   94|      1|            DeadlyImportError(args...) {
   95|      1|    }

_ZNK6Assimp7Blender9StructureixERKNSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEE:
   57|   365k|{
   58|   365k|    std::map<std::string, size_t>::const_iterator it = indices.find(ss);
   59|   365k|    if (it == indices.end()) {
  ------------------
  |  Branch (59:9): [True: 1.94k, False: 363k]
  ------------------
   60|  1.94k|        throw Error("BlendDNA: Did not find a field named `",ss,"` in structure `",name,"`");
   61|  1.94k|    }
   62|       |
   63|   363k|    return fields[(*it).second];
   64|   365k|}
_ZNK6Assimp7Blender9Structure3GetERKNSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEE:
   68|      6|{
   69|      6|    std::map<std::string, size_t>::const_iterator it = indices.find(ss);
   70|      6|    return it == indices.end() ? nullptr : &fields[(*it).second];
  ------------------
  |  Branch (70:12): [True: 0, False: 6]
  ------------------
   71|      6|}
_ZNK6Assimp7Blender9Structure14ResolvePointerERNSt3__110shared_ptrINS0_10FileOffsetEEERKNS0_7PointerERKNS0_12FileDatabaseERKNS0_5FieldEb:
  473|      1|{
  474|       |    // Currently used exclusively by PackedFile::data to represent
  475|       |    // a simple offset into the mapped BLEND file.
  476|      1|    out.reset();
  477|      1|    if (!ptrval.val) {
  ------------------
  |  Branch (477:9): [True: 0, False: 1]
  ------------------
  478|      0|        return false;
  479|      0|    }
  480|       |
  481|       |    // find the file block the pointer is pointing to
  482|      1|    const FileBlockHead* block = LocateFileBlockForAddress(ptrval,db);
  483|       |
  484|      1|    out =  std::shared_ptr< FileOffset > (new FileOffset());
  485|      1|    out->val = block->start+ static_cast<size_t>((ptrval.val - block->address.val) );
  486|      1|    return false;
  487|      1|}
_ZNK6Assimp7Blender9Structure14ResolvePointerINSt3__110shared_ptrENS0_8ElemBaseEEEbRT_IT0_ERKNS0_7PointerERKNS0_12FileDatabaseERKNS0_5FieldEb:
  535|    368|{
  536|       |    // Special case when the data type needs to be determined at runtime.
  537|       |    // Less secure than in the `strongly-typed` case.
  538|       |
  539|    368|    out.reset();
  540|    368|    if (!ptrval.val) {
  ------------------
  |  Branch (540:9): [True: 204, False: 164]
  ------------------
  541|    204|        return false;
  542|    204|    }
  543|       |
  544|       |    // find the file block the pointer is pointing to
  545|    164|    const FileBlockHead* block = LocateFileBlockForAddress(ptrval,db);
  546|       |
  547|       |    // determine the target type from the block header
  548|    164|    const Structure& s = db.dna[block->dna_index];
  549|       |
  550|       |    // try to retrieve the object from the cache
  551|    164|    db.cache(out).get(s,out,ptrval);
  552|    164|    if (out) {
  ------------------
  |  Branch (552:9): [True: 48, False: 116]
  ------------------
  553|     48|        return true;
  554|     48|    }
  555|       |
  556|       |    // seek to this location, but save the previous stream pointer.
  557|    116|    const StreamReaderAny::pos pold = db.reader->GetCurrentPos();
  558|    116|    db.reader->SetCurrentPos(block->start+ static_cast<size_t>((ptrval.val - block->address.val) ));
  559|       |    // FIXME: basically, this could cause problems with 64 bit pointers on 32 bit systems.
  560|       |    // I really ought to improve StreamReader to work with 64 bit indices exclusively.
  561|       |
  562|       |    // continue conversion after allocating the required storage
  563|    116|    DNA::FactoryPair builders = db.dna.GetBlobToStructureConverter(s,db);
  564|    116|    if (!builders.first) {
  ------------------
  |  Branch (564:9): [True: 0, False: 116]
  ------------------
  565|       |        // this might happen if DNA::RegisterConverters hasn't been called so far
  566|       |        // or if the target type is not contained in `our` DNA.
  567|      0|        out.reset();
  568|      0|        ASSIMP_LOG_WARN( "Failed to find a converter for the `",s.name,"` structure" );
  569|      0|        return false;
  570|      0|    }
  571|       |
  572|       |    // allocate the object hull
  573|    116|    out = (s.*builders.first)();
  574|       |
  575|       |    // cache the object immediately to prevent infinite recursion in a
  576|       |    // circular list with a single element (i.e. a self-referencing element).
  577|    116|    db.cache(out).set(s,out,ptrval);
  578|       |
  579|       |    // and do the actual conversion
  580|    116|    (s.*builders.second)(out,db);
  581|    116|    db.reader->SetCurrentPos(pold);
  582|       |
  583|       |    // store a pointer to the name string of the actual type
  584|       |    // in the object itself. This allows the conversion code
  585|       |    // to perform additional type checking.
  586|    116|    out->dna_type = s.name.c_str();
  587|       |
  588|       |
  589|    116|#ifndef ASSIMP_BUILD_BLENDER_NO_STATS
  590|    116|    ++db.stats().pointers_resolved;
  591|    116|#endif
  592|    116|    return false;
  593|    116|}
_ZNK6Assimp7Blender9Structure25LocateFileBlockForAddressERKNS0_7PointerERKNS0_12FileDatabaseE:
  597|  1.09k|{
  598|       |    // the file blocks appear in list sorted by
  599|       |    // with ascending base addresses so we can run a
  600|       |    // binary search to locate the pointer quickly.
  601|       |
  602|       |    // NOTE: Blender seems to distinguish between side-by-side
  603|       |    // data (stored in the same data block) and far pointers,
  604|       |    // which are only used for structures starting with an ID.
  605|       |    // We don't need to make this distinction, our algorithm
  606|       |    // works regardless where the data is stored.
  607|  1.09k|    vector<FileBlockHead>::const_iterator it = std::lower_bound(db.entries.begin(),db.entries.end(),ptrval);
  608|  1.09k|    if (it == db.entries.end()) {
  ------------------
  |  Branch (608:9): [True: 1, False: 1.09k]
  ------------------
  609|       |        // this is crucial, pointers may not be invalid.
  610|       |        // this is either a corrupted file or an attempted attack.
  611|      1|        throw DeadlyImportError("Failure resolving pointer 0x",
  612|      1|            std::hex,ptrval.val,", no file block falls into this address range");
  613|      1|    }
  614|  1.09k|    if (ptrval.val >= (*it).address.val + (*it).size) {
  ------------------
  |  Branch (614:9): [True: 0, False: 1.09k]
  ------------------
  615|      0|        throw DeadlyImportError("Failure resolving pointer 0x",
  616|      0|            std::hex,ptrval.val,", nearest file block starting at 0x",
  617|      0|            (*it).address.val," ends at 0x",
  618|      0|            (*it).address.val + (*it).size);
  619|      0|    }
  620|  1.09k|    return &*it;
  621|  1.09k|}
_ZNK6Assimp7Blender9Structure7ConvertIiEEvRT_RKNS0_12FileDatabaseE:
  677|   181k|{
  678|   181k|    ConvertDispatcher(dest,*this,db);
  679|   181k|}
_ZNK6Assimp7Blender9Structure7ConvertIsEEvRT_RKNS0_12FileDatabaseE:
  683|  37.2k|{
  684|       |    // automatic rescaling from short to float and vice versa (seems to be used by normals)
  685|  37.2k|    if (name == "float") {
  ------------------
  |  Branch (685:9): [True: 7, False: 37.2k]
  ------------------
  686|      7|        float f = db.reader->GetF4();
  687|      7|        if ( f > 1.0f )
  ------------------
  |  Branch (687:14): [True: 4, False: 3]
  ------------------
  688|      4|            f = 1.0f;
  689|      7|        dest = static_cast<short>( f * 32767.f);
  690|       |        //db.reader->IncPtr(-4);
  691|      7|        return;
  692|      7|    }
  693|  37.2k|    else if (name == "double") {
  ------------------
  |  Branch (693:14): [True: 0, False: 37.2k]
  ------------------
  694|      0|        dest = static_cast<short>(db.reader->GetF8() * 32767.);
  695|       |        //db.reader->IncPtr(-8);
  696|      0|        return;
  697|      0|    }
  698|  37.2k|    ConvertDispatcher(dest,*this,db);
  699|  37.2k|}
_ZNK6Assimp7Blender9Structure7ConvertIcEEvRT_RKNS0_12FileDatabaseE:
  703|   144k|{
  704|       |    // automatic rescaling from char to float and vice versa (seems useful for RGB colors)
  705|   144k|    if (name == "float") {
  ------------------
  |  Branch (705:9): [True: 0, False: 144k]
  ------------------
  706|      0|        dest = static_cast<char>(db.reader->GetF4() * 255.f);
  707|      0|        return;
  708|      0|    }
  709|   144k|    else if (name == "double") {
  ------------------
  |  Branch (709:14): [True: 0, False: 144k]
  ------------------
  710|      0|        dest = static_cast<char>(db.reader->GetF8() * 255.f);
  711|      0|        return;
  712|      0|    }
  713|   144k|    ConvertDispatcher(dest,*this,db);
  714|   144k|}
_ZNK6Assimp7Blender9Structure7ConvertIfEEvRT_RKNS0_12FileDatabaseE:
  734|   115k|{
  735|       |    // automatic rescaling from char to float and vice versa (seems useful for RGB colors)
  736|   115k|    if (name == "char") {
  ------------------
  |  Branch (736:9): [True: 0, False: 115k]
  ------------------
  737|      0|        dest = db.reader->GetI1() / 255.f;
  738|      0|        return;
  739|      0|    }
  740|       |    // automatic rescaling from short to float and vice versa (used by normals)
  741|   115k|    else if (name == "short") {
  ------------------
  |  Branch (741:14): [True: 54.0k, False: 61.0k]
  ------------------
  742|  54.0k|        dest = db.reader->GetI2() / 32767.f;
  743|  54.0k|        return;
  744|  54.0k|    }
  745|  61.0k|    ConvertDispatcher(dest,*this,db);
  746|  61.0k|}
_ZNK6Assimp7Blender9Structure7ConvertINS0_7PointerEEEvRT_RKNS0_12FileDatabaseE:
  764|  3.11k|{
  765|  3.11k|    if (db.i64bit) {
  ------------------
  |  Branch (765:9): [True: 1.55k, False: 1.56k]
  ------------------
  766|  1.55k|        dest.val = db.reader->GetU8();
  767|       |        //db.reader->IncPtr(-8);
  768|  1.55k|        return;
  769|  1.55k|    }
  770|  1.56k|    dest.val = db.reader->GetU4();
  771|       |    //db.reader->IncPtr(-4);
  772|  1.56k|}
_ZNK6Assimp7Blender3DNAixERKNSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEE:
  776|   361k|{
  777|   361k|    std::map<std::string, size_t>::const_iterator it = indices.find(ss);
  778|   361k|    if (it == indices.end()) {
  ------------------
  |  Branch (778:9): [True: 0, False: 361k]
  ------------------
  779|      0|        throw Error("BlendDNA: Did not find a structure named `",ss,"`");
  780|      0|    }
  781|       |
  782|   361k|    return structures[(*it).second];
  783|   361k|}
_ZNK6Assimp7Blender3DNA3GetERKNSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEE:
  787|     12|{
  788|     12|    std::map<std::string, size_t>::const_iterator it = indices.find(ss);
  789|     12|    return it == indices.end() ? nullptr : &structures[(*it).second];
  ------------------
  |  Branch (789:12): [True: 0, False: 12]
  ------------------
  790|     12|}
_ZNK6Assimp7Blender3DNAixEm:
  794|    766|{
  795|    766|    if (i >= structures.size()) {
  ------------------
  |  Branch (795:9): [True: 0, False: 766]
  ------------------
  796|      0|        throw Error("BlendDNA: There is no structure with index `",i,"`");
  797|      0|    }
  798|       |
  799|    766|    return structures[i];
  800|    766|}
_ZNK6Assimp7Blender11ObjectCacheINSt3__110shared_ptrEE3getINS0_8ElemBaseEEEvRKNS0_9StructureERNS3_IT_EERKNS0_7PointerE:
  807|    164|) const {
  808|       |
  809|    164|    if(s.cache_idx == static_cast<size_t>(-1)) {
  ------------------
  |  Branch (809:8): [True: 87, False: 77]
  ------------------
  810|     87|        s.cache_idx = db.next_cache_idx++;
  811|     87|        caches.resize(db.next_cache_idx);
  812|     87|        return;
  813|     87|    }
  814|       |
  815|     77|    typename StructureCache::const_iterator it = caches[s.cache_idx].find(ptr);
  816|     77|    if (it != caches[s.cache_idx].end()) {
  ------------------
  |  Branch (816:9): [True: 48, False: 29]
  ------------------
  817|     48|        out = std::static_pointer_cast<T>( (*it).second );
  818|       |
  819|     48|#ifndef ASSIMP_BUILD_BLENDER_NO_STATS
  820|     48|        ++db.stats().cache_hits;
  821|     48|#endif
  822|     48|    }
  823|       |    // otherwise, out remains untouched
  824|     77|}
_ZN6Assimp7Blender11ObjectCacheINSt3__110shared_ptrEE3setINS0_8ElemBaseEEEvRKNS0_9StructureERKNS3_IT_EERKNS0_7PointerE:
  832|    116|) {
  833|    116|    if(s.cache_idx == static_cast<size_t>(-1)) {
  ------------------
  |  Branch (833:8): [True: 0, False: 116]
  ------------------
  834|      0|        s.cache_idx = db.next_cache_idx++;
  835|      0|        caches.resize(db.next_cache_idx);
  836|      0|    }
  837|    116|    caches[s.cache_idx][ptr] = std::static_pointer_cast<ElemBase>( out );
  838|       |
  839|    116|#ifndef ASSIMP_BUILD_BLENDER_NO_STATS
  840|    116|    ++db.stats().cached_objects;
  841|    116|#endif
  842|    116|}
_ZN6Assimp7Blender17ConvertDispatcherIiEEvRT_RKNS0_9StructureERKNS0_12FileDatabaseE:
  654|   181k|{
  655|   181k|    if (in.name == "int") {
  ------------------
  |  Branch (655:9): [True: 148k, False: 33.4k]
  ------------------
  656|   148k|        out = static_cast_silent<T>()(db.reader->GetU4());
  657|   148k|    }
  658|  33.4k|    else if (in.name == "short") {
  ------------------
  |  Branch (658:14): [True: 7.77k, False: 25.6k]
  ------------------
  659|  7.77k|        out = static_cast_silent<T>()(db.reader->GetU2());
  660|  7.77k|    }
  661|  25.6k|    else if (in.name == "char") {
  ------------------
  |  Branch (661:14): [True: 25.6k, False: 0]
  ------------------
  662|  25.6k|        out = static_cast_silent<T>()(db.reader->GetU1());
  663|  25.6k|    }
  664|      0|    else if (in.name == "float") {
  ------------------
  |  Branch (664:14): [True: 0, False: 0]
  ------------------
  665|      0|        out = static_cast<T>(db.reader->GetF4());
  666|      0|    }
  667|      0|    else if (in.name == "double") {
  ------------------
  |  Branch (667:14): [True: 0, False: 0]
  ------------------
  668|      0|        out = static_cast<T>(db.reader->GetF8());
  669|      0|    }
  670|      0|    else {
  671|      0|        throw DeadlyImportError("Unknown source for conversion to primitive data type: ", in.name);
  672|      0|    }
  673|   181k|}
_ZN6Assimp7Blender18static_cast_silentIiEclIjEEiT_:
  635|   148k|    T operator()(V in) {
  636|   148k|        return static_cast<T>(in & static_cast<typename signless<T>::type>(-1));
  637|   148k|    }
_ZN6Assimp7Blender18static_cast_silentIiEclItEEiT_:
  635|  7.77k|    T operator()(V in) {
  636|  7.77k|        return static_cast<T>(in & static_cast<typename signless<T>::type>(-1));
  637|  7.77k|    }
_ZN6Assimp7Blender18static_cast_silentIiEclIhEEiT_:
  635|  25.6k|    T operator()(V in) {
  636|  25.6k|        return static_cast<T>(in & static_cast<typename signless<T>::type>(-1));
  637|  25.6k|    }
_ZN6Assimp7Blender17ConvertDispatcherIsEEvRT_RKNS0_9StructureERKNS0_12FileDatabaseE:
  654|  37.2k|{
  655|  37.2k|    if (in.name == "int") {
  ------------------
  |  Branch (655:9): [True: 14, False: 37.2k]
  ------------------
  656|     14|        out = static_cast_silent<T>()(db.reader->GetU4());
  657|     14|    }
  658|  37.2k|    else if (in.name == "short") {
  ------------------
  |  Branch (658:14): [True: 37.2k, False: 46]
  ------------------
  659|  37.2k|        out = static_cast_silent<T>()(db.reader->GetU2());
  660|  37.2k|    }
  661|     46|    else if (in.name == "char") {
  ------------------
  |  Branch (661:14): [True: 46, False: 0]
  ------------------
  662|     46|        out = static_cast_silent<T>()(db.reader->GetU1());
  663|     46|    }
  664|      0|    else if (in.name == "float") {
  ------------------
  |  Branch (664:14): [True: 0, False: 0]
  ------------------
  665|      0|        out = static_cast<T>(db.reader->GetF4());
  666|      0|    }
  667|      0|    else if (in.name == "double") {
  ------------------
  |  Branch (667:14): [True: 0, False: 0]
  ------------------
  668|      0|        out = static_cast<T>(db.reader->GetF8());
  669|      0|    }
  670|      0|    else {
  671|      0|        throw DeadlyImportError("Unknown source for conversion to primitive data type: ", in.name);
  672|      0|    }
  673|  37.2k|}
_ZN6Assimp7Blender18static_cast_silentIsEclIjEEsT_:
  635|     14|    T operator()(V in) {
  636|     14|        return static_cast<T>(in & static_cast<typename signless<T>::type>(-1));
  637|     14|    }
_ZN6Assimp7Blender18static_cast_silentIsEclItEEsT_:
  635|  37.2k|    T operator()(V in) {
  636|  37.2k|        return static_cast<T>(in & static_cast<typename signless<T>::type>(-1));
  637|  37.2k|    }
_ZN6Assimp7Blender18static_cast_silentIsEclIhEEsT_:
  635|     46|    T operator()(V in) {
  636|     46|        return static_cast<T>(in & static_cast<typename signless<T>::type>(-1));
  637|     46|    }
_ZN6Assimp7Blender17ConvertDispatcherIcEEvRT_RKNS0_9StructureERKNS0_12FileDatabaseE:
  654|   144k|{
  655|   144k|    if (in.name == "int") {
  ------------------
  |  Branch (655:9): [True: 0, False: 144k]
  ------------------
  656|      0|        out = static_cast_silent<T>()(db.reader->GetU4());
  657|      0|    }
  658|   144k|    else if (in.name == "short") {
  ------------------
  |  Branch (658:14): [True: 0, False: 144k]
  ------------------
  659|      0|        out = static_cast_silent<T>()(db.reader->GetU2());
  660|      0|    }
  661|   144k|    else if (in.name == "char") {
  ------------------
  |  Branch (661:14): [True: 144k, False: 0]
  ------------------
  662|   144k|        out = static_cast_silent<T>()(db.reader->GetU1());
  663|   144k|    }
  664|      0|    else if (in.name == "float") {
  ------------------
  |  Branch (664:14): [True: 0, False: 0]
  ------------------
  665|      0|        out = static_cast<T>(db.reader->GetF4());
  666|      0|    }
  667|      0|    else if (in.name == "double") {
  ------------------
  |  Branch (667:14): [True: 0, False: 0]
  ------------------
  668|      0|        out = static_cast<T>(db.reader->GetF8());
  669|      0|    }
  670|      0|    else {
  671|      0|        throw DeadlyImportError("Unknown source for conversion to primitive data type: ", in.name);
  672|      0|    }
  673|   144k|}
_ZN6Assimp7Blender18static_cast_silentIcEclIhEEcT_:
  635|   144k|    T operator()(V in) {
  636|   144k|        return static_cast<T>(in & static_cast<typename signless<T>::type>(-1));
  637|   144k|    }
_ZN6Assimp7Blender17ConvertDispatcherIfEEvRT_RKNS0_9StructureERKNS0_12FileDatabaseE:
  654|  61.0k|{
  655|  61.0k|    if (in.name == "int") {
  ------------------
  |  Branch (655:9): [True: 0, False: 61.0k]
  ------------------
  656|      0|        out = static_cast_silent<T>()(db.reader->GetU4());
  657|      0|    }
  658|  61.0k|    else if (in.name == "short") {
  ------------------
  |  Branch (658:14): [True: 0, False: 61.0k]
  ------------------
  659|      0|        out = static_cast_silent<T>()(db.reader->GetU2());
  660|      0|    }
  661|  61.0k|    else if (in.name == "char") {
  ------------------
  |  Branch (661:14): [True: 0, False: 61.0k]
  ------------------
  662|      0|        out = static_cast_silent<T>()(db.reader->GetU1());
  663|      0|    }
  664|  61.0k|    else if (in.name == "float") {
  ------------------
  |  Branch (664:14): [True: 61.0k, False: 0]
  ------------------
  665|  61.0k|        out = static_cast<T>(db.reader->GetF4());
  666|  61.0k|    }
  667|      0|    else if (in.name == "double") {
  ------------------
  |  Branch (667:14): [True: 0, False: 0]
  ------------------
  668|      0|        out = static_cast<T>(db.reader->GetF8());
  669|      0|    }
  670|      0|    else {
  671|      0|        throw DeadlyImportError("Unknown source for conversion to primitive data type: ", in.name);
  672|      0|    }
  673|  61.0k|}
_ZNK6Assimp7Blender9Structure9ReadFieldILi2ENS0_2IDEEEvRT0_PKcRKNS0_12FileDatabaseE:
  282|    290|{
  283|    290|    const StreamReaderAny::pos old = db.reader->GetCurrentPos();
  284|    290|    try {
  285|    290|        const Field& f = (*this)[name];
  286|       |        // find the structure definition pertaining to this field
  287|    290|        const Structure& s = db.dna[f.type];
  288|       |
  289|    290|        db.reader->IncPtr(f.offset);
  290|    290|        s.Convert(out,db);
  291|    290|    }
  292|    290|    catch (const Error& e) {
  293|      0|        _defaultInitializer<error_policy>()(out,e.what());
  294|      0|    }
  295|       |
  296|       |    // and recover the previous stream position
  297|    290|    db.reader->SetCurrentPos(old);
  298|       |
  299|    290|#ifndef ASSIMP_BUILD_BLENDER_NO_STATS
  300|    290|    ++db.stats().fields_read;
  301|    290|#endif
  302|    290|}
_ZNK6Assimp7Blender9Structure9ReadFieldILi2EiEEvRT0_PKcRKNS0_12FileDatabaseE:
  282|   146k|{
  283|   146k|    const StreamReaderAny::pos old = db.reader->GetCurrentPos();
  284|   146k|    try {
  285|   146k|        const Field& f = (*this)[name];
  286|       |        // find the structure definition pertaining to this field
  287|   146k|        const Structure& s = db.dna[f.type];
  288|       |
  289|   146k|        db.reader->IncPtr(f.offset);
  290|   146k|        s.Convert(out,db);
  291|   146k|    }
  292|   146k|    catch (const Error& e) {
  293|      0|        _defaultInitializer<error_policy>()(out,e.what());
  294|      0|    }
  295|       |
  296|       |    // and recover the previous stream position
  297|   146k|    db.reader->SetCurrentPos(old);
  298|       |
  299|   146k|#ifndef ASSIMP_BUILD_BLENDER_NO_STATS
  300|   146k|    ++db.stats().fields_read;
  301|   146k|#endif
  302|   146k|}
_ZNK6Assimp7Blender9Structure15ReadFieldArray2ILi1EfLm4ELm4EEEvRAT1__AT2__T0_PKcRKNS0_12FileDatabaseE:
  137|    200|{
  138|    200|    const StreamReaderAny::pos old = db.reader->GetCurrentPos();
  139|    200|    try {
  140|    200|        const Field& f = (*this)[name];
  141|    200|        const Structure& s = db.dna[f.type];
  142|       |
  143|       |        // is the input actually an array?
  144|    200|        if (!(f.flags & FieldFlag_Array)) {
  ------------------
  |  Branch (144:13): [True: 0, False: 200]
  ------------------
  145|      0|            throw Error("Field `",name,"` of structure `",
  146|      0|                this->name,"` ought to be an array of size ",M,"*",N
  147|      0|                );
  148|      0|        }
  149|       |
  150|    200|        db.reader->IncPtr(f.offset);
  151|       |
  152|       |        // size conversions are always allowed, regardless of error_policy
  153|    200|        unsigned int i = 0;
  154|  1.00k|        for(; i < std::min(f.array_sizes[0],M); ++i) {
  ------------------
  |  Branch (154:15): [True: 800, False: 200]
  ------------------
  155|    800|            unsigned int j = 0;
  156|  4.00k|            for(; j < std::min(f.array_sizes[1],N); ++j) {
  ------------------
  |  Branch (156:19): [True: 3.20k, False: 800]
  ------------------
  157|  3.20k|                s.Convert(out[i][j],db);
  158|  3.20k|            }
  159|    800|            for(; j < N; ++j) {
  ------------------
  |  Branch (159:19): [True: 0, False: 800]
  ------------------
  160|      0|                _defaultInitializer<ErrorPolicy_Igno>()(out[i][j]);
  161|      0|            }
  162|    800|        }
  163|    200|        for(; i < M; ++i) {
  ------------------
  |  Branch (163:15): [True: 0, False: 200]
  ------------------
  164|      0|            _defaultInitializer<ErrorPolicy_Igno>()(out[i]);
  165|      0|        }
  166|    200|    }
  167|    200|    catch (const Error& e) {
  168|      0|        _defaultInitializer<error_policy>()(out,e.what());
  169|      0|    }
  170|       |
  171|       |    // and recover the previous stream position
  172|    200|    db.reader->SetCurrentPos(old);
  173|       |
  174|    200|#ifndef ASSIMP_BUILD_BLENDER_NO_STATS
  175|    200|    ++db.stats().fields_read;
  176|    200|#endif
  177|    200|}
_ZNK6Assimp7Blender9Structure14ReadFieldArrayILi1EcLm32EEEvRAT1__T0_PKcRKNS0_12FileDatabaseE:
  100|    134|{
  101|    134|    const StreamReaderAny::pos old = db.reader->GetCurrentPos();
  102|    134|    try {
  103|    134|        const Field& f = (*this)[name];
  104|    134|        const Structure& s = db.dna[f.type];
  105|       |
  106|       |        // is the input actually an array?
  107|    134|        if (!(f.flags & FieldFlag_Array)) {
  ------------------
  |  Branch (107:13): [True: 0, False: 134]
  ------------------
  108|      0|            throw Error("Field `",name,"` of structure `",this->name,"` ought to be an array of size ",M);
  109|      0|        }
  110|       |
  111|    134|        db.reader->IncPtr(f.offset);
  112|       |
  113|       |        // size conversions are always allowed, regardless of error_policy
  114|    134|        unsigned int i = 0;
  115|  4.42k|        for(; i < std::min(f.array_sizes[0],M); ++i) {
  ------------------
  |  Branch (115:15): [True: 4.28k, False: 134]
  ------------------
  116|  4.28k|            s.Convert(out[i],db);
  117|  4.28k|        }
  118|    134|        for(; i < M; ++i) {
  ------------------
  |  Branch (118:15): [True: 0, False: 134]
  ------------------
  119|      0|            _defaultInitializer<ErrorPolicy_Igno>()(out[i]);
  120|      0|        }
  121|    134|    }
  122|    134|    catch (const Error& e) {
  123|      0|        _defaultInitializer<error_policy>()(out,e.what());
  124|      0|    }
  125|       |
  126|       |    // and recover the previous stream position
  127|    134|    db.reader->SetCurrentPos(old);
  128|       |
  129|    134|#ifndef ASSIMP_BUILD_BLENDER_NO_STATS
  130|    134|    ++db.stats().fields_read;
  131|    134|#endif
  132|    134|}
_ZNK6Assimp7Blender9Structure12ReadFieldPtrILi1ENSt3__110shared_ptrENS0_6ObjectEEEbRT0_IT1_EPKcRKNS0_12FileDatabaseEb:
  183|    655|{
  184|    655|    const StreamReaderAny::pos old = db.reader->GetCurrentPos();
  185|    655|    Pointer ptrval;
  186|    655|    const Field* f;
  187|    655|    try {
  188|    655|        f = &(*this)[name];
  189|       |
  190|       |        // sanity check, should never happen if the genblenddna script is right
  191|    655|        if (!(f->flags & FieldFlag_Pointer)) {
  ------------------
  |  Branch (191:13): [True: 0, False: 655]
  ------------------
  192|      0|            throw Error("Field `",name,"` of structure `",
  193|      0|                this->name,"` ought to be a pointer");
  194|      0|        }
  195|       |
  196|    655|        db.reader->IncPtr(f->offset);
  197|    655|        Convert(ptrval,db);
  198|       |        // actually it is meaningless on which Structure the Convert is called
  199|       |        // because the `Pointer` argument triggers a special implementation.
  200|    655|    }
  201|    655|    catch (const Error& e) {
  202|      0|        _defaultInitializer<error_policy>()(out,e.what());
  203|       |
  204|      0|        out.reset();
  205|      0|        return false;
  206|      0|    }
  207|       |
  208|       |    // resolve the pointer and load the corresponding structure
  209|    655|    const bool res = ResolvePointer(out,ptrval,db,*f, non_recursive);
  210|       |
  211|    655|    if(!non_recursive) {
  ------------------
  |  Branch (211:8): [True: 654, False: 1]
  ------------------
  212|       |        // and recover the previous stream position
  213|    654|        db.reader->SetCurrentPos(old);
  214|    654|    }
  215|       |
  216|    655|#ifndef ASSIMP_BUILD_BLENDER_NO_STATS
  217|    655|    ++db.stats().fields_read;
  218|    655|#endif
  219|       |
  220|    655|    return res;
  221|    655|}
_ZNK6Assimp7Blender9Structure14ResolvePointerINSt3__110shared_ptrENS0_6ObjectEEEbRT_IT0_ERKNS0_7PointerERKNS0_12FileDatabaseERKNS0_5FieldEb:
  412|    655|{
  413|    655|    out.reset(); // ensure null pointers work
  414|    655|    if (!ptrval.val) {
  ------------------
  |  Branch (414:9): [True: 520, False: 135]
  ------------------
  415|    520|        return false;
  416|    520|    }
  417|    135|    const Structure& s = db.dna[f.type];
  418|       |    // find the file block the pointer is pointing to
  419|    135|    const FileBlockHead* block = LocateFileBlockForAddress(ptrval,db);
  420|       |
  421|       |    // also determine the target type from the block header
  422|       |    // and check if it matches the type which we expect.
  423|    135|    const Structure& ss = db.dna[block->dna_index];
  424|    135|    if (ss != s) {
  ------------------
  |  Branch (424:9): [True: 0, False: 135]
  ------------------
  425|      0|        throw Error("Expected target to be of type `",s.name,
  426|      0|            "` but seemingly it is a `",ss.name,"` instead"
  427|      0|            );
  428|      0|    }
  429|       |
  430|       |    // try to retrieve the object from the cache
  431|    135|    db.cache(out).get(s,out,ptrval);
  432|    135|    if (out) {
  ------------------
  |  Branch (432:9): [True: 35, False: 100]
  ------------------
  433|     35|        return true;
  434|     35|    }
  435|       |
  436|       |    // seek to this location, but save the previous stream pointer.
  437|    100|    const StreamReaderAny::pos pold = db.reader->GetCurrentPos();
  438|    100|    db.reader->SetCurrentPos(block->start+ static_cast<size_t>((ptrval.val - block->address.val) ));
  439|       |    // FIXME: basically, this could cause problems with 64 bit pointers on 32 bit systems.
  440|       |    // I really ought to improve StreamReader to work with 64 bit indices exclusively.
  441|       |
  442|       |    // continue conversion after allocating the required storage
  443|    100|    size_t num = block->size / ss.size;
  444|    100|    T* o = _allocate(out,num);
  445|       |
  446|       |    // cache the object before we convert it to avoid cyclic recursion.
  447|    100|    db.cache(out).set(s,out,ptrval);
  448|       |
  449|       |    // if the non_recursive flag is set, we don't do anything but leave
  450|       |    // the cursor at the correct position to resolve the object.
  451|    100|    if (!non_recursive) {
  ------------------
  |  Branch (451:9): [True: 100, False: 0]
  ------------------
  452|    200|        for (size_t i = 0; i < num; ++i,++o) {
  ------------------
  |  Branch (452:28): [True: 100, False: 100]
  ------------------
  453|    100|            s.Convert(*o,db);
  454|    100|        }
  455|       |
  456|    100|        db.reader->SetCurrentPos(pold);
  457|    100|    }
  458|       |
  459|    100|#ifndef ASSIMP_BUILD_BLENDER_NO_STATS
  460|    100|    if(out) {
  ------------------
  |  Branch (460:8): [True: 99, False: 1]
  ------------------
  461|     99|        ++db.stats().pointers_resolved;
  462|     99|    }
  463|    100|#endif
  464|    100|    return false;
  465|    135|}
_ZNK6Assimp7Blender11ObjectCacheINSt3__110shared_ptrEE3getINS0_6ObjectEEEvRKNS0_9StructureERNS3_IT_EERKNS0_7PointerE:
  807|    135|) const {
  808|       |
  809|    135|    if(s.cache_idx == static_cast<size_t>(-1)) {
  ------------------
  |  Branch (809:8): [True: 26, False: 109]
  ------------------
  810|     26|        s.cache_idx = db.next_cache_idx++;
  811|     26|        caches.resize(db.next_cache_idx);
  812|     26|        return;
  813|     26|    }
  814|       |
  815|    109|    typename StructureCache::const_iterator it = caches[s.cache_idx].find(ptr);
  816|    109|    if (it != caches[s.cache_idx].end()) {
  ------------------
  |  Branch (816:9): [True: 35, False: 74]
  ------------------
  817|     35|        out = std::static_pointer_cast<T>( (*it).second );
  818|       |
  819|     35|#ifndef ASSIMP_BUILD_BLENDER_NO_STATS
  820|     35|        ++db.stats().cache_hits;
  821|     35|#endif
  822|     35|    }
  823|       |    // otherwise, out remains untouched
  824|    109|}
_ZN6Assimp7Blender11ObjectCacheINSt3__110shared_ptrEE3setINS0_6ObjectEEEvRKNS0_9StructureERKNS3_IT_EERKNS0_7PointerE:
  832|    100|) {
  833|    100|    if(s.cache_idx == static_cast<size_t>(-1)) {
  ------------------
  |  Branch (833:8): [True: 0, False: 100]
  ------------------
  834|      0|        s.cache_idx = db.next_cache_idx++;
  835|      0|        caches.resize(db.next_cache_idx);
  836|      0|    }
  837|    100|    caches[s.cache_idx][ptr] = std::static_pointer_cast<ElemBase>( out );
  838|       |
  839|    100|#ifndef ASSIMP_BUILD_BLENDER_NO_STATS
  840|    100|    ++db.stats().cached_objects;
  841|    100|#endif
  842|    100|}
_ZNK6Assimp7Blender9Structure12ReadFieldPtrILi1ENSt3__110shared_ptrENS0_5GroupEEEbRT0_IT1_EPKcRKNS0_12FileDatabaseEb:
  183|    128|{
  184|    128|    const StreamReaderAny::pos old = db.reader->GetCurrentPos();
  185|    128|    Pointer ptrval;
  186|    128|    const Field* f;
  187|    128|    try {
  188|    128|        f = &(*this)[name];
  189|       |
  190|       |        // sanity check, should never happen if the genblenddna script is right
  191|    128|        if (!(f->flags & FieldFlag_Pointer)) {
  ------------------
  |  Branch (191:13): [True: 0, False: 128]
  ------------------
  192|      0|            throw Error("Field `",name,"` of structure `",
  193|      0|                this->name,"` ought to be a pointer");
  194|      0|        }
  195|       |
  196|    128|        db.reader->IncPtr(f->offset);
  197|    128|        Convert(ptrval,db);
  198|       |        // actually it is meaningless on which Structure the Convert is called
  199|       |        // because the `Pointer` argument triggers a special implementation.
  200|    128|    }
  201|    128|    catch (const Error& e) {
  202|      1|        _defaultInitializer<error_policy>()(out,e.what());
  203|       |
  204|      1|        out.reset();
  205|      1|        return false;
  206|      1|    }
  207|       |
  208|       |    // resolve the pointer and load the corresponding structure
  209|    127|    const bool res = ResolvePointer(out,ptrval,db,*f, non_recursive);
  210|       |
  211|    127|    if(!non_recursive) {
  ------------------
  |  Branch (211:8): [True: 127, False: 0]
  ------------------
  212|       |        // and recover the previous stream position
  213|    127|        db.reader->SetCurrentPos(old);
  214|    127|    }
  215|       |
  216|    127|#ifndef ASSIMP_BUILD_BLENDER_NO_STATS
  217|    127|    ++db.stats().fields_read;
  218|    127|#endif
  219|       |
  220|    127|    return res;
  221|    128|}
_ZNK6Assimp7Blender9Structure14ResolvePointerINSt3__110shared_ptrENS0_5GroupEEEbRT_IT0_ERKNS0_7PointerERKNS0_12FileDatabaseERKNS0_5FieldEb:
  412|    127|{
  413|    127|    out.reset(); // ensure null pointers work
  414|    127|    if (!ptrval.val) {
  ------------------
  |  Branch (414:9): [True: 127, False: 0]
  ------------------
  415|    127|        return false;
  416|    127|    }
  417|      0|    const Structure& s = db.dna[f.type];
  418|       |    // find the file block the pointer is pointing to
  419|      0|    const FileBlockHead* block = LocateFileBlockForAddress(ptrval,db);
  420|       |
  421|       |    // also determine the target type from the block header
  422|       |    // and check if it matches the type which we expect.
  423|      0|    const Structure& ss = db.dna[block->dna_index];
  424|      0|    if (ss != s) {
  ------------------
  |  Branch (424:9): [True: 0, False: 0]
  ------------------
  425|      0|        throw Error("Expected target to be of type `",s.name,
  426|      0|            "` but seemingly it is a `",ss.name,"` instead"
  427|      0|            );
  428|      0|    }
  429|       |
  430|       |    // try to retrieve the object from the cache
  431|      0|    db.cache(out).get(s,out,ptrval);
  432|      0|    if (out) {
  ------------------
  |  Branch (432:9): [True: 0, False: 0]
  ------------------
  433|      0|        return true;
  434|      0|    }
  435|       |
  436|       |    // seek to this location, but save the previous stream pointer.
  437|      0|    const StreamReaderAny::pos pold = db.reader->GetCurrentPos();
  438|      0|    db.reader->SetCurrentPos(block->start+ static_cast<size_t>((ptrval.val - block->address.val) ));
  439|       |    // FIXME: basically, this could cause problems with 64 bit pointers on 32 bit systems.
  440|       |    // I really ought to improve StreamReader to work with 64 bit indices exclusively.
  441|       |
  442|       |    // continue conversion after allocating the required storage
  443|      0|    size_t num = block->size / ss.size;
  444|      0|    T* o = _allocate(out,num);
  445|       |
  446|       |    // cache the object before we convert it to avoid cyclic recursion.
  447|      0|    db.cache(out).set(s,out,ptrval);
  448|       |
  449|       |    // if the non_recursive flag is set, we don't do anything but leave
  450|       |    // the cursor at the correct position to resolve the object.
  451|      0|    if (!non_recursive) {
  ------------------
  |  Branch (451:9): [True: 0, False: 0]
  ------------------
  452|      0|        for (size_t i = 0; i < num; ++i,++o) {
  ------------------
  |  Branch (452:28): [True: 0, False: 0]
  ------------------
  453|      0|            s.Convert(*o,db);
  454|      0|        }
  455|       |
  456|      0|        db.reader->SetCurrentPos(pold);
  457|      0|    }
  458|       |
  459|      0|#ifndef ASSIMP_BUILD_BLENDER_NO_STATS
  460|      0|    if(out) {
  ------------------
  |  Branch (460:8): [True: 0, False: 0]
  ------------------
  461|      0|        ++db.stats().pointers_resolved;
  462|      0|    }
  463|      0|#endif
  464|      0|    return false;
  465|      0|}
_ZNK6Assimp7Blender9Structure12ReadFieldPtrILi2ENSt3__110shared_ptrENS0_8ElemBaseEEEbRT0_IT1_EPKcRKNS0_12FileDatabaseEb:
  183|    100|{
  184|    100|    const StreamReaderAny::pos old = db.reader->GetCurrentPos();
  185|    100|    Pointer ptrval;
  186|    100|    const Field* f;
  187|    100|    try {
  188|    100|        f = &(*this)[name];
  189|       |
  190|       |        // sanity check, should never happen if the genblenddna script is right
  191|    100|        if (!(f->flags & FieldFlag_Pointer)) {
  ------------------
  |  Branch (191:13): [True: 0, False: 100]
  ------------------
  192|      0|            throw Error("Field `",name,"` of structure `",
  193|      0|                this->name,"` ought to be a pointer");
  194|      0|        }
  195|       |
  196|    100|        db.reader->IncPtr(f->offset);
  197|    100|        Convert(ptrval,db);
  198|       |        // actually it is meaningless on which Structure the Convert is called
  199|       |        // because the `Pointer` argument triggers a special implementation.
  200|    100|    }
  201|    100|    catch (const Error& e) {
  202|      0|        _defaultInitializer<error_policy>()(out,e.what());
  203|       |
  204|      0|        out.reset();
  205|      0|        return false;
  206|      0|    }
  207|       |
  208|       |    // resolve the pointer and load the corresponding structure
  209|    100|    const bool res = ResolvePointer(out,ptrval,db,*f, non_recursive);
  210|       |
  211|    100|    if(!non_recursive) {
  ------------------
  |  Branch (211:8): [True: 99, False: 1]
  ------------------
  212|       |        // and recover the previous stream position
  213|     99|        db.reader->SetCurrentPos(old);
  214|     99|    }
  215|       |
  216|    100|#ifndef ASSIMP_BUILD_BLENDER_NO_STATS
  217|    100|    ++db.stats().fields_read;
  218|    100|#endif
  219|       |
  220|    100|    return res;
  221|    100|}
_ZNK6Assimp7Blender9Structure9ReadFieldILi1ENS0_8ListBaseEEEvRT0_PKcRKNS0_12FileDatabaseE:
  282|    124|{
  283|    124|    const StreamReaderAny::pos old = db.reader->GetCurrentPos();
  284|    124|    try {
  285|    124|        const Field& f = (*this)[name];
  286|       |        // find the structure definition pertaining to this field
  287|    124|        const Structure& s = db.dna[f.type];
  288|       |
  289|    124|        db.reader->IncPtr(f.offset);
  290|    124|        s.Convert(out,db);
  291|    124|    }
  292|    124|    catch (const Error& e) {
  293|      0|        _defaultInitializer<error_policy>()(out,e.what());
  294|      0|    }
  295|       |
  296|       |    // and recover the previous stream position
  297|    124|    db.reader->SetCurrentPos(old);
  298|       |
  299|    124|#ifndef ASSIMP_BUILD_BLENDER_NO_STATS
  300|    124|    ++db.stats().fields_read;
  301|    124|#endif
  302|    124|}
_ZNK6Assimp7Blender9Structure9ReadFieldILi1EiEEvRT0_PKcRKNS0_12FileDatabaseE:
  282|  34.3k|{
  283|  34.3k|    const StreamReaderAny::pos old = db.reader->GetCurrentPos();
  284|  34.3k|    try {
  285|  34.3k|        const Field& f = (*this)[name];
  286|       |        // find the structure definition pertaining to this field
  287|  34.3k|        const Structure& s = db.dna[f.type];
  288|       |
  289|  34.3k|        db.reader->IncPtr(f.offset);
  290|  34.3k|        s.Convert(out,db);
  291|  34.3k|    }
  292|  34.3k|    catch (const Error& e) {
  293|  1.21k|        _defaultInitializer<error_policy>()(out,e.what());
  294|  1.21k|    }
  295|       |
  296|       |    // and recover the previous stream position
  297|  34.3k|    db.reader->SetCurrentPos(old);
  298|       |
  299|  34.3k|#ifndef ASSIMP_BUILD_BLENDER_NO_STATS
  300|  34.3k|    ++db.stats().fields_read;
  301|  34.3k|#endif
  302|  34.3k|}
_ZNK6Assimp7Blender9Structure12ReadFieldPtrILi2ENSt3__110shared_ptrENS0_16CollectionObjectEEEbRT0_IT1_EPKcRKNS0_12FileDatabaseEb:
  183|      3|{
  184|      3|    const StreamReaderAny::pos old = db.reader->GetCurrentPos();
  185|      3|    Pointer ptrval;
  186|      3|    const Field* f;
  187|      3|    try {
  188|      3|        f = &(*this)[name];
  189|       |
  190|       |        // sanity check, should never happen if the genblenddna script is right
  191|      3|        if (!(f->flags & FieldFlag_Pointer)) {
  ------------------
  |  Branch (191:13): [True: 0, False: 3]
  ------------------
  192|      0|            throw Error("Field `",name,"` of structure `",
  193|      0|                this->name,"` ought to be a pointer");
  194|      0|        }
  195|       |
  196|      3|        db.reader->IncPtr(f->offset);
  197|      3|        Convert(ptrval,db);
  198|       |        // actually it is meaningless on which Structure the Convert is called
  199|       |        // because the `Pointer` argument triggers a special implementation.
  200|      3|    }
  201|      3|    catch (const Error& e) {
  202|      0|        _defaultInitializer<error_policy>()(out,e.what());
  203|       |
  204|      0|        out.reset();
  205|      0|        return false;
  206|      0|    }
  207|       |
  208|       |    // resolve the pointer and load the corresponding structure
  209|      3|    const bool res = ResolvePointer(out,ptrval,db,*f, non_recursive);
  210|       |
  211|      3|    if(!non_recursive) {
  ------------------
  |  Branch (211:8): [True: 3, False: 0]
  ------------------
  212|       |        // and recover the previous stream position
  213|      3|        db.reader->SetCurrentPos(old);
  214|      3|    }
  215|       |
  216|      3|#ifndef ASSIMP_BUILD_BLENDER_NO_STATS
  217|      3|    ++db.stats().fields_read;
  218|      3|#endif
  219|       |
  220|      3|    return res;
  221|      3|}
_ZNK6Assimp7Blender9Structure14ResolvePointerINSt3__110shared_ptrENS0_16CollectionObjectEEEbRT_IT0_ERKNS0_7PointerERKNS0_12FileDatabaseERKNS0_5FieldEb:
  412|      3|{
  413|      3|    out.reset(); // ensure null pointers work
  414|      3|    if (!ptrval.val) {
  ------------------
  |  Branch (414:9): [True: 1, False: 2]
  ------------------
  415|      1|        return false;
  416|      1|    }
  417|      2|    const Structure& s = db.dna[f.type];
  418|       |    // find the file block the pointer is pointing to
  419|      2|    const FileBlockHead* block = LocateFileBlockForAddress(ptrval,db);
  420|       |
  421|       |    // also determine the target type from the block header
  422|       |    // and check if it matches the type which we expect.
  423|      2|    const Structure& ss = db.dna[block->dna_index];
  424|      2|    if (ss != s) {
  ------------------
  |  Branch (424:9): [True: 0, False: 2]
  ------------------
  425|      0|        throw Error("Expected target to be of type `",s.name,
  426|      0|            "` but seemingly it is a `",ss.name,"` instead"
  427|      0|            );
  428|      0|    }
  429|       |
  430|       |    // try to retrieve the object from the cache
  431|      2|    db.cache(out).get(s,out,ptrval);
  432|      2|    if (out) {
  ------------------
  |  Branch (432:9): [True: 0, False: 2]
  ------------------
  433|      0|        return true;
  434|      0|    }
  435|       |
  436|       |    // seek to this location, but save the previous stream pointer.
  437|      2|    const StreamReaderAny::pos pold = db.reader->GetCurrentPos();
  438|      2|    db.reader->SetCurrentPos(block->start+ static_cast<size_t>((ptrval.val - block->address.val) ));
  439|       |    // FIXME: basically, this could cause problems with 64 bit pointers on 32 bit systems.
  440|       |    // I really ought to improve StreamReader to work with 64 bit indices exclusively.
  441|       |
  442|       |    // continue conversion after allocating the required storage
  443|      2|    size_t num = block->size / ss.size;
  444|      2|    T* o = _allocate(out,num);
  445|       |
  446|       |    // cache the object before we convert it to avoid cyclic recursion.
  447|      2|    db.cache(out).set(s,out,ptrval);
  448|       |
  449|       |    // if the non_recursive flag is set, we don't do anything but leave
  450|       |    // the cursor at the correct position to resolve the object.
  451|      2|    if (!non_recursive) {
  ------------------
  |  Branch (451:9): [True: 2, False: 0]
  ------------------
  452|      4|        for (size_t i = 0; i < num; ++i,++o) {
  ------------------
  |  Branch (452:28): [True: 2, False: 2]
  ------------------
  453|      2|            s.Convert(*o,db);
  454|      2|        }
  455|       |
  456|      2|        db.reader->SetCurrentPos(pold);
  457|      2|    }
  458|       |
  459|      2|#ifndef ASSIMP_BUILD_BLENDER_NO_STATS
  460|      2|    if(out) {
  ------------------
  |  Branch (460:8): [True: 2, False: 0]
  ------------------
  461|      2|        ++db.stats().pointers_resolved;
  462|      2|    }
  463|      2|#endif
  464|      2|    return false;
  465|      2|}
_ZNK6Assimp7Blender11ObjectCacheINSt3__110shared_ptrEE3getINS0_16CollectionObjectEEEvRKNS0_9StructureERNS3_IT_EERKNS0_7PointerE:
  807|      2|) const {
  808|       |
  809|      2|    if(s.cache_idx == static_cast<size_t>(-1)) {
  ------------------
  |  Branch (809:8): [True: 0, False: 2]
  ------------------
  810|      0|        s.cache_idx = db.next_cache_idx++;
  811|      0|        caches.resize(db.next_cache_idx);
  812|      0|        return;
  813|      0|    }
  814|       |
  815|      2|    typename StructureCache::const_iterator it = caches[s.cache_idx].find(ptr);
  816|      2|    if (it != caches[s.cache_idx].end()) {
  ------------------
  |  Branch (816:9): [True: 0, False: 2]
  ------------------
  817|      0|        out = std::static_pointer_cast<T>( (*it).second );
  818|       |
  819|      0|#ifndef ASSIMP_BUILD_BLENDER_NO_STATS
  820|      0|        ++db.stats().cache_hits;
  821|      0|#endif
  822|      0|    }
  823|       |    // otherwise, out remains untouched
  824|      2|}
_ZN6Assimp7Blender11ObjectCacheINSt3__110shared_ptrEE3setINS0_16CollectionObjectEEEvRKNS0_9StructureERKNS3_IT_EERKNS0_7PointerE:
  832|      2|) {
  833|      2|    if(s.cache_idx == static_cast<size_t>(-1)) {
  ------------------
  |  Branch (833:8): [True: 0, False: 2]
  ------------------
  834|      0|        s.cache_idx = db.next_cache_idx++;
  835|      0|        caches.resize(db.next_cache_idx);
  836|      0|    }
  837|      2|    caches[s.cache_idx][ptr] = std::static_pointer_cast<ElemBase>( out );
  838|       |
  839|      2|#ifndef ASSIMP_BUILD_BLENDER_NO_STATS
  840|      2|    ++db.stats().cached_objects;
  841|      2|#endif
  842|      2|}
_ZNK6Assimp7Blender9Structure12ReadFieldPtrILi2ENSt3__110shared_ptrENS0_15CollectionChildEEEbRT0_IT1_EPKcRKNS0_12FileDatabaseEb:
  183|      2|{
  184|      2|    const StreamReaderAny::pos old = db.reader->GetCurrentPos();
  185|      2|    Pointer ptrval;
  186|      2|    const Field* f;
  187|      2|    try {
  188|      2|        f = &(*this)[name];
  189|       |
  190|       |        // sanity check, should never happen if the genblenddna script is right
  191|      2|        if (!(f->flags & FieldFlag_Pointer)) {
  ------------------
  |  Branch (191:13): [True: 0, False: 2]
  ------------------
  192|      0|            throw Error("Field `",name,"` of structure `",
  193|      0|                this->name,"` ought to be a pointer");
  194|      0|        }
  195|       |
  196|      2|        db.reader->IncPtr(f->offset);
  197|      2|        Convert(ptrval,db);
  198|       |        // actually it is meaningless on which Structure the Convert is called
  199|       |        // because the `Pointer` argument triggers a special implementation.
  200|      2|    }
  201|      2|    catch (const Error& e) {
  202|      0|        _defaultInitializer<error_policy>()(out,e.what());
  203|       |
  204|      0|        out.reset();
  205|      0|        return false;
  206|      0|    }
  207|       |
  208|       |    // resolve the pointer and load the corresponding structure
  209|      2|    const bool res = ResolvePointer(out,ptrval,db,*f, non_recursive);
  210|       |
  211|      2|    if(!non_recursive) {
  ------------------
  |  Branch (211:8): [True: 2, False: 0]
  ------------------
  212|       |        // and recover the previous stream position
  213|      2|        db.reader->SetCurrentPos(old);
  214|      2|    }
  215|       |
  216|      2|#ifndef ASSIMP_BUILD_BLENDER_NO_STATS
  217|      2|    ++db.stats().fields_read;
  218|      2|#endif
  219|       |
  220|      2|    return res;
  221|      2|}
_ZNK6Assimp7Blender9Structure14ResolvePointerINSt3__110shared_ptrENS0_15CollectionChildEEEbRT_IT0_ERKNS0_7PointerERKNS0_12FileDatabaseERKNS0_5FieldEb:
  412|      2|{
  413|      2|    out.reset(); // ensure null pointers work
  414|      2|    if (!ptrval.val) {
  ------------------
  |  Branch (414:9): [True: 2, False: 0]
  ------------------
  415|      2|        return false;
  416|      2|    }
  417|      0|    const Structure& s = db.dna[f.type];
  418|       |    // find the file block the pointer is pointing to
  419|      0|    const FileBlockHead* block = LocateFileBlockForAddress(ptrval,db);
  420|       |
  421|       |    // also determine the target type from the block header
  422|       |    // and check if it matches the type which we expect.
  423|      0|    const Structure& ss = db.dna[block->dna_index];
  424|      0|    if (ss != s) {
  ------------------
  |  Branch (424:9): [True: 0, False: 0]
  ------------------
  425|      0|        throw Error("Expected target to be of type `",s.name,
  426|      0|            "` but seemingly it is a `",ss.name,"` instead"
  427|      0|            );
  428|      0|    }
  429|       |
  430|       |    // try to retrieve the object from the cache
  431|      0|    db.cache(out).get(s,out,ptrval);
  432|      0|    if (out) {
  ------------------
  |  Branch (432:9): [True: 0, False: 0]
  ------------------
  433|      0|        return true;
  434|      0|    }
  435|       |
  436|       |    // seek to this location, but save the previous stream pointer.
  437|      0|    const StreamReaderAny::pos pold = db.reader->GetCurrentPos();
  438|      0|    db.reader->SetCurrentPos(block->start+ static_cast<size_t>((ptrval.val - block->address.val) ));
  439|       |    // FIXME: basically, this could cause problems with 64 bit pointers on 32 bit systems.
  440|       |    // I really ought to improve StreamReader to work with 64 bit indices exclusively.
  441|       |
  442|       |    // continue conversion after allocating the required storage
  443|      0|    size_t num = block->size / ss.size;
  444|      0|    T* o = _allocate(out,num);
  445|       |
  446|       |    // cache the object before we convert it to avoid cyclic recursion.
  447|      0|    db.cache(out).set(s,out,ptrval);
  448|       |
  449|       |    // if the non_recursive flag is set, we don't do anything but leave
  450|       |    // the cursor at the correct position to resolve the object.
  451|      0|    if (!non_recursive) {
  ------------------
  |  Branch (451:9): [True: 0, False: 0]
  ------------------
  452|      0|        for (size_t i = 0; i < num; ++i,++o) {
  ------------------
  |  Branch (452:28): [True: 0, False: 0]
  ------------------
  453|      0|            s.Convert(*o,db);
  454|      0|        }
  455|       |
  456|      0|        db.reader->SetCurrentPos(pold);
  457|      0|    }
  458|       |
  459|      0|#ifndef ASSIMP_BUILD_BLENDER_NO_STATS
  460|      0|    if(out) {
  ------------------
  |  Branch (460:8): [True: 0, False: 0]
  ------------------
  461|      0|        ++db.stats().pointers_resolved;
  462|      0|    }
  463|      0|#endif
  464|      0|    return false;
  465|      0|}
_ZNK6Assimp7Blender9Structure12ReadFieldPtrILi1ENSt3__110shared_ptrENS0_10CollectionEEEbRT0_IT1_EPKcRKNS0_12FileDatabaseEb:
  183|     26|{
  184|     26|    const StreamReaderAny::pos old = db.reader->GetCurrentPos();
  185|     26|    Pointer ptrval;
  186|     26|    const Field* f;
  187|     26|    try {
  188|     26|        f = &(*this)[name];
  189|       |
  190|       |        // sanity check, should never happen if the genblenddna script is right
  191|     26|        if (!(f->flags & FieldFlag_Pointer)) {
  ------------------
  |  Branch (191:13): [True: 0, False: 26]
  ------------------
  192|      0|            throw Error("Field `",name,"` of structure `",
  193|      0|                this->name,"` ought to be a pointer");
  194|      0|        }
  195|       |
  196|     26|        db.reader->IncPtr(f->offset);
  197|     26|        Convert(ptrval,db);
  198|       |        // actually it is meaningless on which Structure the Convert is called
  199|       |        // because the `Pointer` argument triggers a special implementation.
  200|     26|    }
  201|     26|    catch (const Error& e) {
  202|     24|        _defaultInitializer<error_policy>()(out,e.what());
  203|       |
  204|     24|        out.reset();
  205|     24|        return false;
  206|     24|    }
  207|       |
  208|       |    // resolve the pointer and load the corresponding structure
  209|      2|    const bool res = ResolvePointer(out,ptrval,db,*f, non_recursive);
  210|       |
  211|      2|    if(!non_recursive) {
  ------------------
  |  Branch (211:8): [True: 2, False: 0]
  ------------------
  212|       |        // and recover the previous stream position
  213|      2|        db.reader->SetCurrentPos(old);
  214|      2|    }
  215|       |
  216|      2|#ifndef ASSIMP_BUILD_BLENDER_NO_STATS
  217|      2|    ++db.stats().fields_read;
  218|      2|#endif
  219|       |
  220|      2|    return res;
  221|     26|}
_ZNK6Assimp7Blender9Structure14ResolvePointerINSt3__110shared_ptrENS0_10CollectionEEEbRT_IT0_ERKNS0_7PointerERKNS0_12FileDatabaseERKNS0_5FieldEb:
  412|      2|{
  413|      2|    out.reset(); // ensure null pointers work
  414|      2|    if (!ptrval.val) {
  ------------------
  |  Branch (414:9): [True: 0, False: 2]
  ------------------
  415|      0|        return false;
  416|      0|    }
  417|      2|    const Structure& s = db.dna[f.type];
  418|       |    // find the file block the pointer is pointing to
  419|      2|    const FileBlockHead* block = LocateFileBlockForAddress(ptrval,db);
  420|       |
  421|       |    // also determine the target type from the block header
  422|       |    // and check if it matches the type which we expect.
  423|      2|    const Structure& ss = db.dna[block->dna_index];
  424|      2|    if (ss != s) {
  ------------------
  |  Branch (424:9): [True: 0, False: 2]
  ------------------
  425|      0|        throw Error("Expected target to be of type `",s.name,
  426|      0|            "` but seemingly it is a `",ss.name,"` instead"
  427|      0|            );
  428|      0|    }
  429|       |
  430|       |    // try to retrieve the object from the cache
  431|      2|    db.cache(out).get(s,out,ptrval);
  432|      2|    if (out) {
  ------------------
  |  Branch (432:9): [True: 0, False: 2]
  ------------------
  433|      0|        return true;
  434|      0|    }
  435|       |
  436|       |    // seek to this location, but save the previous stream pointer.
  437|      2|    const StreamReaderAny::pos pold = db.reader->GetCurrentPos();
  438|      2|    db.reader->SetCurrentPos(block->start+ static_cast<size_t>((ptrval.val - block->address.val) ));
  439|       |    // FIXME: basically, this could cause problems with 64 bit pointers on 32 bit systems.
  440|       |    // I really ought to improve StreamReader to work with 64 bit indices exclusively.
  441|       |
  442|       |    // continue conversion after allocating the required storage
  443|      2|    size_t num = block->size / ss.size;
  444|      2|    T* o = _allocate(out,num);
  445|       |
  446|       |    // cache the object before we convert it to avoid cyclic recursion.
  447|      2|    db.cache(out).set(s,out,ptrval);
  448|       |
  449|       |    // if the non_recursive flag is set, we don't do anything but leave
  450|       |    // the cursor at the correct position to resolve the object.
  451|      2|    if (!non_recursive) {
  ------------------
  |  Branch (451:9): [True: 2, False: 0]
  ------------------
  452|      4|        for (size_t i = 0; i < num; ++i,++o) {
  ------------------
  |  Branch (452:28): [True: 2, False: 2]
  ------------------
  453|      2|            s.Convert(*o,db);
  454|      2|        }
  455|       |
  456|      2|        db.reader->SetCurrentPos(pold);
  457|      2|    }
  458|       |
  459|      2|#ifndef ASSIMP_BUILD_BLENDER_NO_STATS
  460|      2|    if(out) {
  ------------------
  |  Branch (460:8): [True: 2, False: 0]
  ------------------
  461|      2|        ++db.stats().pointers_resolved;
  462|      2|    }
  463|      2|#endif
  464|      2|    return false;
  465|      2|}
_ZNK6Assimp7Blender11ObjectCacheINSt3__110shared_ptrEE3getINS0_10CollectionEEEvRKNS0_9StructureERNS3_IT_EERKNS0_7PointerE:
  807|      2|) const {
  808|       |
  809|      2|    if(s.cache_idx == static_cast<size_t>(-1)) {
  ------------------
  |  Branch (809:8): [True: 1, False: 1]
  ------------------
  810|      1|        s.cache_idx = db.next_cache_idx++;
  811|      1|        caches.resize(db.next_cache_idx);
  812|      1|        return;
  813|      1|    }
  814|       |
  815|      1|    typename StructureCache::const_iterator it = caches[s.cache_idx].find(ptr);
  816|      1|    if (it != caches[s.cache_idx].end()) {
  ------------------
  |  Branch (816:9): [True: 0, False: 1]
  ------------------
  817|      0|        out = std::static_pointer_cast<T>( (*it).second );
  818|       |
  819|      0|#ifndef ASSIMP_BUILD_BLENDER_NO_STATS
  820|      0|        ++db.stats().cache_hits;
  821|      0|#endif
  822|      0|    }
  823|       |    // otherwise, out remains untouched
  824|      1|}
_ZN6Assimp7Blender11ObjectCacheINSt3__110shared_ptrEE3setINS0_10CollectionEEEvRKNS0_9StructureERKNS3_IT_EERKNS0_7PointerE:
  832|      2|) {
  833|      2|    if(s.cache_idx == static_cast<size_t>(-1)) {
  ------------------
  |  Branch (833:8): [True: 0, False: 2]
  ------------------
  834|      0|        s.cache_idx = db.next_cache_idx++;
  835|      0|        caches.resize(db.next_cache_idx);
  836|      0|    }
  837|      2|    caches[s.cache_idx][ptr] = std::static_pointer_cast<ElemBase>( out );
  838|       |
  839|      2|#ifndef ASSIMP_BUILD_BLENDER_NO_STATS
  840|      2|    ++db.stats().cached_objects;
  841|      2|#endif
  842|      2|}
_ZNK6Assimp7Blender9Structure9ReadFieldILi2ENS0_8ListBaseEEEvRT0_PKcRKNS0_12FileDatabaseE:
  282|      4|{
  283|      4|    const StreamReaderAny::pos old = db.reader->GetCurrentPos();
  284|      4|    try {
  285|      4|        const Field& f = (*this)[name];
  286|       |        // find the structure definition pertaining to this field
  287|      4|        const Structure& s = db.dna[f.type];
  288|       |
  289|      4|        db.reader->IncPtr(f.offset);
  290|      4|        s.Convert(out,db);
  291|      4|    }
  292|      4|    catch (const Error& e) {
  293|      0|        _defaultInitializer<error_policy>()(out,e.what());
  294|      0|    }
  295|       |
  296|       |    // and recover the previous stream position
  297|      4|    db.reader->SetCurrentPos(old);
  298|       |
  299|      4|#ifndef ASSIMP_BUILD_BLENDER_NO_STATS
  300|      4|    ++db.stats().fields_read;
  301|      4|#endif
  302|      4|}
_ZNK6Assimp7Blender9Structure12ReadFieldPtrILi1ENSt3__110shared_ptrENS0_3TexEEEbRT0_IT1_EPKcRKNS0_12FileDatabaseEb:
  183|     28|{
  184|     28|    const StreamReaderAny::pos old = db.reader->GetCurrentPos();
  185|     28|    Pointer ptrval;
  186|     28|    const Field* f;
  187|     28|    try {
  188|     28|        f = &(*this)[name];
  189|       |
  190|       |        // sanity check, should never happen if the genblenddna script is right
  191|     28|        if (!(f->flags & FieldFlag_Pointer)) {
  ------------------
  |  Branch (191:13): [True: 0, False: 28]
  ------------------
  192|      0|            throw Error("Field `",name,"` of structure `",
  193|      0|                this->name,"` ought to be a pointer");
  194|      0|        }
  195|       |
  196|     28|        db.reader->IncPtr(f->offset);
  197|     28|        Convert(ptrval,db);
  198|       |        // actually it is meaningless on which Structure the Convert is called
  199|       |        // because the `Pointer` argument triggers a special implementation.
  200|     28|    }
  201|     28|    catch (const Error& e) {
  202|      0|        _defaultInitializer<error_policy>()(out,e.what());
  203|       |
  204|      0|        out.reset();
  205|      0|        return false;
  206|      0|    }
  207|       |
  208|       |    // resolve the pointer and load the corresponding structure
  209|     28|    const bool res = ResolvePointer(out,ptrval,db,*f, non_recursive);
  210|       |
  211|     28|    if(!non_recursive) {
  ------------------
  |  Branch (211:8): [True: 28, False: 0]
  ------------------
  212|       |        // and recover the previous stream position
  213|     28|        db.reader->SetCurrentPos(old);
  214|     28|    }
  215|       |
  216|     28|#ifndef ASSIMP_BUILD_BLENDER_NO_STATS
  217|     28|    ++db.stats().fields_read;
  218|     28|#endif
  219|       |
  220|     28|    return res;
  221|     28|}
_ZNK6Assimp7Blender9Structure14ResolvePointerINSt3__110shared_ptrENS0_3TexEEEbRT_IT0_ERKNS0_7PointerERKNS0_12FileDatabaseERKNS0_5FieldEb:
  412|     28|{
  413|     28|    out.reset(); // ensure null pointers work
  414|     28|    if (!ptrval.val) {
  ------------------
  |  Branch (414:9): [True: 0, False: 28]
  ------------------
  415|      0|        return false;
  416|      0|    }
  417|     28|    const Structure& s = db.dna[f.type];
  418|       |    // find the file block the pointer is pointing to
  419|     28|    const FileBlockHead* block = LocateFileBlockForAddress(ptrval,db);
  420|       |
  421|       |    // also determine the target type from the block header
  422|       |    // and check if it matches the type which we expect.
  423|     28|    const Structure& ss = db.dna[block->dna_index];
  424|     28|    if (ss != s) {
  ------------------
  |  Branch (424:9): [True: 0, False: 28]
  ------------------
  425|      0|        throw Error("Expected target to be of type `",s.name,
  426|      0|            "` but seemingly it is a `",ss.name,"` instead"
  427|      0|            );
  428|      0|    }
  429|       |
  430|       |    // try to retrieve the object from the cache
  431|     28|    db.cache(out).get(s,out,ptrval);
  432|     28|    if (out) {
  ------------------
  |  Branch (432:9): [True: 4, False: 24]
  ------------------
  433|      4|        return true;
  434|      4|    }
  435|       |
  436|       |    // seek to this location, but save the previous stream pointer.
  437|     24|    const StreamReaderAny::pos pold = db.reader->GetCurrentPos();
  438|     24|    db.reader->SetCurrentPos(block->start+ static_cast<size_t>((ptrval.val - block->address.val) ));
  439|       |    // FIXME: basically, this could cause problems with 64 bit pointers on 32 bit systems.
  440|       |    // I really ought to improve StreamReader to work with 64 bit indices exclusively.
  441|       |
  442|       |    // continue conversion after allocating the required storage
  443|     24|    size_t num = block->size / ss.size;
  444|     24|    T* o = _allocate(out,num);
  445|       |
  446|       |    // cache the object before we convert it to avoid cyclic recursion.
  447|     24|    db.cache(out).set(s,out,ptrval);
  448|       |
  449|       |    // if the non_recursive flag is set, we don't do anything but leave
  450|       |    // the cursor at the correct position to resolve the object.
  451|     24|    if (!non_recursive) {
  ------------------
  |  Branch (451:9): [True: 24, False: 0]
  ------------------
  452|     48|        for (size_t i = 0; i < num; ++i,++o) {
  ------------------
  |  Branch (452:28): [True: 24, False: 24]
  ------------------
  453|     24|            s.Convert(*o,db);
  454|     24|        }
  455|       |
  456|     24|        db.reader->SetCurrentPos(pold);
  457|     24|    }
  458|       |
  459|     24|#ifndef ASSIMP_BUILD_BLENDER_NO_STATS
  460|     24|    if(out) {
  ------------------
  |  Branch (460:8): [True: 24, False: 0]
  ------------------
  461|     24|        ++db.stats().pointers_resolved;
  462|     24|    }
  463|     24|#endif
  464|     24|    return false;
  465|     28|}
_ZNK6Assimp7Blender11ObjectCacheINSt3__110shared_ptrEE3getINS0_3TexEEEvRKNS0_9StructureERNS3_IT_EERKNS0_7PointerE:
  807|     28|) const {
  808|       |
  809|     28|    if(s.cache_idx == static_cast<size_t>(-1)) {
  ------------------
  |  Branch (809:8): [True: 21, False: 7]
  ------------------
  810|     21|        s.cache_idx = db.next_cache_idx++;
  811|     21|        caches.resize(db.next_cache_idx);
  812|     21|        return;
  813|     21|    }
  814|       |
  815|      7|    typename StructureCache::const_iterator it = caches[s.cache_idx].find(ptr);
  816|      7|    if (it != caches[s.cache_idx].end()) {
  ------------------
  |  Branch (816:9): [True: 4, False: 3]
  ------------------
  817|      4|        out = std::static_pointer_cast<T>( (*it).second );
  818|       |
  819|      4|#ifndef ASSIMP_BUILD_BLENDER_NO_STATS
  820|      4|        ++db.stats().cache_hits;
  821|      4|#endif
  822|      4|    }
  823|       |    // otherwise, out remains untouched
  824|      7|}
_ZN6Assimp7Blender11ObjectCacheINSt3__110shared_ptrEE3setINS0_3TexEEEvRKNS0_9StructureERKNS3_IT_EERKNS0_7PointerE:
  832|     24|) {
  833|     24|    if(s.cache_idx == static_cast<size_t>(-1)) {
  ------------------
  |  Branch (833:8): [True: 0, False: 24]
  ------------------
  834|      0|        s.cache_idx = db.next_cache_idx++;
  835|      0|        caches.resize(db.next_cache_idx);
  836|      0|    }
  837|     24|    caches[s.cache_idx][ptr] = std::static_pointer_cast<ElemBase>( out );
  838|       |
  839|     24|#ifndef ASSIMP_BUILD_BLENDER_NO_STATS
  840|     24|    ++db.stats().cached_objects;
  841|     24|#endif
  842|     24|}
_ZNK6Assimp7Blender9Structure9ReadFieldILi1EcEEvRT0_PKcRKNS0_12FileDatabaseE:
  282|   102k|{
  283|   102k|    const StreamReaderAny::pos old = db.reader->GetCurrentPos();
  284|   102k|    try {
  285|   102k|        const Field& f = (*this)[name];
  286|       |        // find the structure definition pertaining to this field
  287|   102k|        const Structure& s = db.dna[f.type];
  288|       |
  289|   102k|        db.reader->IncPtr(f.offset);
  290|   102k|        s.Convert(out,db);
  291|   102k|    }
  292|   102k|    catch (const Error& e) {
  293|      2|        _defaultInitializer<error_policy>()(out,e.what());
  294|      2|    }
  295|       |
  296|       |    // and recover the previous stream position
  297|   102k|    db.reader->SetCurrentPos(old);
  298|       |
  299|   102k|#ifndef ASSIMP_BUILD_BLENDER_NO_STATS
  300|   102k|    ++db.stats().fields_read;
  301|   102k|#endif
  302|   102k|}
_ZNK6Assimp7Blender9Structure14ReadFieldArrayILi1EfLm3EEEvRAT1__T0_PKcRKNS0_12FileDatabaseE:
  100|  18.0k|{
  101|  18.0k|    const StreamReaderAny::pos old = db.reader->GetCurrentPos();
  102|  18.0k|    try {
  103|  18.0k|        const Field& f = (*this)[name];
  104|  18.0k|        const Structure& s = db.dna[f.type];
  105|       |
  106|       |        // is the input actually an array?
  107|  18.0k|        if (!(f.flags & FieldFlag_Array)) {
  ------------------
  |  Branch (107:13): [True: 0, False: 18.0k]
  ------------------
  108|      0|            throw Error("Field `",name,"` of structure `",this->name,"` ought to be an array of size ",M);
  109|      0|        }
  110|       |
  111|  18.0k|        db.reader->IncPtr(f.offset);
  112|       |
  113|       |        // size conversions are always allowed, regardless of error_policy
  114|  18.0k|        unsigned int i = 0;
  115|  72.3k|        for(; i < std::min(f.array_sizes[0],M); ++i) {
  ------------------
  |  Branch (115:15): [True: 54.2k, False: 18.0k]
  ------------------
  116|  54.2k|            s.Convert(out[i],db);
  117|  54.2k|        }
  118|  18.0k|        for(; i < M; ++i) {
  ------------------
  |  Branch (118:15): [True: 0, False: 18.0k]
  ------------------
  119|      0|            _defaultInitializer<ErrorPolicy_Igno>()(out[i]);
  120|      0|        }
  121|  18.0k|    }
  122|  18.0k|    catch (const Error& e) {
  123|      0|        _defaultInitializer<error_policy>()(out,e.what());
  124|      0|    }
  125|       |
  126|       |    // and recover the previous stream position
  127|  18.0k|    db.reader->SetCurrentPos(old);
  128|       |
  129|  18.0k|#ifndef ASSIMP_BUILD_BLENDER_NO_STATS
  130|  18.0k|    ++db.stats().fields_read;
  131|  18.0k|#endif
  132|  18.0k|}
_ZNK6Assimp7Blender9Structure9ReadFieldILi1EfEEvRT0_PKcRKNS0_12FileDatabaseE:
  282|  2.96k|{
  283|  2.96k|    const StreamReaderAny::pos old = db.reader->GetCurrentPos();
  284|  2.96k|    try {
  285|  2.96k|        const Field& f = (*this)[name];
  286|       |        // find the structure definition pertaining to this field
  287|  2.96k|        const Structure& s = db.dna[f.type];
  288|       |
  289|  2.96k|        db.reader->IncPtr(f.offset);
  290|  2.96k|        s.Convert(out,db);
  291|  2.96k|    }
  292|  2.96k|    catch (const Error& e) {
  293|    289|        _defaultInitializer<error_policy>()(out,e.what());
  294|    289|    }
  295|       |
  296|       |    // and recover the previous stream position
  297|  2.96k|    db.reader->SetCurrentPos(old);
  298|       |
  299|  2.96k|#ifndef ASSIMP_BUILD_BLENDER_NO_STATS
  300|  2.96k|    ++db.stats().fields_read;
  301|  2.96k|#endif
  302|  2.96k|}
_ZNK6Assimp7Blender9Structure9ReadFieldILi1EsEEvRT0_PKcRKNS0_12FileDatabaseE:
  282|  37.4k|{
  283|  37.4k|    const StreamReaderAny::pos old = db.reader->GetCurrentPos();
  284|  37.4k|    try {
  285|  37.4k|        const Field& f = (*this)[name];
  286|       |        // find the structure definition pertaining to this field
  287|  37.4k|        const Structure& s = db.dna[f.type];
  288|       |
  289|  37.4k|        db.reader->IncPtr(f.offset);
  290|  37.4k|        s.Convert(out,db);
  291|  37.4k|    }
  292|  37.4k|    catch (const Error& e) {
  293|    117|        _defaultInitializer<error_policy>()(out,e.what());
  294|    117|    }
  295|       |
  296|       |    // and recover the previous stream position
  297|  37.4k|    db.reader->SetCurrentPos(old);
  298|       |
  299|  37.4k|#ifndef ASSIMP_BUILD_BLENDER_NO_STATS
  300|  37.4k|    ++db.stats().fields_read;
  301|  37.4k|#endif
  302|  37.4k|}
_ZNK6Assimp7Blender9Structure15ReadFieldArray2ILi2EfLm4ELm2EEEvRAT1__AT2__T0_PKcRKNS0_12FileDatabaseE:
  137|     28|{
  138|     28|    const StreamReaderAny::pos old = db.reader->GetCurrentPos();
  139|     28|    try {
  140|     28|        const Field& f = (*this)[name];
  141|     28|        const Structure& s = db.dna[f.type];
  142|       |
  143|       |        // is the input actually an array?
  144|     28|        if (!(f.flags & FieldFlag_Array)) {
  ------------------
  |  Branch (144:13): [True: 0, False: 28]
  ------------------
  145|      0|            throw Error("Field `",name,"` of structure `",
  146|      0|                this->name,"` ought to be an array of size ",M,"*",N
  147|      0|                );
  148|      0|        }
  149|       |
  150|     28|        db.reader->IncPtr(f.offset);
  151|       |
  152|       |        // size conversions are always allowed, regardless of error_policy
  153|     28|        unsigned int i = 0;
  154|    140|        for(; i < std::min(f.array_sizes[0],M); ++i) {
  ------------------
  |  Branch (154:15): [True: 112, False: 28]
  ------------------
  155|    112|            unsigned int j = 0;
  156|    336|            for(; j < std::min(f.array_sizes[1],N); ++j) {
  ------------------
  |  Branch (156:19): [True: 224, False: 112]
  ------------------
  157|    224|                s.Convert(out[i][j],db);
  158|    224|            }
  159|    112|            for(; j < N; ++j) {
  ------------------
  |  Branch (159:19): [True: 0, False: 112]
  ------------------
  160|      0|                _defaultInitializer<ErrorPolicy_Igno>()(out[i][j]);
  161|      0|            }
  162|    112|        }
  163|     28|        for(; i < M; ++i) {
  ------------------
  |  Branch (163:15): [True: 0, False: 28]
  ------------------
  164|      0|            _defaultInitializer<ErrorPolicy_Igno>()(out[i]);
  165|      0|        }
  166|     28|    }
  167|     28|    catch (const Error& e) {
  168|      0|        _defaultInitializer<error_policy>()(out,e.what());
  169|      0|    }
  170|       |
  171|       |    // and recover the previous stream position
  172|     28|    db.reader->SetCurrentPos(old);
  173|       |
  174|     28|#ifndef ASSIMP_BUILD_BLENDER_NO_STATS
  175|     28|    ++db.stats().fields_read;
  176|     28|#endif
  177|     28|}
_ZNK6Assimp7Blender9Structure9ReadFieldILi2ENS0_12ModifierDataEEEvRT0_PKcRKNS0_12FileDatabaseE:
  282|      6|{
  283|      6|    const StreamReaderAny::pos old = db.reader->GetCurrentPos();
  284|      6|    try {
  285|      6|        const Field& f = (*this)[name];
  286|       |        // find the structure definition pertaining to this field
  287|      6|        const Structure& s = db.dna[f.type];
  288|       |
  289|      6|        db.reader->IncPtr(f.offset);
  290|      6|        s.Convert(out,db);
  291|      6|    }
  292|      6|    catch (const Error& e) {
  293|      0|        _defaultInitializer<error_policy>()(out,e.what());
  294|      0|    }
  295|       |
  296|       |    // and recover the previous stream position
  297|      6|    db.reader->SetCurrentPos(old);
  298|       |
  299|      6|#ifndef ASSIMP_BUILD_BLENDER_NO_STATS
  300|      6|    ++db.stats().fields_read;
  301|      6|#endif
  302|      6|}
_ZNK6Assimp7Blender9Structure9ReadFieldILi2EsEEvRT0_PKcRKNS0_12FileDatabaseE:
  282|      4|{
  283|      4|    const StreamReaderAny::pos old = db.reader->GetCurrentPos();
  284|      4|    try {
  285|      4|        const Field& f = (*this)[name];
  286|       |        // find the structure definition pertaining to this field
  287|      4|        const Structure& s = db.dna[f.type];
  288|       |
  289|      4|        db.reader->IncPtr(f.offset);
  290|      4|        s.Convert(out,db);
  291|      4|    }
  292|      4|    catch (const Error& e) {
  293|      0|        _defaultInitializer<error_policy>()(out,e.what());
  294|      0|    }
  295|       |
  296|       |    // and recover the previous stream position
  297|      4|    db.reader->SetCurrentPos(old);
  298|       |
  299|      4|#ifndef ASSIMP_BUILD_BLENDER_NO_STATS
  300|      4|    ++db.stats().fields_read;
  301|      4|#endif
  302|      4|}
_ZNK6Assimp7Blender9Structure12ReadFieldPtrILi1ENSt3__110shared_ptrENS0_10FileOffsetEEEbRT0_IT1_EPKcRKNS0_12FileDatabaseEb:
  183|      1|{
  184|      1|    const StreamReaderAny::pos old = db.reader->GetCurrentPos();
  185|      1|    Pointer ptrval;
  186|      1|    const Field* f;
  187|      1|    try {
  188|      1|        f = &(*this)[name];
  189|       |
  190|       |        // sanity check, should never happen if the genblenddna script is right
  191|      1|        if (!(f->flags & FieldFlag_Pointer)) {
  ------------------
  |  Branch (191:13): [True: 0, False: 1]
  ------------------
  192|      0|            throw Error("Field `",name,"` of structure `",
  193|      0|                this->name,"` ought to be a pointer");
  194|      0|        }
  195|       |
  196|      1|        db.reader->IncPtr(f->offset);
  197|      1|        Convert(ptrval,db);
  198|       |        // actually it is meaningless on which Structure the Convert is called
  199|       |        // because the `Pointer` argument triggers a special implementation.
  200|      1|    }
  201|      1|    catch (const Error& e) {
  202|      0|        _defaultInitializer<error_policy>()(out,e.what());
  203|       |
  204|      0|        out.reset();
  205|      0|        return false;
  206|      0|    }
  207|       |
  208|       |    // resolve the pointer and load the corresponding structure
  209|      1|    const bool res = ResolvePointer(out,ptrval,db,*f, non_recursive);
  210|       |
  211|      1|    if(!non_recursive) {
  ------------------
  |  Branch (211:8): [True: 1, False: 0]
  ------------------
  212|       |        // and recover the previous stream position
  213|      1|        db.reader->SetCurrentPos(old);
  214|      1|    }
  215|       |
  216|      1|#ifndef ASSIMP_BUILD_BLENDER_NO_STATS
  217|      1|    ++db.stats().fields_read;
  218|      1|#endif
  219|       |
  220|      1|    return res;
  221|      1|}
_ZNK6Assimp7Blender9Structure12ReadFieldPtrILi1ENSt3__110shared_ptrENS0_4BaseEEEbRT0_IT1_EPKcRKNS0_12FileDatabaseEb:
  183|    121|{
  184|    121|    const StreamReaderAny::pos old = db.reader->GetCurrentPos();
  185|    121|    Pointer ptrval;
  186|    121|    const Field* f;
  187|    121|    try {
  188|    121|        f = &(*this)[name];
  189|       |
  190|       |        // sanity check, should never happen if the genblenddna script is right
  191|    121|        if (!(f->flags & FieldFlag_Pointer)) {
  ------------------
  |  Branch (191:13): [True: 0, False: 121]
  ------------------
  192|      0|            throw Error("Field `",name,"` of structure `",
  193|      0|                this->name,"` ought to be a pointer");
  194|      0|        }
  195|       |
  196|    121|        db.reader->IncPtr(f->offset);
  197|    121|        Convert(ptrval,db);
  198|       |        // actually it is meaningless on which Structure the Convert is called
  199|       |        // because the `Pointer` argument triggers a special implementation.
  200|    121|    }
  201|    121|    catch (const Error& e) {
  202|      0|        _defaultInitializer<error_policy>()(out,e.what());
  203|       |
  204|      0|        out.reset();
  205|      0|        return false;
  206|      0|    }
  207|       |
  208|       |    // resolve the pointer and load the corresponding structure
  209|    121|    const bool res = ResolvePointer(out,ptrval,db,*f, non_recursive);
  210|       |
  211|    121|    if(!non_recursive) {
  ------------------
  |  Branch (211:8): [True: 25, False: 96]
  ------------------
  212|       |        // and recover the previous stream position
  213|     25|        db.reader->SetCurrentPos(old);
  214|     25|    }
  215|       |
  216|    121|#ifndef ASSIMP_BUILD_BLENDER_NO_STATS
  217|    121|    ++db.stats().fields_read;
  218|    121|#endif
  219|       |
  220|    121|    return res;
  221|    121|}
_ZNK6Assimp7Blender9Structure14ResolvePointerINSt3__110shared_ptrENS0_4BaseEEEbRT_IT0_ERKNS0_7PointerERKNS0_12FileDatabaseERKNS0_5FieldEb:
  412|    121|{
  413|    121|    out.reset(); // ensure null pointers work
  414|    121|    if (!ptrval.val) {
  ------------------
  |  Branch (414:9): [True: 27, False: 94]
  ------------------
  415|     27|        return false;
  416|     27|    }
  417|     94|    const Structure& s = db.dna[f.type];
  418|       |    // find the file block the pointer is pointing to
  419|     94|    const FileBlockHead* block = LocateFileBlockForAddress(ptrval,db);
  420|       |
  421|       |    // also determine the target type from the block header
  422|       |    // and check if it matches the type which we expect.
  423|     94|    const Structure& ss = db.dna[block->dna_index];
  424|     94|    if (ss != s) {
  ------------------
  |  Branch (424:9): [True: 0, False: 94]
  ------------------
  425|      0|        throw Error("Expected target to be of type `",s.name,
  426|      0|            "` but seemingly it is a `",ss.name,"` instead"
  427|      0|            );
  428|      0|    }
  429|       |
  430|       |    // try to retrieve the object from the cache
  431|     94|    db.cache(out).get(s,out,ptrval);
  432|     94|    if (out) {
  ------------------
  |  Branch (432:9): [True: 6, False: 88]
  ------------------
  433|      6|        return true;
  434|      6|    }
  435|       |
  436|       |    // seek to this location, but save the previous stream pointer.
  437|     88|    const StreamReaderAny::pos pold = db.reader->GetCurrentPos();
  438|     88|    db.reader->SetCurrentPos(block->start+ static_cast<size_t>((ptrval.val - block->address.val) ));
  439|       |    // FIXME: basically, this could cause problems with 64 bit pointers on 32 bit systems.
  440|       |    // I really ought to improve StreamReader to work with 64 bit indices exclusively.
  441|       |
  442|       |    // continue conversion after allocating the required storage
  443|     88|    size_t num = block->size / ss.size;
  444|     88|    T* o = _allocate(out,num);
  445|       |
  446|       |    // cache the object before we convert it to avoid cyclic recursion.
  447|     88|    db.cache(out).set(s,out,ptrval);
  448|       |
  449|       |    // if the non_recursive flag is set, we don't do anything but leave
  450|       |    // the cursor at the correct position to resolve the object.
  451|     88|    if (!non_recursive) {
  ------------------
  |  Branch (451:9): [True: 23, False: 65]
  ------------------
  452|     46|        for (size_t i = 0; i < num; ++i,++o) {
  ------------------
  |  Branch (452:28): [True: 23, False: 23]
  ------------------
  453|     23|            s.Convert(*o,db);
  454|     23|        }
  455|       |
  456|     23|        db.reader->SetCurrentPos(pold);
  457|     23|    }
  458|       |
  459|     88|#ifndef ASSIMP_BUILD_BLENDER_NO_STATS
  460|     88|    if(out) {
  ------------------
  |  Branch (460:8): [True: 87, False: 1]
  ------------------
  461|     87|        ++db.stats().pointers_resolved;
  462|     87|    }
  463|     88|#endif
  464|     88|    return false;
  465|     94|}
_ZNK6Assimp7Blender11ObjectCacheINSt3__110shared_ptrEE3getINS0_4BaseEEEvRKNS0_9StructureERNS3_IT_EERKNS0_7PointerE:
  807|     94|) const {
  808|       |
  809|     94|    if(s.cache_idx == static_cast<size_t>(-1)) {
  ------------------
  |  Branch (809:8): [True: 23, False: 71]
  ------------------
  810|     23|        s.cache_idx = db.next_cache_idx++;
  811|     23|        caches.resize(db.next_cache_idx);
  812|     23|        return;
  813|     23|    }
  814|       |
  815|     71|    typename StructureCache::const_iterator it = caches[s.cache_idx].find(ptr);
  816|     71|    if (it != caches[s.cache_idx].end()) {
  ------------------
  |  Branch (816:9): [True: 6, False: 65]
  ------------------
  817|      6|        out = std::static_pointer_cast<T>( (*it).second );
  818|       |
  819|      6|#ifndef ASSIMP_BUILD_BLENDER_NO_STATS
  820|      6|        ++db.stats().cache_hits;
  821|      6|#endif
  822|      6|    }
  823|       |    // otherwise, out remains untouched
  824|     71|}
_ZN6Assimp7Blender11ObjectCacheINSt3__110shared_ptrEE3setINS0_4BaseEEEvRKNS0_9StructureERKNS3_IT_EERKNS0_7PointerE:
  832|     88|) {
  833|     88|    if(s.cache_idx == static_cast<size_t>(-1)) {
  ------------------
  |  Branch (833:8): [True: 0, False: 88]
  ------------------
  834|      0|        s.cache_idx = db.next_cache_idx++;
  835|      0|        caches.resize(db.next_cache_idx);
  836|      0|    }
  837|     88|    caches[s.cache_idx][ptr] = std::static_pointer_cast<ElemBase>( out );
  838|       |
  839|     88|#ifndef ASSIMP_BUILD_BLENDER_NO_STATS
  840|     88|    ++db.stats().cached_objects;
  841|     88|#endif
  842|     88|}
_ZNK6Assimp7Blender9Structure12ReadFieldPtrILi1ENSt3__110shared_ptrENS0_4MTexELm18EEEbRAT2__T0_IT1_EPKcRKNS0_12FileDatabaseE:
  227|     28|{
  228|       |    // XXX see if we can reduce this to call to the 'normal' ReadFieldPtr
  229|     28|    const StreamReaderAny::pos old = db.reader->GetCurrentPos();
  230|     28|    Pointer ptrval[N];
  231|     28|    const Field* f;
  232|     28|    try {
  233|     28|        f = &(*this)[name];
  234|       |
  235|       |#ifdef _DEBUG
  236|       |        // sanity check, should never happen if the genblenddna script is right
  237|       |        if ((FieldFlag_Pointer|FieldFlag_Pointer) != (f->flags & (FieldFlag_Pointer|FieldFlag_Pointer))) {
  238|       |            throw Error("Field `",name,"` of structure `",
  239|       |                this->name,"` ought to be a pointer AND an array");
  240|       |        }
  241|       |#endif // _DEBUG
  242|       |
  243|     28|        db.reader->IncPtr(f->offset);
  244|       |
  245|     28|        size_t i = 0;
  246|    514|        for(; i < std::min(f->array_sizes[0],N); ++i) {
  ------------------
  |  Branch (246:15): [True: 486, False: 28]
  ------------------
  247|    486|            Convert(ptrval[i],db);
  248|    486|        }
  249|     28|        for(; i < N; ++i) {
  ------------------
  |  Branch (249:15): [True: 0, False: 28]
  ------------------
  250|      0|            _defaultInitializer<ErrorPolicy_Igno>()(ptrval[i]);
  251|      0|        }
  252|       |
  253|       |        // actually it is meaningless on which Structure the Convert is called
  254|       |        // because the `Pointer` argument triggers a special implementation.
  255|     28|    }
  256|     28|    catch (const Error& e) {
  257|      1|        _defaultInitializer<error_policy>()(out,e.what());
  258|     19|        for(size_t i = 0; i < N; ++i) {
  ------------------
  |  Branch (258:27): [True: 18, False: 1]
  ------------------
  259|     18|            out[i].reset();
  260|     18|        }
  261|      1|        return false;
  262|      1|    }
  263|       |
  264|     27|    bool res = true;
  265|    513|    for(size_t i = 0; i < N; ++i) {
  ------------------
  |  Branch (265:23): [True: 486, False: 27]
  ------------------
  266|       |        // resolve the pointer and load the corresponding structure
  267|    486|        res = ResolvePointer(out[i],ptrval[i],db,*f) && res;
  ------------------
  |  Branch (267:15): [True: 0, False: 486]
  |  Branch (267:57): [True: 0, False: 0]
  ------------------
  268|    486|    }
  269|       |
  270|       |    // and recover the previous stream position
  271|     27|    db.reader->SetCurrentPos(old);
  272|       |
  273|     27|#ifndef ASSIMP_BUILD_BLENDER_NO_STATS
  274|     27|    ++db.stats().fields_read;
  275|     27|#endif
  276|     27|    return res;
  277|     28|}
_ZNK6Assimp7Blender9Structure14ResolvePointerINSt3__110shared_ptrENS0_4MTexEEEbRT_IT0_ERKNS0_7PointerERKNS0_12FileDatabaseERKNS0_5FieldEb:
  412|    486|{
  413|    486|    out.reset(); // ensure null pointers work
  414|    486|    if (!ptrval.val) {
  ------------------
  |  Branch (414:9): [True: 458, False: 28]
  ------------------
  415|    458|        return false;
  416|    458|    }
  417|     28|    const Structure& s = db.dna[f.type];
  418|       |    // find the file block the pointer is pointing to
  419|     28|    const FileBlockHead* block = LocateFileBlockForAddress(ptrval,db);
  420|       |
  421|       |    // also determine the target type from the block header
  422|       |    // and check if it matches the type which we expect.
  423|     28|    const Structure& ss = db.dna[block->dna_index];
  424|     28|    if (ss != s) {
  ------------------
  |  Branch (424:9): [True: 0, False: 28]
  ------------------
  425|      0|        throw Error("Expected target to be of type `",s.name,
  426|      0|            "` but seemingly it is a `",ss.name,"` instead"
  427|      0|            );
  428|      0|    }
  429|       |
  430|       |    // try to retrieve the object from the cache
  431|     28|    db.cache(out).get(s,out,ptrval);
  432|     28|    if (out) {
  ------------------
  |  Branch (432:9): [True: 0, False: 28]
  ------------------
  433|      0|        return true;
  434|      0|    }
  435|       |
  436|       |    // seek to this location, but save the previous stream pointer.
  437|     28|    const StreamReaderAny::pos pold = db.reader->GetCurrentPos();
  438|     28|    db.reader->SetCurrentPos(block->start+ static_cast<size_t>((ptrval.val - block->address.val) ));
  439|       |    // FIXME: basically, this could cause problems with 64 bit pointers on 32 bit systems.
  440|       |    // I really ought to improve StreamReader to work with 64 bit indices exclusively.
  441|       |
  442|       |    // continue conversion after allocating the required storage
  443|     28|    size_t num = block->size / ss.size;
  444|     28|    T* o = _allocate(out,num);
  445|       |
  446|       |    // cache the object before we convert it to avoid cyclic recursion.
  447|     28|    db.cache(out).set(s,out,ptrval);
  448|       |
  449|       |    // if the non_recursive flag is set, we don't do anything but leave
  450|       |    // the cursor at the correct position to resolve the object.
  451|     28|    if (!non_recursive) {
  ------------------
  |  Branch (451:9): [True: 28, False: 0]
  ------------------
  452|     56|        for (size_t i = 0; i < num; ++i,++o) {
  ------------------
  |  Branch (452:28): [True: 28, False: 28]
  ------------------
  453|     28|            s.Convert(*o,db);
  454|     28|        }
  455|       |
  456|     28|        db.reader->SetCurrentPos(pold);
  457|     28|    }
  458|       |
  459|     28|#ifndef ASSIMP_BUILD_BLENDER_NO_STATS
  460|     28|    if(out) {
  ------------------
  |  Branch (460:8): [True: 28, False: 0]
  ------------------
  461|     28|        ++db.stats().pointers_resolved;
  462|     28|    }
  463|     28|#endif
  464|     28|    return false;
  465|     28|}
_ZNK6Assimp7Blender11ObjectCacheINSt3__110shared_ptrEE3getINS0_4MTexEEEvRKNS0_9StructureERNS3_IT_EERKNS0_7PointerE:
  807|     28|) const {
  808|       |
  809|     28|    if(s.cache_idx == static_cast<size_t>(-1)) {
  ------------------
  |  Branch (809:8): [True: 21, False: 7]
  ------------------
  810|     21|        s.cache_idx = db.next_cache_idx++;
  811|     21|        caches.resize(db.next_cache_idx);
  812|     21|        return;
  813|     21|    }
  814|       |
  815|      7|    typename StructureCache::const_iterator it = caches[s.cache_idx].find(ptr);
  816|      7|    if (it != caches[s.cache_idx].end()) {
  ------------------
  |  Branch (816:9): [True: 0, False: 7]
  ------------------
  817|      0|        out = std::static_pointer_cast<T>( (*it).second );
  818|       |
  819|      0|#ifndef ASSIMP_BUILD_BLENDER_NO_STATS
  820|      0|        ++db.stats().cache_hits;
  821|      0|#endif
  822|      0|    }
  823|       |    // otherwise, out remains untouched
  824|      7|}
_ZN6Assimp7Blender11ObjectCacheINSt3__110shared_ptrEE3setINS0_4MTexEEEvRKNS0_9StructureERKNS3_IT_EERKNS0_7PointerE:
  832|     28|) {
  833|     28|    if(s.cache_idx == static_cast<size_t>(-1)) {
  ------------------
  |  Branch (833:8): [True: 0, False: 28]
  ------------------
  834|      0|        s.cache_idx = db.next_cache_idx++;
  835|      0|        caches.resize(db.next_cache_idx);
  836|      0|    }
  837|     28|    caches[s.cache_idx][ptr] = std::static_pointer_cast<ElemBase>( out );
  838|       |
  839|     28|#ifndef ASSIMP_BUILD_BLENDER_NO_STATS
  840|     28|    ++db.stats().cached_objects;
  841|     28|#endif
  842|     28|}
_ZNK6Assimp7Blender9Structure12ReadFieldPtrILi1ENSt3__110shared_ptrENS0_5ImageEEEbRT0_IT1_EPKcRKNS0_12FileDatabaseEb:
  183|    115|{
  184|    115|    const StreamReaderAny::pos old = db.reader->GetCurrentPos();
  185|    115|    Pointer ptrval;
  186|    115|    const Field* f;
  187|    115|    try {
  188|    115|        f = &(*this)[name];
  189|       |
  190|       |        // sanity check, should never happen if the genblenddna script is right
  191|    115|        if (!(f->flags & FieldFlag_Pointer)) {
  ------------------
  |  Branch (191:13): [True: 0, False: 115]
  ------------------
  192|      0|            throw Error("Field `",name,"` of structure `",
  193|      0|                this->name,"` ought to be a pointer");
  194|      0|        }
  195|       |
  196|    115|        db.reader->IncPtr(f->offset);
  197|    115|        Convert(ptrval,db);
  198|       |        // actually it is meaningless on which Structure the Convert is called
  199|       |        // because the `Pointer` argument triggers a special implementation.
  200|    115|    }
  201|    115|    catch (const Error& e) {
  202|      0|        _defaultInitializer<error_policy>()(out,e.what());
  203|       |
  204|      0|        out.reset();
  205|      0|        return false;
  206|      0|    }
  207|       |
  208|       |    // resolve the pointer and load the corresponding structure
  209|    115|    const bool res = ResolvePointer(out,ptrval,db,*f, non_recursive);
  210|       |
  211|    115|    if(!non_recursive) {
  ------------------
  |  Branch (211:8): [True: 115, False: 0]
  ------------------
  212|       |        // and recover the previous stream position
  213|    115|        db.reader->SetCurrentPos(old);
  214|    115|    }
  215|       |
  216|    115|#ifndef ASSIMP_BUILD_BLENDER_NO_STATS
  217|    115|    ++db.stats().fields_read;
  218|    115|#endif
  219|       |
  220|    115|    return res;
  221|    115|}
_ZNK6Assimp7Blender9Structure14ResolvePointerINSt3__110shared_ptrENS0_5ImageEEEbRT_IT0_ERKNS0_7PointerERKNS0_12FileDatabaseERKNS0_5FieldEb:
  412|    115|{
  413|    115|    out.reset(); // ensure null pointers work
  414|    115|    if (!ptrval.val) {
  ------------------
  |  Branch (414:9): [True: 15, False: 100]
  ------------------
  415|     15|        return false;
  416|     15|    }
  417|    100|    const Structure& s = db.dna[f.type];
  418|       |    // find the file block the pointer is pointing to
  419|    100|    const FileBlockHead* block = LocateFileBlockForAddress(ptrval,db);
  420|       |
  421|       |    // also determine the target type from the block header
  422|       |    // and check if it matches the type which we expect.
  423|    100|    const Structure& ss = db.dna[block->dna_index];
  424|    100|    if (ss != s) {
  ------------------
  |  Branch (424:9): [True: 0, False: 100]
  ------------------
  425|      0|        throw Error("Expected target to be of type `",s.name,
  426|      0|            "` but seemingly it is a `",ss.name,"` instead"
  427|      0|            );
  428|      0|    }
  429|       |
  430|       |    // try to retrieve the object from the cache
  431|    100|    db.cache(out).get(s,out,ptrval);
  432|    100|    if (out) {
  ------------------
  |  Branch (432:9): [True: 92, False: 8]
  ------------------
  433|     92|        return true;
  434|     92|    }
  435|       |
  436|       |    // seek to this location, but save the previous stream pointer.
  437|      8|    const StreamReaderAny::pos pold = db.reader->GetCurrentPos();
  438|      8|    db.reader->SetCurrentPos(block->start+ static_cast<size_t>((ptrval.val - block->address.val) ));
  439|       |    // FIXME: basically, this could cause problems with 64 bit pointers on 32 bit systems.
  440|       |    // I really ought to improve StreamReader to work with 64 bit indices exclusively.
  441|       |
  442|       |    // continue conversion after allocating the required storage
  443|      8|    size_t num = block->size / ss.size;
  444|      8|    T* o = _allocate(out,num);
  445|       |
  446|       |    // cache the object before we convert it to avoid cyclic recursion.
  447|      8|    db.cache(out).set(s,out,ptrval);
  448|       |
  449|       |    // if the non_recursive flag is set, we don't do anything but leave
  450|       |    // the cursor at the correct position to resolve the object.
  451|      8|    if (!non_recursive) {
  ------------------
  |  Branch (451:9): [True: 8, False: 0]
  ------------------
  452|     16|        for (size_t i = 0; i < num; ++i,++o) {
  ------------------
  |  Branch (452:28): [True: 8, False: 8]
  ------------------
  453|      8|            s.Convert(*o,db);
  454|      8|        }
  455|       |
  456|      8|        db.reader->SetCurrentPos(pold);
  457|      8|    }
  458|       |
  459|      8|#ifndef ASSIMP_BUILD_BLENDER_NO_STATS
  460|      8|    if(out) {
  ------------------
  |  Branch (460:8): [True: 8, False: 0]
  ------------------
  461|      8|        ++db.stats().pointers_resolved;
  462|      8|    }
  463|      8|#endif
  464|      8|    return false;
  465|    100|}
_ZNK6Assimp7Blender11ObjectCacheINSt3__110shared_ptrEE3getINS0_5ImageEEEvRKNS0_9StructureERNS3_IT_EERKNS0_7PointerE:
  807|    100|) const {
  808|       |
  809|    100|    if(s.cache_idx == static_cast<size_t>(-1)) {
  ------------------
  |  Branch (809:8): [True: 6, False: 94]
  ------------------
  810|      6|        s.cache_idx = db.next_cache_idx++;
  811|      6|        caches.resize(db.next_cache_idx);
  812|      6|        return;
  813|      6|    }
  814|       |
  815|     94|    typename StructureCache::const_iterator it = caches[s.cache_idx].find(ptr);
  816|     94|    if (it != caches[s.cache_idx].end()) {
  ------------------
  |  Branch (816:9): [True: 92, False: 2]
  ------------------
  817|     92|        out = std::static_pointer_cast<T>( (*it).second );
  818|       |
  819|     92|#ifndef ASSIMP_BUILD_BLENDER_NO_STATS
  820|     92|        ++db.stats().cache_hits;
  821|     92|#endif
  822|     92|    }
  823|       |    // otherwise, out remains untouched
  824|     94|}
_ZN6Assimp7Blender11ObjectCacheINSt3__110shared_ptrEE3setINS0_5ImageEEEvRKNS0_9StructureERKNS3_IT_EERKNS0_7PointerE:
  832|      8|) {
  833|      8|    if(s.cache_idx == static_cast<size_t>(-1)) {
  ------------------
  |  Branch (833:8): [True: 0, False: 8]
  ------------------
  834|      0|        s.cache_idx = db.next_cache_idx++;
  835|      0|        caches.resize(db.next_cache_idx);
  836|      0|    }
  837|      8|    caches[s.cache_idx][ptr] = std::static_pointer_cast<ElemBase>( out );
  838|       |
  839|      8|#ifndef ASSIMP_BUILD_BLENDER_NO_STATS
  840|      8|    ++db.stats().cached_objects;
  841|      8|#endif
  842|      8|}
_ZNK6Assimp7Blender9Structure12ReadFieldPtrILi2ENS0_6vectorENS0_5MFaceEEEbRT0_IT1_EPKcRKNS0_12FileDatabaseEb:
  183|     42|{
  184|     42|    const StreamReaderAny::pos old = db.reader->GetCurrentPos();
  185|     42|    Pointer ptrval;
  186|     42|    const Field* f;
  187|     42|    try {
  188|     42|        f = &(*this)[name];
  189|       |
  190|       |        // sanity check, should never happen if the genblenddna script is right
  191|     42|        if (!(f->flags & FieldFlag_Pointer)) {
  ------------------
  |  Branch (191:13): [True: 0, False: 42]
  ------------------
  192|      0|            throw Error("Field `",name,"` of structure `",
  193|      0|                this->name,"` ought to be a pointer");
  194|      0|        }
  195|       |
  196|     42|        db.reader->IncPtr(f->offset);
  197|     42|        Convert(ptrval,db);
  198|       |        // actually it is meaningless on which Structure the Convert is called
  199|       |        // because the `Pointer` argument triggers a special implementation.
  200|     42|    }
  201|     42|    catch (const Error& e) {
  202|      0|        _defaultInitializer<error_policy>()(out,e.what());
  203|       |
  204|      0|        out.reset();
  205|      0|        return false;
  206|      0|    }
  207|       |
  208|       |    // resolve the pointer and load the corresponding structure
  209|     42|    const bool res = ResolvePointer(out,ptrval,db,*f, non_recursive);
  210|       |
  211|     42|    if(!non_recursive) {
  ------------------
  |  Branch (211:8): [True: 42, False: 0]
  ------------------
  212|       |        // and recover the previous stream position
  213|     42|        db.reader->SetCurrentPos(old);
  214|     42|    }
  215|       |
  216|     42|#ifndef ASSIMP_BUILD_BLENDER_NO_STATS
  217|     42|    ++db.stats().fields_read;
  218|     42|#endif
  219|       |
  220|     42|    return res;
  221|     42|}
_ZNK6Assimp7Blender9Structure14ResolvePointerINS0_6vectorENS0_5MFaceEEEbRT_IT0_ERKNS0_7PointerERKNS0_12FileDatabaseERKNS0_5FieldEb:
  412|     42|{
  413|     42|    out.reset(); // ensure null pointers work
  414|     42|    if (!ptrval.val) {
  ------------------
  |  Branch (414:9): [True: 11, False: 31]
  ------------------
  415|     11|        return false;
  416|     11|    }
  417|     31|    const Structure& s = db.dna[f.type];
  418|       |    // find the file block the pointer is pointing to
  419|     31|    const FileBlockHead* block = LocateFileBlockForAddress(ptrval,db);
  420|       |
  421|       |    // also determine the target type from the block header
  422|       |    // and check if it matches the type which we expect.
  423|     31|    const Structure& ss = db.dna[block->dna_index];
  424|     31|    if (ss != s) {
  ------------------
  |  Branch (424:9): [True: 0, False: 31]
  ------------------
  425|      0|        throw Error("Expected target to be of type `",s.name,
  426|      0|            "` but seemingly it is a `",ss.name,"` instead"
  427|      0|            );
  428|      0|    }
  429|       |
  430|       |    // try to retrieve the object from the cache
  431|     31|    db.cache(out).get(s,out,ptrval);
  432|     31|    if (out) {
  ------------------
  |  Branch (432:9): [True: 0, False: 31]
  ------------------
  433|      0|        return true;
  434|      0|    }
  435|       |
  436|       |    // seek to this location, but save the previous stream pointer.
  437|     31|    const StreamReaderAny::pos pold = db.reader->GetCurrentPos();
  438|     31|    db.reader->SetCurrentPos(block->start+ static_cast<size_t>((ptrval.val - block->address.val) ));
  439|       |    // FIXME: basically, this could cause problems with 64 bit pointers on 32 bit systems.
  440|       |    // I really ought to improve StreamReader to work with 64 bit indices exclusively.
  441|       |
  442|       |    // continue conversion after allocating the required storage
  443|     31|    size_t num = block->size / ss.size;
  444|     31|    T* o = _allocate(out,num);
  445|       |
  446|       |    // cache the object before we convert it to avoid cyclic recursion.
  447|     31|    db.cache(out).set(s,out,ptrval);
  448|       |
  449|       |    // if the non_recursive flag is set, we don't do anything but leave
  450|       |    // the cursor at the correct position to resolve the object.
  451|     31|    if (!non_recursive) {
  ------------------
  |  Branch (451:9): [True: 31, False: 0]
  ------------------
  452|  7.54k|        for (size_t i = 0; i < num; ++i,++o) {
  ------------------
  |  Branch (452:28): [True: 7.51k, False: 31]
  ------------------
  453|  7.51k|            s.Convert(*o,db);
  454|  7.51k|        }
  455|       |
  456|     31|        db.reader->SetCurrentPos(pold);
  457|     31|    }
  458|       |
  459|     31|#ifndef ASSIMP_BUILD_BLENDER_NO_STATS
  460|     31|    if(out) {
  ------------------
  |  Branch (460:8): [True: 31, False: 0]
  ------------------
  461|     31|        ++db.stats().pointers_resolved;
  462|     31|    }
  463|     31|#endif
  464|     31|    return false;
  465|     31|}
_ZNK6Assimp7Blender9Structure12ReadFieldPtrILi1ENS0_6vectorENS0_6MTFaceEEEbRT0_IT1_EPKcRKNS0_12FileDatabaseEb:
  183|     42|{
  184|     42|    const StreamReaderAny::pos old = db.reader->GetCurrentPos();
  185|     42|    Pointer ptrval;
  186|     42|    const Field* f;
  187|     42|    try {
  188|     42|        f = &(*this)[name];
  189|       |
  190|       |        // sanity check, should never happen if the genblenddna script is right
  191|     42|        if (!(f->flags & FieldFlag_Pointer)) {
  ------------------
  |  Branch (191:13): [True: 0, False: 42]
  ------------------
  192|      0|            throw Error("Field `",name,"` of structure `",
  193|      0|                this->name,"` ought to be a pointer");
  194|      0|        }
  195|       |
  196|     42|        db.reader->IncPtr(f->offset);
  197|     42|        Convert(ptrval,db);
  198|       |        // actually it is meaningless on which Structure the Convert is called
  199|       |        // because the `Pointer` argument triggers a special implementation.
  200|     42|    }
  201|     42|    catch (const Error& e) {
  202|      0|        _defaultInitializer<error_policy>()(out,e.what());
  203|       |
  204|      0|        out.reset();
  205|      0|        return false;
  206|      0|    }
  207|       |
  208|       |    // resolve the pointer and load the corresponding structure
  209|     42|    const bool res = ResolvePointer(out,ptrval,db,*f, non_recursive);
  210|       |
  211|     42|    if(!non_recursive) {
  ------------------
  |  Branch (211:8): [True: 42, False: 0]
  ------------------
  212|       |        // and recover the previous stream position
  213|     42|        db.reader->SetCurrentPos(old);
  214|     42|    }
  215|       |
  216|     42|#ifndef ASSIMP_BUILD_BLENDER_NO_STATS
  217|     42|    ++db.stats().fields_read;
  218|     42|#endif
  219|       |
  220|     42|    return res;
  221|     42|}
_ZNK6Assimp7Blender9Structure14ResolvePointerINS0_6vectorENS0_6MTFaceEEEbRT_IT0_ERKNS0_7PointerERKNS0_12FileDatabaseERKNS0_5FieldEb:
  412|     42|{
  413|     42|    out.reset(); // ensure null pointers work
  414|     42|    if (!ptrval.val) {
  ------------------
  |  Branch (414:9): [True: 38, False: 4]
  ------------------
  415|     38|        return false;
  416|     38|    }
  417|      4|    const Structure& s = db.dna[f.type];
  418|       |    // find the file block the pointer is pointing to
  419|      4|    const FileBlockHead* block = LocateFileBlockForAddress(ptrval,db);
  420|       |
  421|       |    // also determine the target type from the block header
  422|       |    // and check if it matches the type which we expect.
  423|      4|    const Structure& ss = db.dna[block->dna_index];
  424|      4|    if (ss != s) {
  ------------------
  |  Branch (424:9): [True: 0, False: 4]
  ------------------
  425|      0|        throw Error("Expected target to be of type `",s.name,
  426|      0|            "` but seemingly it is a `",ss.name,"` instead"
  427|      0|            );
  428|      0|    }
  429|       |
  430|       |    // try to retrieve the object from the cache
  431|      4|    db.cache(out).get(s,out,ptrval);
  432|      4|    if (out) {
  ------------------
  |  Branch (432:9): [True: 0, False: 4]
  ------------------
  433|      0|        return true;
  434|      0|    }
  435|       |
  436|       |    // seek to this location, but save the previous stream pointer.
  437|      4|    const StreamReaderAny::pos pold = db.reader->GetCurrentPos();
  438|      4|    db.reader->SetCurrentPos(block->start+ static_cast<size_t>((ptrval.val - block->address.val) ));
  439|       |    // FIXME: basically, this could cause problems with 64 bit pointers on 32 bit systems.
  440|       |    // I really ought to improve StreamReader to work with 64 bit indices exclusively.
  441|       |
  442|       |    // continue conversion after allocating the required storage
  443|      4|    size_t num = block->size / ss.size;
  444|      4|    T* o = _allocate(out,num);
  445|       |
  446|       |    // cache the object before we convert it to avoid cyclic recursion.
  447|      4|    db.cache(out).set(s,out,ptrval);
  448|       |
  449|       |    // if the non_recursive flag is set, we don't do anything but leave
  450|       |    // the cursor at the correct position to resolve the object.
  451|      4|    if (!non_recursive) {
  ------------------
  |  Branch (451:9): [True: 4, False: 0]
  ------------------
  452|     18|        for (size_t i = 0; i < num; ++i,++o) {
  ------------------
  |  Branch (452:28): [True: 14, False: 4]
  ------------------
  453|     14|            s.Convert(*o,db);
  454|     14|        }
  455|       |
  456|      4|        db.reader->SetCurrentPos(pold);
  457|      4|    }
  458|       |
  459|      4|#ifndef ASSIMP_BUILD_BLENDER_NO_STATS
  460|      4|    if(out) {
  ------------------
  |  Branch (460:8): [True: 4, False: 0]
  ------------------
  461|      4|        ++db.stats().pointers_resolved;
  462|      4|    }
  463|      4|#endif
  464|      4|    return false;
  465|      4|}
_ZNK6Assimp7Blender9Structure12ReadFieldPtrILi1ENS0_6vectorENS0_5TFaceEEEbRT0_IT1_EPKcRKNS0_12FileDatabaseEb:
  183|     42|{
  184|     42|    const StreamReaderAny::pos old = db.reader->GetCurrentPos();
  185|     42|    Pointer ptrval;
  186|     42|    const Field* f;
  187|     42|    try {
  188|     42|        f = &(*this)[name];
  189|       |
  190|       |        // sanity check, should never happen if the genblenddna script is right
  191|     42|        if (!(f->flags & FieldFlag_Pointer)) {
  ------------------
  |  Branch (191:13): [True: 0, False: 42]
  ------------------
  192|      0|            throw Error("Field `",name,"` of structure `",
  193|      0|                this->name,"` ought to be a pointer");
  194|      0|        }
  195|       |
  196|     42|        db.reader->IncPtr(f->offset);
  197|     42|        Convert(ptrval,db);
  198|       |        // actually it is meaningless on which Structure the Convert is called
  199|       |        // because the `Pointer` argument triggers a special implementation.
  200|     42|    }
  201|     42|    catch (const Error& e) {
  202|      0|        _defaultInitializer<error_policy>()(out,e.what());
  203|       |
  204|      0|        out.reset();
  205|      0|        return false;
  206|      0|    }
  207|       |
  208|       |    // resolve the pointer and load the corresponding structure
  209|     42|    const bool res = ResolvePointer(out,ptrval,db,*f, non_recursive);
  210|       |
  211|     42|    if(!non_recursive) {
  ------------------
  |  Branch (211:8): [True: 42, False: 0]
  ------------------
  212|       |        // and recover the previous stream position
  213|     42|        db.reader->SetCurrentPos(old);
  214|     42|    }
  215|       |
  216|     42|#ifndef ASSIMP_BUILD_BLENDER_NO_STATS
  217|     42|    ++db.stats().fields_read;
  218|     42|#endif
  219|       |
  220|     42|    return res;
  221|     42|}
_ZNK6Assimp7Blender9Structure14ResolvePointerINS0_6vectorENS0_5TFaceEEEbRT_IT0_ERKNS0_7PointerERKNS0_12FileDatabaseERKNS0_5FieldEb:
  412|     42|{
  413|     42|    out.reset(); // ensure null pointers work
  414|     42|    if (!ptrval.val) {
  ------------------
  |  Branch (414:9): [True: 42, False: 0]
  ------------------
  415|     42|        return false;
  416|     42|    }
  417|      0|    const Structure& s = db.dna[f.type];
  418|       |    // find the file block the pointer is pointing to
  419|      0|    const FileBlockHead* block = LocateFileBlockForAddress(ptrval,db);
  420|       |
  421|       |    // also determine the target type from the block header
  422|       |    // and check if it matches the type which we expect.
  423|      0|    const Structure& ss = db.dna[block->dna_index];
  424|      0|    if (ss != s) {
  ------------------
  |  Branch (424:9): [True: 0, False: 0]
  ------------------
  425|      0|        throw Error("Expected target to be of type `",s.name,
  426|      0|            "` but seemingly it is a `",ss.name,"` instead"
  427|      0|            );
  428|      0|    }
  429|       |
  430|       |    // try to retrieve the object from the cache
  431|      0|    db.cache(out).get(s,out,ptrval);
  432|      0|    if (out) {
  ------------------
  |  Branch (432:9): [True: 0, False: 0]
  ------------------
  433|      0|        return true;
  434|      0|    }
  435|       |
  436|       |    // seek to this location, but save the previous stream pointer.
  437|      0|    const StreamReaderAny::pos pold = db.reader->GetCurrentPos();
  438|      0|    db.reader->SetCurrentPos(block->start+ static_cast<size_t>((ptrval.val - block->address.val) ));
  439|       |    // FIXME: basically, this could cause problems with 64 bit pointers on 32 bit systems.
  440|       |    // I really ought to improve StreamReader to work with 64 bit indices exclusively.
  441|       |
  442|       |    // continue conversion after allocating the required storage
  443|      0|    size_t num = block->size / ss.size;
  444|      0|    T* o = _allocate(out,num);
  445|       |
  446|       |    // cache the object before we convert it to avoid cyclic recursion.
  447|      0|    db.cache(out).set(s,out,ptrval);
  448|       |
  449|       |    // if the non_recursive flag is set, we don't do anything but leave
  450|       |    // the cursor at the correct position to resolve the object.
  451|      0|    if (!non_recursive) {
  ------------------
  |  Branch (451:9): [True: 0, False: 0]
  ------------------
  452|      0|        for (size_t i = 0; i < num; ++i,++o) {
  ------------------
  |  Branch (452:28): [True: 0, False: 0]
  ------------------
  453|      0|            s.Convert(*o,db);
  454|      0|        }
  455|       |
  456|      0|        db.reader->SetCurrentPos(pold);
  457|      0|    }
  458|       |
  459|      0|#ifndef ASSIMP_BUILD_BLENDER_NO_STATS
  460|      0|    if(out) {
  ------------------
  |  Branch (460:8): [True: 0, False: 0]
  ------------------
  461|      0|        ++db.stats().pointers_resolved;
  462|      0|    }
  463|      0|#endif
  464|      0|    return false;
  465|      0|}
_ZNK6Assimp7Blender9Structure12ReadFieldPtrILi2ENS0_6vectorENS0_5MVertEEEbRT0_IT1_EPKcRKNS0_12FileDatabaseEb:
  183|     42|{
  184|     42|    const StreamReaderAny::pos old = db.reader->GetCurrentPos();
  185|     42|    Pointer ptrval;
  186|     42|    const Field* f;
  187|     42|    try {
  188|     42|        f = &(*this)[name];
  189|       |
  190|       |        // sanity check, should never happen if the genblenddna script is right
  191|     42|        if (!(f->flags & FieldFlag_Pointer)) {
  ------------------
  |  Branch (191:13): [True: 0, False: 42]
  ------------------
  192|      0|            throw Error("Field `",name,"` of structure `",
  193|      0|                this->name,"` ought to be a pointer");
  194|      0|        }
  195|       |
  196|     42|        db.reader->IncPtr(f->offset);
  197|     42|        Convert(ptrval,db);
  198|       |        // actually it is meaningless on which Structure the Convert is called
  199|       |        // because the `Pointer` argument triggers a special implementation.
  200|     42|    }
  201|     42|    catch (const Error& e) {
  202|      0|        _defaultInitializer<error_policy>()(out,e.what());
  203|       |
  204|      0|        out.reset();
  205|      0|        return false;
  206|      0|    }
  207|       |
  208|       |    // resolve the pointer and load the corresponding structure
  209|     42|    const bool res = ResolvePointer(out,ptrval,db,*f, non_recursive);
  210|       |
  211|     42|    if(!non_recursive) {
  ------------------
  |  Branch (211:8): [True: 42, False: 0]
  ------------------
  212|       |        // and recover the previous stream position
  213|     42|        db.reader->SetCurrentPos(old);
  214|     42|    }
  215|       |
  216|     42|#ifndef ASSIMP_BUILD_BLENDER_NO_STATS
  217|     42|    ++db.stats().fields_read;
  218|     42|#endif
  219|       |
  220|     42|    return res;
  221|     42|}
_ZNK6Assimp7Blender9Structure14ResolvePointerINS0_6vectorENS0_5MVertEEEbRT_IT0_ERKNS0_7PointerERKNS0_12FileDatabaseERKNS0_5FieldEb:
  412|     42|{
  413|     42|    out.reset(); // ensure null pointers work
  414|     42|    if (!ptrval.val) {
  ------------------
  |  Branch (414:9): [True: 0, False: 42]
  ------------------
  415|      0|        return false;
  416|      0|    }
  417|     42|    const Structure& s = db.dna[f.type];
  418|       |    // find the file block the pointer is pointing to
  419|     42|    const FileBlockHead* block = LocateFileBlockForAddress(ptrval,db);
  420|       |
  421|       |    // also determine the target type from the block header
  422|       |    // and check if it matches the type which we expect.
  423|     42|    const Structure& ss = db.dna[block->dna_index];
  424|     42|    if (ss != s) {
  ------------------
  |  Branch (424:9): [True: 0, False: 42]
  ------------------
  425|      0|        throw Error("Expected target to be of type `",s.name,
  426|      0|            "` but seemingly it is a `",ss.name,"` instead"
  427|      0|            );
  428|      0|    }
  429|       |
  430|       |    // try to retrieve the object from the cache
  431|     42|    db.cache(out).get(s,out,ptrval);
  432|     42|    if (out) {
  ------------------
  |  Branch (432:9): [True: 0, False: 42]
  ------------------
  433|      0|        return true;
  434|      0|    }
  435|       |
  436|       |    // seek to this location, but save the previous stream pointer.
  437|     42|    const StreamReaderAny::pos pold = db.reader->GetCurrentPos();
  438|     42|    db.reader->SetCurrentPos(block->start+ static_cast<size_t>((ptrval.val - block->address.val) ));
  439|       |    // FIXME: basically, this could cause problems with 64 bit pointers on 32 bit systems.
  440|       |    // I really ought to improve StreamReader to work with 64 bit indices exclusively.
  441|       |
  442|       |    // continue conversion after allocating the required storage
  443|     42|    size_t num = block->size / ss.size;
  444|     42|    T* o = _allocate(out,num);
  445|       |
  446|       |    // cache the object before we convert it to avoid cyclic recursion.
  447|     42|    db.cache(out).set(s,out,ptrval);
  448|       |
  449|       |    // if the non_recursive flag is set, we don't do anything but leave
  450|       |    // the cursor at the correct position to resolve the object.
  451|     42|    if (!non_recursive) {
  ------------------
  |  Branch (451:9): [True: 42, False: 0]
  ------------------
  452|  9.05k|        for (size_t i = 0; i < num; ++i,++o) {
  ------------------
  |  Branch (452:28): [True: 9.01k, False: 42]
  ------------------
  453|  9.01k|            s.Convert(*o,db);
  454|  9.01k|        }
  455|       |
  456|     42|        db.reader->SetCurrentPos(pold);
  457|     42|    }
  458|       |
  459|     42|#ifndef ASSIMP_BUILD_BLENDER_NO_STATS
  460|     42|    if(out) {
  ------------------
  |  Branch (460:8): [True: 42, False: 0]
  ------------------
  461|     42|        ++db.stats().pointers_resolved;
  462|     42|    }
  463|     42|#endif
  464|     42|    return false;
  465|     42|}
_ZNK6Assimp7Blender9Structure12ReadFieldPtrILi1ENS0_6vectorENS0_5MEdgeEEEbRT0_IT1_EPKcRKNS0_12FileDatabaseEb:
  183|     42|{
  184|     42|    const StreamReaderAny::pos old = db.reader->GetCurrentPos();
  185|     42|    Pointer ptrval;
  186|     42|    const Field* f;
  187|     42|    try {
  188|     42|        f = &(*this)[name];
  189|       |
  190|       |        // sanity check, should never happen if the genblenddna script is right
  191|     42|        if (!(f->flags & FieldFlag_Pointer)) {
  ------------------
  |  Branch (191:13): [True: 0, False: 42]
  ------------------
  192|      0|            throw Error("Field `",name,"` of structure `",
  193|      0|                this->name,"` ought to be a pointer");
  194|      0|        }
  195|       |
  196|     42|        db.reader->IncPtr(f->offset);
  197|     42|        Convert(ptrval,db);
  198|       |        // actually it is meaningless on which Structure the Convert is called
  199|       |        // because the `Pointer` argument triggers a special implementation.
  200|     42|    }
  201|     42|    catch (const Error& e) {
  202|      0|        _defaultInitializer<error_policy>()(out,e.what());
  203|       |
  204|      0|        out.reset();
  205|      0|        return false;
  206|      0|    }
  207|       |
  208|       |    // resolve the pointer and load the corresponding structure
  209|     42|    const bool res = ResolvePointer(out,ptrval,db,*f, non_recursive);
  210|       |
  211|     42|    if(!non_recursive) {
  ------------------
  |  Branch (211:8): [True: 42, False: 0]
  ------------------
  212|       |        // and recover the previous stream position
  213|     42|        db.reader->SetCurrentPos(old);
  214|     42|    }
  215|       |
  216|     42|#ifndef ASSIMP_BUILD_BLENDER_NO_STATS
  217|     42|    ++db.stats().fields_read;
  218|     42|#endif
  219|       |
  220|     42|    return res;
  221|     42|}
_ZNK6Assimp7Blender9Structure14ResolvePointerINS0_6vectorENS0_5MEdgeEEEbRT_IT0_ERKNS0_7PointerERKNS0_12FileDatabaseERKNS0_5FieldEb:
  412|     42|{
  413|     42|    out.reset(); // ensure null pointers work
  414|     42|    if (!ptrval.val) {
  ------------------
  |  Branch (414:9): [True: 0, False: 42]
  ------------------
  415|      0|        return false;
  416|      0|    }
  417|     42|    const Structure& s = db.dna[f.type];
  418|       |    // find the file block the pointer is pointing to
  419|     42|    const FileBlockHead* block = LocateFileBlockForAddress(ptrval,db);
  420|       |
  421|       |    // also determine the target type from the block header
  422|       |    // and check if it matches the type which we expect.
  423|     42|    const Structure& ss = db.dna[block->dna_index];
  424|     42|    if (ss != s) {
  ------------------
  |  Branch (424:9): [True: 0, False: 42]
  ------------------
  425|      0|        throw Error("Expected target to be of type `",s.name,
  426|      0|            "` but seemingly it is a `",ss.name,"` instead"
  427|      0|            );
  428|      0|    }
  429|       |
  430|       |    // try to retrieve the object from the cache
  431|     42|    db.cache(out).get(s,out,ptrval);
  432|     42|    if (out) {
  ------------------
  |  Branch (432:9): [True: 0, False: 42]
  ------------------
  433|      0|        return true;
  434|      0|    }
  435|       |
  436|       |    // seek to this location, but save the previous stream pointer.
  437|     42|    const StreamReaderAny::pos pold = db.reader->GetCurrentPos();
  438|     42|    db.reader->SetCurrentPos(block->start+ static_cast<size_t>((ptrval.val - block->address.val) ));
  439|       |    // FIXME: basically, this could cause problems with 64 bit pointers on 32 bit systems.
  440|       |    // I really ought to improve StreamReader to work with 64 bit indices exclusively.
  441|       |
  442|       |    // continue conversion after allocating the required storage
  443|     42|    size_t num = block->size / ss.size;
  444|     42|    T* o = _allocate(out,num);
  445|       |
  446|       |    // cache the object before we convert it to avoid cyclic recursion.
  447|     42|    db.cache(out).set(s,out,ptrval);
  448|       |
  449|       |    // if the non_recursive flag is set, we don't do anything but leave
  450|       |    // the cursor at the correct position to resolve the object.
  451|     42|    if (!non_recursive) {
  ------------------
  |  Branch (451:9): [True: 42, False: 0]
  ------------------
  452|  17.0k|        for (size_t i = 0; i < num; ++i,++o) {
  ------------------
  |  Branch (452:28): [True: 16.9k, False: 42]
  ------------------
  453|  16.9k|            s.Convert(*o,db);
  454|  16.9k|        }
  455|       |
  456|     42|        db.reader->SetCurrentPos(pold);
  457|     42|    }
  458|       |
  459|     42|#ifndef ASSIMP_BUILD_BLENDER_NO_STATS
  460|     42|    if(out) {
  ------------------
  |  Branch (460:8): [True: 42, False: 0]
  ------------------
  461|     42|        ++db.stats().pointers_resolved;
  462|     42|    }
  463|     42|#endif
  464|     42|    return false;
  465|     42|}
_ZNK6Assimp7Blender9Structure12ReadFieldPtrILi1ENS0_6vectorENS0_5MLoopEEEbRT0_IT1_EPKcRKNS0_12FileDatabaseEb:
  183|     42|{
  184|     42|    const StreamReaderAny::pos old = db.reader->GetCurrentPos();
  185|     42|    Pointer ptrval;
  186|     42|    const Field* f;
  187|     42|    try {
  188|     42|        f = &(*this)[name];
  189|       |
  190|       |        // sanity check, should never happen if the genblenddna script is right
  191|     42|        if (!(f->flags & FieldFlag_Pointer)) {
  ------------------
  |  Branch (191:13): [True: 0, False: 42]
  ------------------
  192|      0|            throw Error("Field `",name,"` of structure `",
  193|      0|                this->name,"` ought to be a pointer");
  194|      0|        }
  195|       |
  196|     42|        db.reader->IncPtr(f->offset);
  197|     42|        Convert(ptrval,db);
  198|       |        // actually it is meaningless on which Structure the Convert is called
  199|       |        // because the `Pointer` argument triggers a special implementation.
  200|     42|    }
  201|     42|    catch (const Error& e) {
  202|     30|        _defaultInitializer<error_policy>()(out,e.what());
  203|       |
  204|     30|        out.reset();
  205|     30|        return false;
  206|     30|    }
  207|       |
  208|       |    // resolve the pointer and load the corresponding structure
  209|     12|    const bool res = ResolvePointer(out,ptrval,db,*f, non_recursive);
  210|       |
  211|     12|    if(!non_recursive) {
  ------------------
  |  Branch (211:8): [True: 12, False: 0]
  ------------------
  212|       |        // and recover the previous stream position
  213|     12|        db.reader->SetCurrentPos(old);
  214|     12|    }
  215|       |
  216|     12|#ifndef ASSIMP_BUILD_BLENDER_NO_STATS
  217|     12|    ++db.stats().fields_read;
  218|     12|#endif
  219|       |
  220|     12|    return res;
  221|     42|}
_ZNK6Assimp7Blender9Structure14ResolvePointerINS0_6vectorENS0_5MLoopEEEbRT_IT0_ERKNS0_7PointerERKNS0_12FileDatabaseERKNS0_5FieldEb:
  412|     12|{
  413|     12|    out.reset(); // ensure null pointers work
  414|     12|    if (!ptrval.val) {
  ------------------
  |  Branch (414:9): [True: 1, False: 11]
  ------------------
  415|      1|        return false;
  416|      1|    }
  417|     11|    const Structure& s = db.dna[f.type];
  418|       |    // find the file block the pointer is pointing to
  419|     11|    const FileBlockHead* block = LocateFileBlockForAddress(ptrval,db);
  420|       |
  421|       |    // also determine the target type from the block header
  422|       |    // and check if it matches the type which we expect.
  423|     11|    const Structure& ss = db.dna[block->dna_index];
  424|     11|    if (ss != s) {
  ------------------
  |  Branch (424:9): [True: 0, False: 11]
  ------------------
  425|      0|        throw Error("Expected target to be of type `",s.name,
  426|      0|            "` but seemingly it is a `",ss.name,"` instead"
  427|      0|            );
  428|      0|    }
  429|       |
  430|       |    // try to retrieve the object from the cache
  431|     11|    db.cache(out).get(s,out,ptrval);
  432|     11|    if (out) {
  ------------------
  |  Branch (432:9): [True: 0, False: 11]
  ------------------
  433|      0|        return true;
  434|      0|    }
  435|       |
  436|       |    // seek to this location, but save the previous stream pointer.
  437|     11|    const StreamReaderAny::pos pold = db.reader->GetCurrentPos();
  438|     11|    db.reader->SetCurrentPos(block->start+ static_cast<size_t>((ptrval.val - block->address.val) ));
  439|       |    // FIXME: basically, this could cause problems with 64 bit pointers on 32 bit systems.
  440|       |    // I really ought to improve StreamReader to work with 64 bit indices exclusively.
  441|       |
  442|       |    // continue conversion after allocating the required storage
  443|     11|    size_t num = block->size / ss.size;
  444|     11|    T* o = _allocate(out,num);
  445|       |
  446|       |    // cache the object before we convert it to avoid cyclic recursion.
  447|     11|    db.cache(out).set(s,out,ptrval);
  448|       |
  449|       |    // if the non_recursive flag is set, we don't do anything but leave
  450|       |    // the cursor at the correct position to resolve the object.
  451|     11|    if (!non_recursive) {
  ------------------
  |  Branch (451:9): [True: 11, False: 0]
  ------------------
  452|  2.66k|        for (size_t i = 0; i < num; ++i,++o) {
  ------------------
  |  Branch (452:28): [True: 2.65k, False: 11]
  ------------------
  453|  2.65k|            s.Convert(*o,db);
  454|  2.65k|        }
  455|       |
  456|     11|        db.reader->SetCurrentPos(pold);
  457|     11|    }
  458|       |
  459|     11|#ifndef ASSIMP_BUILD_BLENDER_NO_STATS
  460|     11|    if(out) {
  ------------------
  |  Branch (460:8): [True: 11, False: 0]
  ------------------
  461|     11|        ++db.stats().pointers_resolved;
  462|     11|    }
  463|     11|#endif
  464|     11|    return false;
  465|     11|}
_ZNK6Assimp7Blender9Structure12ReadFieldPtrILi1ENS0_6vectorENS0_7MLoopUVEEEbRT0_IT1_EPKcRKNS0_12FileDatabaseEb:
  183|     42|{
  184|     42|    const StreamReaderAny::pos old = db.reader->GetCurrentPos();
  185|     42|    Pointer ptrval;
  186|     42|    const Field* f;
  187|     42|    try {
  188|     42|        f = &(*this)[name];
  189|       |
  190|       |        // sanity check, should never happen if the genblenddna script is right
  191|     42|        if (!(f->flags & FieldFlag_Pointer)) {
  ------------------
  |  Branch (191:13): [True: 0, False: 42]
  ------------------
  192|      0|            throw Error("Field `",name,"` of structure `",
  193|      0|                this->name,"` ought to be a pointer");
  194|      0|        }
  195|       |
  196|     42|        db.reader->IncPtr(f->offset);
  197|     42|        Convert(ptrval,db);
  198|       |        // actually it is meaningless on which Structure the Convert is called
  199|       |        // because the `Pointer` argument triggers a special implementation.
  200|     42|    }
  201|     42|    catch (const Error& e) {
  202|     30|        _defaultInitializer<error_policy>()(out,e.what());
  203|       |
  204|     30|        out.reset();
  205|     30|        return false;
  206|     30|    }
  207|       |
  208|       |    // resolve the pointer and load the corresponding structure
  209|     12|    const bool res = ResolvePointer(out,ptrval,db,*f, non_recursive);
  210|       |
  211|     12|    if(!non_recursive) {
  ------------------
  |  Branch (211:8): [True: 12, False: 0]
  ------------------
  212|       |        // and recover the previous stream position
  213|     12|        db.reader->SetCurrentPos(old);
  214|     12|    }
  215|       |
  216|     12|#ifndef ASSIMP_BUILD_BLENDER_NO_STATS
  217|     12|    ++db.stats().fields_read;
  218|     12|#endif
  219|       |
  220|     12|    return res;
  221|     42|}
_ZNK6Assimp7Blender9Structure14ResolvePointerINS0_6vectorENS0_7MLoopUVEEEbRT_IT0_ERKNS0_7PointerERKNS0_12FileDatabaseERKNS0_5FieldEb:
  412|     12|{
  413|     12|    out.reset(); // ensure null pointers work
  414|     12|    if (!ptrval.val) {
  ------------------
  |  Branch (414:9): [True: 9, False: 3]
  ------------------
  415|      9|        return false;
  416|      9|    }
  417|      3|    const Structure& s = db.dna[f.type];
  418|       |    // find the file block the pointer is pointing to
  419|      3|    const FileBlockHead* block = LocateFileBlockForAddress(ptrval,db);
  420|       |
  421|       |    // also determine the target type from the block header
  422|       |    // and check if it matches the type which we expect.
  423|      3|    const Structure& ss = db.dna[block->dna_index];
  424|      3|    if (ss != s) {
  ------------------
  |  Branch (424:9): [True: 0, False: 3]
  ------------------
  425|      0|        throw Error("Expected target to be of type `",s.name,
  426|      0|            "` but seemingly it is a `",ss.name,"` instead"
  427|      0|            );
  428|      0|    }
  429|       |
  430|       |    // try to retrieve the object from the cache
  431|      3|    db.cache(out).get(s,out,ptrval);
  432|      3|    if (out) {
  ------------------
  |  Branch (432:9): [True: 0, False: 3]
  ------------------
  433|      0|        return true;
  434|      0|    }
  435|       |
  436|       |    // seek to this location, but save the previous stream pointer.
  437|      3|    const StreamReaderAny::pos pold = db.reader->GetCurrentPos();
  438|      3|    db.reader->SetCurrentPos(block->start+ static_cast<size_t>((ptrval.val - block->address.val) ));
  439|       |    // FIXME: basically, this could cause problems with 64 bit pointers on 32 bit systems.
  440|       |    // I really ought to improve StreamReader to work with 64 bit indices exclusively.
  441|       |
  442|       |    // continue conversion after allocating the required storage
  443|      3|    size_t num = block->size / ss.size;
  444|      3|    T* o = _allocate(out,num);
  445|       |
  446|       |    // cache the object before we convert it to avoid cyclic recursion.
  447|      3|    db.cache(out).set(s,out,ptrval);
  448|       |
  449|       |    // if the non_recursive flag is set, we don't do anything but leave
  450|       |    // the cursor at the correct position to resolve the object.
  451|      3|    if (!non_recursive) {
  ------------------
  |  Branch (451:9): [True: 3, False: 0]
  ------------------
  452|    163|        for (size_t i = 0; i < num; ++i,++o) {
  ------------------
  |  Branch (452:28): [True: 160, False: 3]
  ------------------
  453|    160|            s.Convert(*o,db);
  454|    160|        }
  455|       |
  456|      3|        db.reader->SetCurrentPos(pold);
  457|      3|    }
  458|       |
  459|      3|#ifndef ASSIMP_BUILD_BLENDER_NO_STATS
  460|      3|    if(out) {
  ------------------
  |  Branch (460:8): [True: 3, False: 0]
  ------------------
  461|      3|        ++db.stats().pointers_resolved;
  462|      3|    }
  463|      3|#endif
  464|      3|    return false;
  465|      3|}
_ZNK6Assimp7Blender9Structure12ReadFieldPtrILi1ENS0_6vectorENS0_8MLoopColEEEbRT0_IT1_EPKcRKNS0_12FileDatabaseEb:
  183|     42|{
  184|     42|    const StreamReaderAny::pos old = db.reader->GetCurrentPos();
  185|     42|    Pointer ptrval;
  186|     42|    const Field* f;
  187|     42|    try {
  188|     42|        f = &(*this)[name];
  189|       |
  190|       |        // sanity check, should never happen if the genblenddna script is right
  191|     42|        if (!(f->flags & FieldFlag_Pointer)) {
  ------------------
  |  Branch (191:13): [True: 0, False: 42]
  ------------------
  192|      0|            throw Error("Field `",name,"` of structure `",
  193|      0|                this->name,"` ought to be a pointer");
  194|      0|        }
  195|       |
  196|     42|        db.reader->IncPtr(f->offset);
  197|     42|        Convert(ptrval,db);
  198|       |        // actually it is meaningless on which Structure the Convert is called
  199|       |        // because the `Pointer` argument triggers a special implementation.
  200|     42|    }
  201|     42|    catch (const Error& e) {
  202|     30|        _defaultInitializer<error_policy>()(out,e.what());
  203|       |
  204|     30|        out.reset();
  205|     30|        return false;
  206|     30|    }
  207|       |
  208|       |    // resolve the pointer and load the corresponding structure
  209|     12|    const bool res = ResolvePointer(out,ptrval,db,*f, non_recursive);
  210|       |
  211|     12|    if(!non_recursive) {
  ------------------
  |  Branch (211:8): [True: 12, False: 0]
  ------------------
  212|       |        // and recover the previous stream position
  213|     12|        db.reader->SetCurrentPos(old);
  214|     12|    }
  215|       |
  216|     12|#ifndef ASSIMP_BUILD_BLENDER_NO_STATS
  217|     12|    ++db.stats().fields_read;
  218|     12|#endif
  219|       |
  220|     12|    return res;
  221|     42|}
_ZNK6Assimp7Blender9Structure14ResolvePointerINS0_6vectorENS0_8MLoopColEEEbRT_IT0_ERKNS0_7PointerERKNS0_12FileDatabaseERKNS0_5FieldEb:
  412|     12|{
  413|     12|    out.reset(); // ensure null pointers work
  414|     12|    if (!ptrval.val) {
  ------------------
  |  Branch (414:9): [True: 12, False: 0]
  ------------------
  415|     12|        return false;
  416|     12|    }
  417|      0|    const Structure& s = db.dna[f.type];
  418|       |    // find the file block the pointer is pointing to
  419|      0|    const FileBlockHead* block = LocateFileBlockForAddress(ptrval,db);
  420|       |
  421|       |    // also determine the target type from the block header
  422|       |    // and check if it matches the type which we expect.
  423|      0|    const Structure& ss = db.dna[block->dna_index];
  424|      0|    if (ss != s) {
  ------------------
  |  Branch (424:9): [True: 0, False: 0]
  ------------------
  425|      0|        throw Error("Expected target to be of type `",s.name,
  426|      0|            "` but seemingly it is a `",ss.name,"` instead"
  427|      0|            );
  428|      0|    }
  429|       |
  430|       |    // try to retrieve the object from the cache
  431|      0|    db.cache(out).get(s,out,ptrval);
  432|      0|    if (out) {
  ------------------
  |  Branch (432:9): [True: 0, False: 0]
  ------------------
  433|      0|        return true;
  434|      0|    }
  435|       |
  436|       |    // seek to this location, but save the previous stream pointer.
  437|      0|    const StreamReaderAny::pos pold = db.reader->GetCurrentPos();
  438|      0|    db.reader->SetCurrentPos(block->start+ static_cast<size_t>((ptrval.val - block->address.val) ));
  439|       |    // FIXME: basically, this could cause problems with 64 bit pointers on 32 bit systems.
  440|       |    // I really ought to improve StreamReader to work with 64 bit indices exclusively.
  441|       |
  442|       |    // continue conversion after allocating the required storage
  443|      0|    size_t num = block->size / ss.size;
  444|      0|    T* o = _allocate(out,num);
  445|       |
  446|       |    // cache the object before we convert it to avoid cyclic recursion.
  447|      0|    db.cache(out).set(s,out,ptrval);
  448|       |
  449|       |    // if the non_recursive flag is set, we don't do anything but leave
  450|       |    // the cursor at the correct position to resolve the object.
  451|      0|    if (!non_recursive) {
  ------------------
  |  Branch (451:9): [True: 0, False: 0]
  ------------------
  452|      0|        for (size_t i = 0; i < num; ++i,++o) {
  ------------------
  |  Branch (452:28): [True: 0, False: 0]
  ------------------
  453|      0|            s.Convert(*o,db);
  454|      0|        }
  455|       |
  456|      0|        db.reader->SetCurrentPos(pold);
  457|      0|    }
  458|       |
  459|      0|#ifndef ASSIMP_BUILD_BLENDER_NO_STATS
  460|      0|    if(out) {
  ------------------
  |  Branch (460:8): [True: 0, False: 0]
  ------------------
  461|      0|        ++db.stats().pointers_resolved;
  462|      0|    }
  463|      0|#endif
  464|      0|    return false;
  465|      0|}
_ZNK6Assimp7Blender9Structure12ReadFieldPtrILi1ENS0_6vectorENS0_5MPolyEEEbRT0_IT1_EPKcRKNS0_12FileDatabaseEb:
  183|     42|{
  184|     42|    const StreamReaderAny::pos old = db.reader->GetCurrentPos();
  185|     42|    Pointer ptrval;
  186|     42|    const Field* f;
  187|     42|    try {
  188|     42|        f = &(*this)[name];
  189|       |
  190|       |        // sanity check, should never happen if the genblenddna script is right
  191|     42|        if (!(f->flags & FieldFlag_Pointer)) {
  ------------------
  |  Branch (191:13): [True: 0, False: 42]
  ------------------
  192|      0|            throw Error("Field `",name,"` of structure `",
  193|      0|                this->name,"` ought to be a pointer");
  194|      0|        }
  195|       |
  196|     42|        db.reader->IncPtr(f->offset);
  197|     42|        Convert(ptrval,db);
  198|       |        // actually it is meaningless on which Structure the Convert is called
  199|       |        // because the `Pointer` argument triggers a special implementation.
  200|     42|    }
  201|     42|    catch (const Error& e) {
  202|     30|        _defaultInitializer<error_policy>()(out,e.what());
  203|       |
  204|     30|        out.reset();
  205|     30|        return false;
  206|     30|    }
  207|       |
  208|       |    // resolve the pointer and load the corresponding structure
  209|     12|    const bool res = ResolvePointer(out,ptrval,db,*f, non_recursive);
  210|       |
  211|     12|    if(!non_recursive) {
  ------------------
  |  Branch (211:8): [True: 12, False: 0]
  ------------------
  212|       |        // and recover the previous stream position
  213|     12|        db.reader->SetCurrentPos(old);
  214|     12|    }
  215|       |
  216|     12|#ifndef ASSIMP_BUILD_BLENDER_NO_STATS
  217|     12|    ++db.stats().fields_read;
  218|     12|#endif
  219|       |
  220|     12|    return res;
  221|     42|}
_ZNK6Assimp7Blender9Structure14ResolvePointerINS0_6vectorENS0_5MPolyEEEbRT_IT0_ERKNS0_7PointerERKNS0_12FileDatabaseERKNS0_5FieldEb:
  412|     12|{
  413|     12|    out.reset(); // ensure null pointers work
  414|     12|    if (!ptrval.val) {
  ------------------
  |  Branch (414:9): [True: 1, False: 11]
  ------------------
  415|      1|        return false;
  416|      1|    }
  417|     11|    const Structure& s = db.dna[f.type];
  418|       |    // find the file block the pointer is pointing to
  419|     11|    const FileBlockHead* block = LocateFileBlockForAddress(ptrval,db);
  420|       |
  421|       |    // also determine the target type from the block header
  422|       |    // and check if it matches the type which we expect.
  423|     11|    const Structure& ss = db.dna[block->dna_index];
  424|     11|    if (ss != s) {
  ------------------
  |  Branch (424:9): [True: 0, False: 11]
  ------------------
  425|      0|        throw Error("Expected target to be of type `",s.name,
  426|      0|            "` but seemingly it is a `",ss.name,"` instead"
  427|      0|            );
  428|      0|    }
  429|       |
  430|       |    // try to retrieve the object from the cache
  431|     11|    db.cache(out).get(s,out,ptrval);
  432|     11|    if (out) {
  ------------------
  |  Branch (432:9): [True: 0, False: 11]
  ------------------
  433|      0|        return true;
  434|      0|    }
  435|       |
  436|       |    // seek to this location, but save the previous stream pointer.
  437|     11|    const StreamReaderAny::pos pold = db.reader->GetCurrentPos();
  438|     11|    db.reader->SetCurrentPos(block->start+ static_cast<size_t>((ptrval.val - block->address.val) ));
  439|       |    // FIXME: basically, this could cause problems with 64 bit pointers on 32 bit systems.
  440|       |    // I really ought to improve StreamReader to work with 64 bit indices exclusively.
  441|       |
  442|       |    // continue conversion after allocating the required storage
  443|     11|    size_t num = block->size / ss.size;
  444|     11|    T* o = _allocate(out,num);
  445|       |
  446|       |    // cache the object before we convert it to avoid cyclic recursion.
  447|     11|    db.cache(out).set(s,out,ptrval);
  448|       |
  449|       |    // if the non_recursive flag is set, we don't do anything but leave
  450|       |    // the cursor at the correct position to resolve the object.
  451|     11|    if (!non_recursive) {
  ------------------
  |  Branch (451:9): [True: 11, False: 0]
  ------------------
  452|    694|        for (size_t i = 0; i < num; ++i,++o) {
  ------------------
  |  Branch (452:28): [True: 683, False: 11]
  ------------------
  453|    683|            s.Convert(*o,db);
  454|    683|        }
  455|       |
  456|     11|        db.reader->SetCurrentPos(pold);
  457|     11|    }
  458|       |
  459|     11|#ifndef ASSIMP_BUILD_BLENDER_NO_STATS
  460|     11|    if(out) {
  ------------------
  |  Branch (460:8): [True: 11, False: 0]
  ------------------
  461|     11|        ++db.stats().pointers_resolved;
  462|     11|    }
  463|     11|#endif
  464|     11|    return false;
  465|     11|}
_ZNK6Assimp7Blender9Structure12ReadFieldPtrILi1ENS0_6vectorENS0_8MTexPolyEEEbRT0_IT1_EPKcRKNS0_12FileDatabaseEb:
  183|     42|{
  184|     42|    const StreamReaderAny::pos old = db.reader->GetCurrentPos();
  185|     42|    Pointer ptrval;
  186|     42|    const Field* f;
  187|     42|    try {
  188|     42|        f = &(*this)[name];
  189|       |
  190|       |        // sanity check, should never happen if the genblenddna script is right
  191|     42|        if (!(f->flags & FieldFlag_Pointer)) {
  ------------------
  |  Branch (191:13): [True: 0, False: 42]
  ------------------
  192|      0|            throw Error("Field `",name,"` of structure `",
  193|      0|                this->name,"` ought to be a pointer");
  194|      0|        }
  195|       |
  196|     42|        db.reader->IncPtr(f->offset);
  197|     42|        Convert(ptrval,db);
  198|       |        // actually it is meaningless on which Structure the Convert is called
  199|       |        // because the `Pointer` argument triggers a special implementation.
  200|     42|    }
  201|     42|    catch (const Error& e) {
  202|     31|        _defaultInitializer<error_policy>()(out,e.what());
  203|       |
  204|     31|        out.reset();
  205|     31|        return false;
  206|     31|    }
  207|       |
  208|       |    // resolve the pointer and load the corresponding structure
  209|     11|    const bool res = ResolvePointer(out,ptrval,db,*f, non_recursive);
  210|       |
  211|     11|    if(!non_recursive) {
  ------------------
  |  Branch (211:8): [True: 11, False: 0]
  ------------------
  212|       |        // and recover the previous stream position
  213|     11|        db.reader->SetCurrentPos(old);
  214|     11|    }
  215|       |
  216|     11|#ifndef ASSIMP_BUILD_BLENDER_NO_STATS
  217|     11|    ++db.stats().fields_read;
  218|     11|#endif
  219|       |
  220|     11|    return res;
  221|     42|}
_ZNK6Assimp7Blender9Structure14ResolvePointerINS0_6vectorENS0_8MTexPolyEEEbRT_IT0_ERKNS0_7PointerERKNS0_12FileDatabaseERKNS0_5FieldEb:
  412|     11|{
  413|     11|    out.reset(); // ensure null pointers work
  414|     11|    if (!ptrval.val) {
  ------------------
  |  Branch (414:9): [True: 9, False: 2]
  ------------------
  415|      9|        return false;
  416|      9|    }
  417|      2|    const Structure& s = db.dna[f.type];
  418|       |    // find the file block the pointer is pointing to
  419|      2|    const FileBlockHead* block = LocateFileBlockForAddress(ptrval,db);
  420|       |
  421|       |    // also determine the target type from the block header
  422|       |    // and check if it matches the type which we expect.
  423|      2|    const Structure& ss = db.dna[block->dna_index];
  424|      2|    if (ss != s) {
  ------------------
  |  Branch (424:9): [True: 0, False: 2]
  ------------------
  425|      0|        throw Error("Expected target to be of type `",s.name,
  426|      0|            "` but seemingly it is a `",ss.name,"` instead"
  427|      0|            );
  428|      0|    }
  429|       |
  430|       |    // try to retrieve the object from the cache
  431|      2|    db.cache(out).get(s,out,ptrval);
  432|      2|    if (out) {
  ------------------
  |  Branch (432:9): [True: 0, False: 2]
  ------------------
  433|      0|        return true;
  434|      0|    }
  435|       |
  436|       |    // seek to this location, but save the previous stream pointer.
  437|      2|    const StreamReaderAny::pos pold = db.reader->GetCurrentPos();
  438|      2|    db.reader->SetCurrentPos(block->start+ static_cast<size_t>((ptrval.val - block->address.val) ));
  439|       |    // FIXME: basically, this could cause problems with 64 bit pointers on 32 bit systems.
  440|       |    // I really ought to improve StreamReader to work with 64 bit indices exclusively.
  441|       |
  442|       |    // continue conversion after allocating the required storage
  443|      2|    size_t num = block->size / ss.size;
  444|      2|    T* o = _allocate(out,num);
  445|       |
  446|       |    // cache the object before we convert it to avoid cyclic recursion.
  447|      2|    db.cache(out).set(s,out,ptrval);
  448|       |
  449|       |    // if the non_recursive flag is set, we don't do anything but leave
  450|       |    // the cursor at the correct position to resolve the object.
  451|      2|    if (!non_recursive) {
  ------------------
  |  Branch (451:9): [True: 2, False: 0]
  ------------------
  452|     47|        for (size_t i = 0; i < num; ++i,++o) {
  ------------------
  |  Branch (452:28): [True: 45, False: 2]
  ------------------
  453|     45|            s.Convert(*o,db);
  454|     45|        }
  455|       |
  456|      2|        db.reader->SetCurrentPos(pold);
  457|      2|    }
  458|       |
  459|      2|#ifndef ASSIMP_BUILD_BLENDER_NO_STATS
  460|      2|    if(out) {
  ------------------
  |  Branch (460:8): [True: 2, False: 0]
  ------------------
  461|      2|        ++db.stats().pointers_resolved;
  462|      2|    }
  463|      2|#endif
  464|      2|    return false;
  465|      2|}
_ZNK6Assimp7Blender9Structure12ReadFieldPtrILi1ENS0_6vectorENS0_11MDeformVertEEEbRT0_IT1_EPKcRKNS0_12FileDatabaseEb:
  183|     42|{
  184|     42|    const StreamReaderAny::pos old = db.reader->GetCurrentPos();
  185|     42|    Pointer ptrval;
  186|     42|    const Field* f;
  187|     42|    try {
  188|     42|        f = &(*this)[name];
  189|       |
  190|       |        // sanity check, should never happen if the genblenddna script is right
  191|     42|        if (!(f->flags & FieldFlag_Pointer)) {
  ------------------
  |  Branch (191:13): [True: 0, False: 42]
  ------------------
  192|      0|            throw Error("Field `",name,"` of structure `",
  193|      0|                this->name,"` ought to be a pointer");
  194|      0|        }
  195|       |
  196|     42|        db.reader->IncPtr(f->offset);
  197|     42|        Convert(ptrval,db);
  198|       |        // actually it is meaningless on which Structure the Convert is called
  199|       |        // because the `Pointer` argument triggers a special implementation.
  200|     42|    }
  201|     42|    catch (const Error& e) {
  202|      0|        _defaultInitializer<error_policy>()(out,e.what());
  203|       |
  204|      0|        out.reset();
  205|      0|        return false;
  206|      0|    }
  207|       |
  208|       |    // resolve the pointer and load the corresponding structure
  209|     42|    const bool res = ResolvePointer(out,ptrval,db,*f, non_recursive);
  210|       |
  211|     42|    if(!non_recursive) {
  ------------------
  |  Branch (211:8): [True: 42, False: 0]
  ------------------
  212|       |        // and recover the previous stream position
  213|     42|        db.reader->SetCurrentPos(old);
  214|     42|    }
  215|       |
  216|     42|#ifndef ASSIMP_BUILD_BLENDER_NO_STATS
  217|     42|    ++db.stats().fields_read;
  218|     42|#endif
  219|       |
  220|     42|    return res;
  221|     42|}
_ZNK6Assimp7Blender9Structure14ResolvePointerINS0_6vectorENS0_11MDeformVertEEEbRT_IT0_ERKNS0_7PointerERKNS0_12FileDatabaseERKNS0_5FieldEb:
  412|     42|{
  413|     42|    out.reset(); // ensure null pointers work
  414|     42|    if (!ptrval.val) {
  ------------------
  |  Branch (414:9): [True: 42, False: 0]
  ------------------
  415|     42|        return false;
  416|     42|    }
  417|      0|    const Structure& s = db.dna[f.type];
  418|       |    // find the file block the pointer is pointing to
  419|      0|    const FileBlockHead* block = LocateFileBlockForAddress(ptrval,db);
  420|       |
  421|       |    // also determine the target type from the block header
  422|       |    // and check if it matches the type which we expect.
  423|      0|    const Structure& ss = db.dna[block->dna_index];
  424|      0|    if (ss != s) {
  ------------------
  |  Branch (424:9): [True: 0, False: 0]
  ------------------
  425|      0|        throw Error("Expected target to be of type `",s.name,
  426|      0|            "` but seemingly it is a `",ss.name,"` instead"
  427|      0|            );
  428|      0|    }
  429|       |
  430|       |    // try to retrieve the object from the cache
  431|      0|    db.cache(out).get(s,out,ptrval);
  432|      0|    if (out) {
  ------------------
  |  Branch (432:9): [True: 0, False: 0]
  ------------------
  433|      0|        return true;
  434|      0|    }
  435|       |
  436|       |    // seek to this location, but save the previous stream pointer.
  437|      0|    const StreamReaderAny::pos pold = db.reader->GetCurrentPos();
  438|      0|    db.reader->SetCurrentPos(block->start+ static_cast<size_t>((ptrval.val - block->address.val) ));
  439|       |    // FIXME: basically, this could cause problems with 64 bit pointers on 32 bit systems.
  440|       |    // I really ought to improve StreamReader to work with 64 bit indices exclusively.
  441|       |
  442|       |    // continue conversion after allocating the required storage
  443|      0|    size_t num = block->size / ss.size;
  444|      0|    T* o = _allocate(out,num);
  445|       |
  446|       |    // cache the object before we convert it to avoid cyclic recursion.
  447|      0|    db.cache(out).set(s,out,ptrval);
  448|       |
  449|       |    // if the non_recursive flag is set, we don't do anything but leave
  450|       |    // the cursor at the correct position to resolve the object.
  451|      0|    if (!non_recursive) {
  ------------------
  |  Branch (451:9): [True: 0, False: 0]
  ------------------
  452|      0|        for (size_t i = 0; i < num; ++i,++o) {
  ------------------
  |  Branch (452:28): [True: 0, False: 0]
  ------------------
  453|      0|            s.Convert(*o,db);
  454|      0|        }
  455|       |
  456|      0|        db.reader->SetCurrentPos(pold);
  457|      0|    }
  458|       |
  459|      0|#ifndef ASSIMP_BUILD_BLENDER_NO_STATS
  460|      0|    if(out) {
  ------------------
  |  Branch (460:8): [True: 0, False: 0]
  ------------------
  461|      0|        ++db.stats().pointers_resolved;
  462|      0|    }
  463|      0|#endif
  464|      0|    return false;
  465|      0|}
_ZNK6Assimp7Blender9Structure12ReadFieldPtrILi1ENS0_6vectorENS0_4MColEEEbRT0_IT1_EPKcRKNS0_12FileDatabaseEb:
  183|     42|{
  184|     42|    const StreamReaderAny::pos old = db.reader->GetCurrentPos();
  185|     42|    Pointer ptrval;
  186|     42|    const Field* f;
  187|     42|    try {
  188|     42|        f = &(*this)[name];
  189|       |
  190|       |        // sanity check, should never happen if the genblenddna script is right
  191|     42|        if (!(f->flags & FieldFlag_Pointer)) {
  ------------------
  |  Branch (191:13): [True: 0, False: 42]
  ------------------
  192|      0|            throw Error("Field `",name,"` of structure `",
  193|      0|                this->name,"` ought to be a pointer");
  194|      0|        }
  195|       |
  196|     42|        db.reader->IncPtr(f->offset);
  197|     42|        Convert(ptrval,db);
  198|       |        // actually it is meaningless on which Structure the Convert is called
  199|       |        // because the `Pointer` argument triggers a special implementation.
  200|     42|    }
  201|     42|    catch (const Error& e) {
  202|      0|        _defaultInitializer<error_policy>()(out,e.what());
  203|       |
  204|      0|        out.reset();
  205|      0|        return false;
  206|      0|    }
  207|       |
  208|       |    // resolve the pointer and load the corresponding structure
  209|     42|    const bool res = ResolvePointer(out,ptrval,db,*f, non_recursive);
  210|       |
  211|     42|    if(!non_recursive) {
  ------------------
  |  Branch (211:8): [True: 42, False: 0]
  ------------------
  212|       |        // and recover the previous stream position
  213|     42|        db.reader->SetCurrentPos(old);
  214|     42|    }
  215|       |
  216|     42|#ifndef ASSIMP_BUILD_BLENDER_NO_STATS
  217|     42|    ++db.stats().fields_read;
  218|     42|#endif
  219|       |
  220|     42|    return res;
  221|     42|}
_ZNK6Assimp7Blender9Structure14ResolvePointerINS0_6vectorENS0_4MColEEEbRT_IT0_ERKNS0_7PointerERKNS0_12FileDatabaseERKNS0_5FieldEb:
  412|     42|{
  413|     42|    out.reset(); // ensure null pointers work
  414|     42|    if (!ptrval.val) {
  ------------------
  |  Branch (414:9): [True: 41, False: 1]
  ------------------
  415|     41|        return false;
  416|     41|    }
  417|      1|    const Structure& s = db.dna[f.type];
  418|       |    // find the file block the pointer is pointing to
  419|      1|    const FileBlockHead* block = LocateFileBlockForAddress(ptrval,db);
  420|       |
  421|       |    // also determine the target type from the block header
  422|       |    // and check if it matches the type which we expect.
  423|      1|    const Structure& ss = db.dna[block->dna_index];
  424|      1|    if (ss != s) {
  ------------------
  |  Branch (424:9): [True: 0, False: 1]
  ------------------
  425|      0|        throw Error("Expected target to be of type `",s.name,
  426|      0|            "` but seemingly it is a `",ss.name,"` instead"
  427|      0|            );
  428|      0|    }
  429|       |
  430|       |    // try to retrieve the object from the cache
  431|      1|    db.cache(out).get(s,out,ptrval);
  432|      1|    if (out) {
  ------------------
  |  Branch (432:9): [True: 0, False: 1]
  ------------------
  433|      0|        return true;
  434|      0|    }
  435|       |
  436|       |    // seek to this location, but save the previous stream pointer.
  437|      1|    const StreamReaderAny::pos pold = db.reader->GetCurrentPos();
  438|      1|    db.reader->SetCurrentPos(block->start+ static_cast<size_t>((ptrval.val - block->address.val) ));
  439|       |    // FIXME: basically, this could cause problems with 64 bit pointers on 32 bit systems.
  440|       |    // I really ought to improve StreamReader to work with 64 bit indices exclusively.
  441|       |
  442|       |    // continue conversion after allocating the required storage
  443|      1|    size_t num = block->size / ss.size;
  444|      1|    T* o = _allocate(out,num);
  445|       |
  446|       |    // cache the object before we convert it to avoid cyclic recursion.
  447|      1|    db.cache(out).set(s,out,ptrval);
  448|       |
  449|       |    // if the non_recursive flag is set, we don't do anything but leave
  450|       |    // the cursor at the correct position to resolve the object.
  451|      1|    if (!non_recursive) {
  ------------------
  |  Branch (451:9): [True: 1, False: 0]
  ------------------
  452|     25|        for (size_t i = 0; i < num; ++i,++o) {
  ------------------
  |  Branch (452:28): [True: 24, False: 1]
  ------------------
  453|     24|            s.Convert(*o,db);
  454|     24|        }
  455|       |
  456|      1|        db.reader->SetCurrentPos(pold);
  457|      1|    }
  458|       |
  459|      1|#ifndef ASSIMP_BUILD_BLENDER_NO_STATS
  460|      1|    if(out) {
  ------------------
  |  Branch (460:8): [True: 1, False: 0]
  ------------------
  461|      1|        ++db.stats().pointers_resolved;
  462|      1|    }
  463|      1|#endif
  464|      1|    return false;
  465|      1|}
_ZNK6Assimp7Blender9Structure12ReadFieldPtrILi2ENS0_6vectorENSt3__110shared_ptrINS0_8MaterialEEEEEbRT0_IT1_EPKcRKNS0_12FileDatabaseEb:
  183|     42|{
  184|     42|    const StreamReaderAny::pos old = db.reader->GetCurrentPos();
  185|     42|    Pointer ptrval;
  186|     42|    const Field* f;
  187|     42|    try {
  188|     42|        f = &(*this)[name];
  189|       |
  190|       |        // sanity check, should never happen if the genblenddna script is right
  191|     42|        if (!(f->flags & FieldFlag_Pointer)) {
  ------------------
  |  Branch (191:13): [True: 0, False: 42]
  ------------------
  192|      0|            throw Error("Field `",name,"` of structure `",
  193|      0|                this->name,"` ought to be a pointer");
  194|      0|        }
  195|       |
  196|     42|        db.reader->IncPtr(f->offset);
  197|     42|        Convert(ptrval,db);
  198|       |        // actually it is meaningless on which Structure the Convert is called
  199|       |        // because the `Pointer` argument triggers a special implementation.
  200|     42|    }
  201|     42|    catch (const Error& e) {
  202|      0|        _defaultInitializer<error_policy>()(out,e.what());
  203|       |
  204|      0|        out.reset();
  205|      0|        return false;
  206|      0|    }
  207|       |
  208|       |    // resolve the pointer and load the corresponding structure
  209|     42|    const bool res = ResolvePointer(out,ptrval,db,*f, non_recursive);
  210|       |
  211|     42|    if(!non_recursive) {
  ------------------
  |  Branch (211:8): [True: 42, False: 0]
  ------------------
  212|       |        // and recover the previous stream position
  213|     42|        db.reader->SetCurrentPos(old);
  214|     42|    }
  215|       |
  216|     42|#ifndef ASSIMP_BUILD_BLENDER_NO_STATS
  217|     42|    ++db.stats().fields_read;
  218|     42|#endif
  219|       |
  220|     42|    return res;
  221|     42|}
_ZNK6Assimp7Blender9Structure14ResolvePointerINSt3__110shared_ptrENS0_8MaterialEEEbRNS0_6vectorIT_IT0_EEERKNS0_7PointerERKNS0_12FileDatabaseERKNS0_5FieldEb:
  495|     42|{
  496|       |    // This is a function overload, not a template specialization. According to
  497|       |    // the partial ordering rules, it should be selected by the compiler
  498|       |    // for array-of-pointer inputs, i.e. Object::mats.
  499|       |
  500|     42|    out.reset();
  501|     42|    if (!ptrval.val) {
  ------------------
  |  Branch (501:9): [True: 4, False: 38]
  ------------------
  502|      4|        return false;
  503|      4|    }
  504|       |
  505|       |    // find the file block the pointer is pointing to
  506|     38|    const FileBlockHead* block = LocateFileBlockForAddress(ptrval,db);
  507|     38|    const size_t num = block->size / (db.i64bit?8:4);
  ------------------
  |  Branch (507:39): [True: 15, False: 23]
  ------------------
  508|       |
  509|       |    // keep the old stream position
  510|     38|    const StreamReaderAny::pos pold = db.reader->GetCurrentPos();
  511|     38|    db.reader->SetCurrentPos(block->start+ static_cast<size_t>((ptrval.val - block->address.val) ));
  512|       |
  513|     38|    bool res = false;
  514|       |    // allocate raw storage for the array
  515|     38|    out.resize(num);
  516|     77|    for (size_t i = 0; i< num; ++i) {
  ------------------
  |  Branch (516:24): [True: 39, False: 38]
  ------------------
  517|     39|        Pointer val;
  518|     39|        Convert(val,db);
  519|       |
  520|       |        // and resolve the pointees
  521|     39|        res = ResolvePointer(out[i],val,db,f) && res;
  ------------------
  |  Branch (521:15): [True: 11, False: 28]
  |  Branch (521:50): [True: 0, False: 11]
  ------------------
  522|     39|    }
  523|       |
  524|     38|    db.reader->SetCurrentPos(pold);
  525|     38|    return res;
  526|     42|}
_ZNK6Assimp7Blender9Structure14ResolvePointerINSt3__110shared_ptrENS0_8MaterialEEEbRT_IT0_ERKNS0_7PointerERKNS0_12FileDatabaseERKNS0_5FieldEb:
  412|     39|{
  413|     39|    out.reset(); // ensure null pointers work
  414|     39|    if (!ptrval.val) {
  ------------------
  |  Branch (414:9): [True: 0, False: 39]
  ------------------
  415|      0|        return false;
  416|      0|    }
  417|     39|    const Structure& s = db.dna[f.type];
  418|       |    // find the file block the pointer is pointing to
  419|     39|    const FileBlockHead* block = LocateFileBlockForAddress(ptrval,db);
  420|       |
  421|       |    // also determine the target type from the block header
  422|       |    // and check if it matches the type which we expect.
  423|     39|    const Structure& ss = db.dna[block->dna_index];
  424|     39|    if (ss != s) {
  ------------------
  |  Branch (424:9): [True: 0, False: 39]
  ------------------
  425|      0|        throw Error("Expected target to be of type `",s.name,
  426|      0|            "` but seemingly it is a `",ss.name,"` instead"
  427|      0|            );
  428|      0|    }
  429|       |
  430|       |    // try to retrieve the object from the cache
  431|     39|    db.cache(out).get(s,out,ptrval);
  432|     39|    if (out) {
  ------------------
  |  Branch (432:9): [True: 11, False: 28]
  ------------------
  433|     11|        return true;
  434|     11|    }
  435|       |
  436|       |    // seek to this location, but save the previous stream pointer.
  437|     28|    const StreamReaderAny::pos pold = db.reader->GetCurrentPos();
  438|     28|    db.reader->SetCurrentPos(block->start+ static_cast<size_t>((ptrval.val - block->address.val) ));
  439|       |    // FIXME: basically, this could cause problems with 64 bit pointers on 32 bit systems.
  440|       |    // I really ought to improve StreamReader to work with 64 bit indices exclusively.
  441|       |
  442|       |    // continue conversion after allocating the required storage
  443|     28|    size_t num = block->size / ss.size;
  444|     28|    T* o = _allocate(out,num);
  445|       |
  446|       |    // cache the object before we convert it to avoid cyclic recursion.
  447|     28|    db.cache(out).set(s,out,ptrval);
  448|       |
  449|       |    // if the non_recursive flag is set, we don't do anything but leave
  450|       |    // the cursor at the correct position to resolve the object.
  451|     28|    if (!non_recursive) {
  ------------------
  |  Branch (451:9): [True: 28, False: 0]
  ------------------
  452|     56|        for (size_t i = 0; i < num; ++i,++o) {
  ------------------
  |  Branch (452:28): [True: 28, False: 28]
  ------------------
  453|     28|            s.Convert(*o,db);
  454|     28|        }
  455|       |
  456|     28|        db.reader->SetCurrentPos(pold);
  457|     28|    }
  458|       |
  459|     28|#ifndef ASSIMP_BUILD_BLENDER_NO_STATS
  460|     28|    if(out) {
  ------------------
  |  Branch (460:8): [True: 28, False: 0]
  ------------------
  461|     28|        ++db.stats().pointers_resolved;
  462|     28|    }
  463|     28|#endif
  464|     28|    return false;
  465|     39|}
_ZNK6Assimp7Blender11ObjectCacheINSt3__110shared_ptrEE3getINS0_8MaterialEEEvRKNS0_9StructureERNS3_IT_EERKNS0_7PointerE:
  807|     39|) const {
  808|       |
  809|     39|    if(s.cache_idx == static_cast<size_t>(-1)) {
  ------------------
  |  Branch (809:8): [True: 23, False: 16]
  ------------------
  810|     23|        s.cache_idx = db.next_cache_idx++;
  811|     23|        caches.resize(db.next_cache_idx);
  812|     23|        return;
  813|     23|    }
  814|       |
  815|     16|    typename StructureCache::const_iterator it = caches[s.cache_idx].find(ptr);
  816|     16|    if (it != caches[s.cache_idx].end()) {
  ------------------
  |  Branch (816:9): [True: 11, False: 5]
  ------------------
  817|     11|        out = std::static_pointer_cast<T>( (*it).second );
  818|       |
  819|     11|#ifndef ASSIMP_BUILD_BLENDER_NO_STATS
  820|     11|        ++db.stats().cache_hits;
  821|     11|#endif
  822|     11|    }
  823|       |    // otherwise, out remains untouched
  824|     16|}
_ZN6Assimp7Blender11ObjectCacheINSt3__110shared_ptrEE3setINS0_8MaterialEEEvRKNS0_9StructureERKNS3_IT_EERKNS0_7PointerE:
  832|     28|) {
  833|     28|    if(s.cache_idx == static_cast<size_t>(-1)) {
  ------------------
  |  Branch (833:8): [True: 0, False: 28]
  ------------------
  834|      0|        s.cache_idx = db.next_cache_idx++;
  835|      0|        caches.resize(db.next_cache_idx);
  836|      0|    }
  837|     28|    caches[s.cache_idx][ptr] = std::static_pointer_cast<ElemBase>( out );
  838|       |
  839|     28|#ifndef ASSIMP_BUILD_BLENDER_NO_STATS
  840|     28|    ++db.stats().cached_objects;
  841|     28|#endif
  842|     28|}
_ZNK6Assimp7Blender9Structure9ReadFieldILi1ENS0_10CustomDataEEEvRT0_PKcRKNS0_12FileDatabaseE:
  282|    208|{
  283|    208|    const StreamReaderAny::pos old = db.reader->GetCurrentPos();
  284|    208|    try {
  285|    208|        const Field& f = (*this)[name];
  286|       |        // find the structure definition pertaining to this field
  287|    208|        const Structure& s = db.dna[f.type];
  288|       |
  289|    208|        db.reader->IncPtr(f.offset);
  290|    208|        s.Convert(out,db);
  291|    208|    }
  292|    208|    catch (const Error& e) {
  293|     61|        _defaultInitializer<error_policy>()(out,e.what());
  294|     61|    }
  295|       |
  296|       |    // and recover the previous stream position
  297|    208|    db.reader->SetCurrentPos(old);
  298|       |
  299|    207|#ifndef ASSIMP_BUILD_BLENDER_NO_STATS
  300|    207|    ++db.stats().fields_read;
  301|    207|#endif
  302|    207|}
_ZNK6Assimp7Blender9Structure14ReadFieldArrayILi2EfLm3EEEvRAT1__T0_PKcRKNS0_12FileDatabaseE:
  100|  18.0k|{
  101|  18.0k|    const StreamReaderAny::pos old = db.reader->GetCurrentPos();
  102|  18.0k|    try {
  103|  18.0k|        const Field& f = (*this)[name];
  104|  18.0k|        const Structure& s = db.dna[f.type];
  105|       |
  106|       |        // is the input actually an array?
  107|  18.0k|        if (!(f.flags & FieldFlag_Array)) {
  ------------------
  |  Branch (107:13): [True: 0, False: 18.0k]
  ------------------
  108|      0|            throw Error("Field `",name,"` of structure `",this->name,"` ought to be an array of size ",M);
  109|      0|        }
  110|       |
  111|  18.0k|        db.reader->IncPtr(f.offset);
  112|       |
  113|       |        // size conversions are always allowed, regardless of error_policy
  114|  18.0k|        unsigned int i = 0;
  115|  72.1k|        for(; i < std::min(f.array_sizes[0],M); ++i) {
  ------------------
  |  Branch (115:15): [True: 54.0k, False: 18.0k]
  ------------------
  116|  54.0k|            s.Convert(out[i],db);
  117|  54.0k|        }
  118|  18.0k|        for(; i < M; ++i) {
  ------------------
  |  Branch (118:15): [True: 0, False: 18.0k]
  ------------------
  119|      0|            _defaultInitializer<ErrorPolicy_Igno>()(out[i]);
  120|      0|        }
  121|  18.0k|    }
  122|  18.0k|    catch (const Error& e) {
  123|      0|        _defaultInitializer<error_policy>()(out,e.what());
  124|      0|    }
  125|       |
  126|       |    // and recover the previous stream position
  127|  18.0k|    db.reader->SetCurrentPos(old);
  128|       |
  129|  18.0k|#ifndef ASSIMP_BUILD_BLENDER_NO_STATS
  130|  18.0k|    ++db.stats().fields_read;
  131|  18.0k|#endif
  132|  18.0k|}
_ZNK6Assimp7Blender9Structure14ReadFieldArrayILi1EfLm2EEEvRAT1__T0_PKcRKNS0_12FileDatabaseE:
  100|    324|{
  101|    324|    const StreamReaderAny::pos old = db.reader->GetCurrentPos();
  102|    324|    try {
  103|    324|        const Field& f = (*this)[name];
  104|    324|        const Structure& s = db.dna[f.type];
  105|       |
  106|       |        // is the input actually an array?
  107|    324|        if (!(f.flags & FieldFlag_Array)) {
  ------------------
  |  Branch (107:13): [True: 0, False: 324]
  ------------------
  108|      0|            throw Error("Field `",name,"` of structure `",this->name,"` ought to be an array of size ",M);
  109|      0|        }
  110|       |
  111|    324|        db.reader->IncPtr(f.offset);
  112|       |
  113|       |        // size conversions are always allowed, regardless of error_policy
  114|    324|        unsigned int i = 0;
  115|    972|        for(; i < std::min(f.array_sizes[0],M); ++i) {
  ------------------
  |  Branch (115:15): [True: 648, False: 324]
  ------------------
  116|    648|            s.Convert(out[i],db);
  117|    648|        }
  118|    324|        for(; i < M; ++i) {
  ------------------
  |  Branch (118:15): [True: 0, False: 324]
  ------------------
  119|      0|            _defaultInitializer<ErrorPolicy_Igno>()(out[i]);
  120|      0|        }
  121|    324|    }
  122|    324|    catch (const Error& e) {
  123|      0|        _defaultInitializer<error_policy>()(out,e.what());
  124|      0|    }
  125|       |
  126|       |    // and recover the previous stream position
  127|    324|    db.reader->SetCurrentPos(old);
  128|       |
  129|    324|#ifndef ASSIMP_BUILD_BLENDER_NO_STATS
  130|    324|    ++db.stats().fields_read;
  131|    324|#endif
  132|    324|}
_ZNK6Assimp7Blender9Structure12ReadFieldPtrILi1ENSt3__110shared_ptrENS0_8ElemBaseEEEbRT0_IT1_EPKcRKNS0_12FileDatabaseEb:
  183|    268|{
  184|    268|    const StreamReaderAny::pos old = db.reader->GetCurrentPos();
  185|    268|    Pointer ptrval;
  186|    268|    const Field* f;
  187|    268|    try {
  188|    268|        f = &(*this)[name];
  189|       |
  190|       |        // sanity check, should never happen if the genblenddna script is right
  191|    268|        if (!(f->flags & FieldFlag_Pointer)) {
  ------------------
  |  Branch (191:13): [True: 0, False: 268]
  ------------------
  192|      0|            throw Error("Field `",name,"` of structure `",
  193|      0|                this->name,"` ought to be a pointer");
  194|      0|        }
  195|       |
  196|    268|        db.reader->IncPtr(f->offset);
  197|    268|        Convert(ptrval,db);
  198|       |        // actually it is meaningless on which Structure the Convert is called
  199|       |        // because the `Pointer` argument triggers a special implementation.
  200|    268|    }
  201|    268|    catch (const Error& e) {
  202|      0|        _defaultInitializer<error_policy>()(out,e.what());
  203|       |
  204|      0|        out.reset();
  205|      0|        return false;
  206|      0|    }
  207|       |
  208|       |    // resolve the pointer and load the corresponding structure
  209|    268|    const bool res = ResolvePointer(out,ptrval,db,*f, non_recursive);
  210|       |
  211|    268|    if(!non_recursive) {
  ------------------
  |  Branch (211:8): [True: 268, False: 0]
  ------------------
  212|       |        // and recover the previous stream position
  213|    268|        db.reader->SetCurrentPos(old);
  214|    268|    }
  215|       |
  216|    268|#ifndef ASSIMP_BUILD_BLENDER_NO_STATS
  217|    268|    ++db.stats().fields_read;
  218|    268|#endif
  219|       |
  220|    268|    return res;
  221|    268|}
_ZNK6Assimp7Blender9Structure14ReadFieldArrayILi1EcLm1024EEEvRAT1__T0_PKcRKNS0_12FileDatabaseE:
  100|    290|{
  101|    290|    const StreamReaderAny::pos old = db.reader->GetCurrentPos();
  102|    290|    try {
  103|    290|        const Field& f = (*this)[name];
  104|    290|        const Structure& s = db.dna[f.type];
  105|       |
  106|       |        // is the input actually an array?
  107|    290|        if (!(f.flags & FieldFlag_Array)) {
  ------------------
  |  Branch (107:13): [True: 0, False: 290]
  ------------------
  108|      0|            throw Error("Field `",name,"` of structure `",this->name,"` ought to be an array of size ",M);
  109|      0|        }
  110|       |
  111|    290|        db.reader->IncPtr(f.offset);
  112|       |
  113|       |        // size conversions are always allowed, regardless of error_policy
  114|    290|        unsigned int i = 0;
  115|  11.7k|        for(; i < std::min(f.array_sizes[0],M); ++i) {
  ------------------
  |  Branch (115:15): [True: 11.4k, False: 290]
  ------------------
  116|  11.4k|            s.Convert(out[i],db);
  117|  11.4k|        }
  118|   285k|        for(; i < M; ++i) {
  ------------------
  |  Branch (118:15): [True: 285k, False: 290]
  ------------------
  119|   285k|            _defaultInitializer<ErrorPolicy_Igno>()(out[i]);
  120|   285k|        }
  121|    290|    }
  122|    290|    catch (const Error& e) {
  123|      0|        _defaultInitializer<error_policy>()(out,e.what());
  124|      0|    }
  125|       |
  126|       |    // and recover the previous stream position
  127|    290|    db.reader->SetCurrentPos(old);
  128|       |
  129|    290|#ifndef ASSIMP_BUILD_BLENDER_NO_STATS
  130|    290|    ++db.stats().fields_read;
  131|    290|#endif
  132|    290|}
_ZNK6Assimp7Blender9Structure9ReadFieldILi2EcEEvRT0_PKcRKNS0_12FileDatabaseE:
  282|     96|{
  283|     96|    const StreamReaderAny::pos old = db.reader->GetCurrentPos();
  284|     96|    try {
  285|     96|        const Field& f = (*this)[name];
  286|       |        // find the structure definition pertaining to this field
  287|     96|        const Structure& s = db.dna[f.type];
  288|       |
  289|     96|        db.reader->IncPtr(f.offset);
  290|     96|        s.Convert(out,db);
  291|     96|    }
  292|     96|    catch (const Error& e) {
  293|      0|        _defaultInitializer<error_policy>()(out,e.what());
  294|      0|    }
  295|       |
  296|       |    // and recover the previous stream position
  297|     96|    db.reader->SetCurrentPos(old);
  298|       |
  299|     96|#ifndef ASSIMP_BUILD_BLENDER_NO_STATS
  300|     96|    ++db.stats().fields_read;
  301|     96|#endif
  302|     96|}
_ZNK6Assimp7Blender9Structure12ReadFieldPtrILi1ENSt3__110shared_ptrENS0_5WorldEEEbRT0_IT1_EPKcRKNS0_12FileDatabaseEb:
  183|     26|{
  184|     26|    const StreamReaderAny::pos old = db.reader->GetCurrentPos();
  185|     26|    Pointer ptrval;
  186|     26|    const Field* f;
  187|     26|    try {
  188|     26|        f = &(*this)[name];
  189|       |
  190|       |        // sanity check, should never happen if the genblenddna script is right
  191|     26|        if (!(f->flags & FieldFlag_Pointer)) {
  ------------------
  |  Branch (191:13): [True: 0, False: 26]
  ------------------
  192|      0|            throw Error("Field `",name,"` of structure `",
  193|      0|                this->name,"` ought to be a pointer");
  194|      0|        }
  195|       |
  196|     26|        db.reader->IncPtr(f->offset);
  197|     26|        Convert(ptrval,db);
  198|       |        // actually it is meaningless on which Structure the Convert is called
  199|       |        // because the `Pointer` argument triggers a special implementation.
  200|     26|    }
  201|     26|    catch (const Error& e) {
  202|      0|        _defaultInitializer<error_policy>()(out,e.what());
  203|       |
  204|      0|        out.reset();
  205|      0|        return false;
  206|      0|    }
  207|       |
  208|       |    // resolve the pointer and load the corresponding structure
  209|     26|    const bool res = ResolvePointer(out,ptrval,db,*f, non_recursive);
  210|       |
  211|     26|    if(!non_recursive) {
  ------------------
  |  Branch (211:8): [True: 26, False: 0]
  ------------------
  212|       |        // and recover the previous stream position
  213|     26|        db.reader->SetCurrentPos(old);
  214|     26|    }
  215|       |
  216|     26|#ifndef ASSIMP_BUILD_BLENDER_NO_STATS
  217|     26|    ++db.stats().fields_read;
  218|     26|#endif
  219|       |
  220|     26|    return res;
  221|     26|}
_ZNK6Assimp7Blender9Structure14ResolvePointerINSt3__110shared_ptrENS0_5WorldEEEbRT_IT0_ERKNS0_7PointerERKNS0_12FileDatabaseERKNS0_5FieldEb:
  412|     26|{
  413|     26|    out.reset(); // ensure null pointers work
  414|     26|    if (!ptrval.val) {
  ------------------
  |  Branch (414:9): [True: 0, False: 26]
  ------------------
  415|      0|        return false;
  416|      0|    }
  417|     26|    const Structure& s = db.dna[f.type];
  418|       |    // find the file block the pointer is pointing to
  419|     26|    const FileBlockHead* block = LocateFileBlockForAddress(ptrval,db);
  420|       |
  421|       |    // also determine the target type from the block header
  422|       |    // and check if it matches the type which we expect.
  423|     26|    const Structure& ss = db.dna[block->dna_index];
  424|     26|    if (ss != s) {
  ------------------
  |  Branch (424:9): [True: 0, False: 26]
  ------------------
  425|      0|        throw Error("Expected target to be of type `",s.name,
  426|      0|            "` but seemingly it is a `",ss.name,"` instead"
  427|      0|            );
  428|      0|    }
  429|       |
  430|       |    // try to retrieve the object from the cache
  431|     26|    db.cache(out).get(s,out,ptrval);
  432|     26|    if (out) {
  ------------------
  |  Branch (432:9): [True: 0, False: 26]
  ------------------
  433|      0|        return true;
  434|      0|    }
  435|       |
  436|       |    // seek to this location, but save the previous stream pointer.
  437|     26|    const StreamReaderAny::pos pold = db.reader->GetCurrentPos();
  438|     26|    db.reader->SetCurrentPos(block->start+ static_cast<size_t>((ptrval.val - block->address.val) ));
  439|       |    // FIXME: basically, this could cause problems with 64 bit pointers on 32 bit systems.
  440|       |    // I really ought to improve StreamReader to work with 64 bit indices exclusively.
  441|       |
  442|       |    // continue conversion after allocating the required storage
  443|     26|    size_t num = block->size / ss.size;
  444|     26|    T* o = _allocate(out,num);
  445|       |
  446|       |    // cache the object before we convert it to avoid cyclic recursion.
  447|     26|    db.cache(out).set(s,out,ptrval);
  448|       |
  449|       |    // if the non_recursive flag is set, we don't do anything but leave
  450|       |    // the cursor at the correct position to resolve the object.
  451|     26|    if (!non_recursive) {
  ------------------
  |  Branch (451:9): [True: 26, False: 0]
  ------------------
  452|     52|        for (size_t i = 0; i < num; ++i,++o) {
  ------------------
  |  Branch (452:28): [True: 26, False: 26]
  ------------------
  453|     26|            s.Convert(*o,db);
  454|     26|        }
  455|       |
  456|     26|        db.reader->SetCurrentPos(pold);
  457|     26|    }
  458|       |
  459|     26|#ifndef ASSIMP_BUILD_BLENDER_NO_STATS
  460|     26|    if(out) {
  ------------------
  |  Branch (460:8): [True: 26, False: 0]
  ------------------
  461|     26|        ++db.stats().pointers_resolved;
  462|     26|    }
  463|     26|#endif
  464|     26|    return false;
  465|     26|}
_ZNK6Assimp7Blender11ObjectCacheINSt3__110shared_ptrEE3getINS0_5WorldEEEvRKNS0_9StructureERNS3_IT_EERKNS0_7PointerE:
  807|     26|) const {
  808|       |
  809|     26|    if(s.cache_idx == static_cast<size_t>(-1)) {
  ------------------
  |  Branch (809:8): [True: 26, False: 0]
  ------------------
  810|     26|        s.cache_idx = db.next_cache_idx++;
  811|     26|        caches.resize(db.next_cache_idx);
  812|     26|        return;
  813|     26|    }
  814|       |
  815|      0|    typename StructureCache::const_iterator it = caches[s.cache_idx].find(ptr);
  816|      0|    if (it != caches[s.cache_idx].end()) {
  ------------------
  |  Branch (816:9): [True: 0, False: 0]
  ------------------
  817|      0|        out = std::static_pointer_cast<T>( (*it).second );
  818|       |
  819|      0|#ifndef ASSIMP_BUILD_BLENDER_NO_STATS
  820|      0|        ++db.stats().cache_hits;
  821|      0|#endif
  822|      0|    }
  823|       |    // otherwise, out remains untouched
  824|      0|}
_ZN6Assimp7Blender11ObjectCacheINSt3__110shared_ptrEE3setINS0_5WorldEEEvRKNS0_9StructureERKNS3_IT_EERKNS0_7PointerE:
  832|     26|) {
  833|     26|    if(s.cache_idx == static_cast<size_t>(-1)) {
  ------------------
  |  Branch (833:8): [True: 0, False: 26]
  ------------------
  834|      0|        s.cache_idx = db.next_cache_idx++;
  835|      0|        caches.resize(db.next_cache_idx);
  836|      0|    }
  837|     26|    caches[s.cache_idx][ptr] = std::static_pointer_cast<ElemBase>( out );
  838|       |
  839|     26|#ifndef ASSIMP_BUILD_BLENDER_NO_STATS
  840|     26|    ++db.stats().cached_objects;
  841|     26|#endif
  842|     26|}
_ZNK6Assimp7Blender9Structure14ReadFieldArrayILi1EcLm240EEEvRAT1__T0_PKcRKNS0_12FileDatabaseE:
  100|      8|{
  101|      8|    const StreamReaderAny::pos old = db.reader->GetCurrentPos();
  102|      8|    try {
  103|      8|        const Field& f = (*this)[name];
  104|      8|        const Structure& s = db.dna[f.type];
  105|       |
  106|       |        // is the input actually an array?
  107|      8|        if (!(f.flags & FieldFlag_Array)) {
  ------------------
  |  Branch (107:13): [True: 0, False: 8]
  ------------------
  108|      0|            throw Error("Field `",name,"` of structure `",this->name,"` ought to be an array of size ",M);
  109|      0|        }
  110|       |
  111|      8|        db.reader->IncPtr(f.offset);
  112|       |
  113|       |        // size conversions are always allowed, regardless of error_policy
  114|      8|        unsigned int i = 0;
  115|  1.92k|        for(; i < std::min(f.array_sizes[0],M); ++i) {
  ------------------
  |  Branch (115:15): [True: 1.92k, False: 8]
  ------------------
  116|  1.92k|            s.Convert(out[i],db);
  117|  1.92k|        }
  118|      8|        for(; i < M; ++i) {
  ------------------
  |  Branch (118:15): [True: 0, False: 8]
  ------------------
  119|      0|            _defaultInitializer<ErrorPolicy_Igno>()(out[i]);
  120|      0|        }
  121|      8|    }
  122|      8|    catch (const Error& e) {
  123|      0|        _defaultInitializer<error_policy>()(out,e.what());
  124|      0|    }
  125|       |
  126|       |    // and recover the previous stream position
  127|      8|    db.reader->SetCurrentPos(old);
  128|       |
  129|      8|#ifndef ASSIMP_BUILD_BLENDER_NO_STATS
  130|      8|    ++db.stats().fields_read;
  131|      8|#endif
  132|      8|}
_ZNK6Assimp7Blender9Structure12ReadFieldPtrILi1ENSt3__110shared_ptrENS0_10PackedFileEEEbRT0_IT1_EPKcRKNS0_12FileDatabaseEb:
  183|      8|{
  184|      8|    const StreamReaderAny::pos old = db.reader->GetCurrentPos();
  185|      8|    Pointer ptrval;
  186|      8|    const Field* f;
  187|      8|    try {
  188|      8|        f = &(*this)[name];
  189|       |
  190|       |        // sanity check, should never happen if the genblenddna script is right
  191|      8|        if (!(f->flags & FieldFlag_Pointer)) {
  ------------------
  |  Branch (191:13): [True: 0, False: 8]
  ------------------
  192|      0|            throw Error("Field `",name,"` of structure `",
  193|      0|                this->name,"` ought to be a pointer");
  194|      0|        }
  195|       |
  196|      8|        db.reader->IncPtr(f->offset);
  197|      8|        Convert(ptrval,db);
  198|       |        // actually it is meaningless on which Structure the Convert is called
  199|       |        // because the `Pointer` argument triggers a special implementation.
  200|      8|    }
  201|      8|    catch (const Error& e) {
  202|      0|        _defaultInitializer<error_policy>()(out,e.what());
  203|       |
  204|      0|        out.reset();
  205|      0|        return false;
  206|      0|    }
  207|       |
  208|       |    // resolve the pointer and load the corresponding structure
  209|      8|    const bool res = ResolvePointer(out,ptrval,db,*f, non_recursive);
  210|       |
  211|      8|    if(!non_recursive) {
  ------------------
  |  Branch (211:8): [True: 8, False: 0]
  ------------------
  212|       |        // and recover the previous stream position
  213|      8|        db.reader->SetCurrentPos(old);
  214|      8|    }
  215|       |
  216|      8|#ifndef ASSIMP_BUILD_BLENDER_NO_STATS
  217|      8|    ++db.stats().fields_read;
  218|      8|#endif
  219|       |
  220|      8|    return res;
  221|      8|}
_ZNK6Assimp7Blender9Structure14ResolvePointerINSt3__110shared_ptrENS0_10PackedFileEEEbRT_IT0_ERKNS0_7PointerERKNS0_12FileDatabaseERKNS0_5FieldEb:
  412|      8|{
  413|      8|    out.reset(); // ensure null pointers work
  414|      8|    if (!ptrval.val) {
  ------------------
  |  Branch (414:9): [True: 7, False: 1]
  ------------------
  415|      7|        return false;
  416|      7|    }
  417|      1|    const Structure& s = db.dna[f.type];
  418|       |    // find the file block the pointer is pointing to
  419|      1|    const FileBlockHead* block = LocateFileBlockForAddress(ptrval,db);
  420|       |
  421|       |    // also determine the target type from the block header
  422|       |    // and check if it matches the type which we expect.
  423|      1|    const Structure& ss = db.dna[block->dna_index];
  424|      1|    if (ss != s) {
  ------------------
  |  Branch (424:9): [True: 0, False: 1]
  ------------------
  425|      0|        throw Error("Expected target to be of type `",s.name,
  426|      0|            "` but seemingly it is a `",ss.name,"` instead"
  427|      0|            );
  428|      0|    }
  429|       |
  430|       |    // try to retrieve the object from the cache
  431|      1|    db.cache(out).get(s,out,ptrval);
  432|      1|    if (out) {
  ------------------
  |  Branch (432:9): [True: 0, False: 1]
  ------------------
  433|      0|        return true;
  434|      0|    }
  435|       |
  436|       |    // seek to this location, but save the previous stream pointer.
  437|      1|    const StreamReaderAny::pos pold = db.reader->GetCurrentPos();
  438|      1|    db.reader->SetCurrentPos(block->start+ static_cast<size_t>((ptrval.val - block->address.val) ));
  439|       |    // FIXME: basically, this could cause problems with 64 bit pointers on 32 bit systems.
  440|       |    // I really ought to improve StreamReader to work with 64 bit indices exclusively.
  441|       |
  442|       |    // continue conversion after allocating the required storage
  443|      1|    size_t num = block->size / ss.size;
  444|      1|    T* o = _allocate(out,num);
  445|       |
  446|       |    // cache the object before we convert it to avoid cyclic recursion.
  447|      1|    db.cache(out).set(s,out,ptrval);
  448|       |
  449|       |    // if the non_recursive flag is set, we don't do anything but leave
  450|       |    // the cursor at the correct position to resolve the object.
  451|      1|    if (!non_recursive) {
  ------------------
  |  Branch (451:9): [True: 1, False: 0]
  ------------------
  452|      2|        for (size_t i = 0; i < num; ++i,++o) {
  ------------------
  |  Branch (452:28): [True: 1, False: 1]
  ------------------
  453|      1|            s.Convert(*o,db);
  454|      1|        }
  455|       |
  456|      1|        db.reader->SetCurrentPos(pold);
  457|      1|    }
  458|       |
  459|      1|#ifndef ASSIMP_BUILD_BLENDER_NO_STATS
  460|      1|    if(out) {
  ------------------
  |  Branch (460:8): [True: 1, False: 0]
  ------------------
  461|      1|        ++db.stats().pointers_resolved;
  462|      1|    }
  463|      1|#endif
  464|      1|    return false;
  465|      1|}
_ZNK6Assimp7Blender11ObjectCacheINSt3__110shared_ptrEE3getINS0_10PackedFileEEEvRKNS0_9StructureERNS3_IT_EERKNS0_7PointerE:
  807|      1|) const {
  808|       |
  809|      1|    if(s.cache_idx == static_cast<size_t>(-1)) {
  ------------------
  |  Branch (809:8): [True: 1, False: 0]
  ------------------
  810|      1|        s.cache_idx = db.next_cache_idx++;
  811|      1|        caches.resize(db.next_cache_idx);
  812|      1|        return;
  813|      1|    }
  814|       |
  815|      0|    typename StructureCache::const_iterator it = caches[s.cache_idx].find(ptr);
  816|      0|    if (it != caches[s.cache_idx].end()) {
  ------------------
  |  Branch (816:9): [True: 0, False: 0]
  ------------------
  817|      0|        out = std::static_pointer_cast<T>( (*it).second );
  818|       |
  819|      0|#ifndef ASSIMP_BUILD_BLENDER_NO_STATS
  820|      0|        ++db.stats().cache_hits;
  821|      0|#endif
  822|      0|    }
  823|       |    // otherwise, out remains untouched
  824|      0|}
_ZN6Assimp7Blender11ObjectCacheINSt3__110shared_ptrEE3setINS0_10PackedFileEEEvRKNS0_9StructureERKNS3_IT_EERKNS0_7PointerE:
  832|      1|) {
  833|      1|    if(s.cache_idx == static_cast<size_t>(-1)) {
  ------------------
  |  Branch (833:8): [True: 0, False: 1]
  ------------------
  834|      0|        s.cache_idx = db.next_cache_idx++;
  835|      0|        caches.resize(db.next_cache_idx);
  836|      0|    }
  837|      1|    caches[s.cache_idx][ptr] = std::static_pointer_cast<ElemBase>( out );
  838|       |
  839|      1|#ifndef ASSIMP_BUILD_BLENDER_NO_STATS
  840|      1|    ++db.stats().cached_objects;
  841|      1|#endif
  842|      1|}
_ZNK6Assimp7Blender9Structure14ReadFieldArrayILi1EiLm42EEEvRAT1__T0_PKcRKNS0_12FileDatabaseE:
  100|    148|{
  101|    148|    const StreamReaderAny::pos old = db.reader->GetCurrentPos();
  102|    148|    try {
  103|    148|        const Field& f = (*this)[name];
  104|    148|        const Structure& s = db.dna[f.type];
  105|       |
  106|       |        // is the input actually an array?
  107|    148|        if (!(f.flags & FieldFlag_Array)) {
  ------------------
  |  Branch (107:13): [True: 0, False: 148]
  ------------------
  108|      0|            throw Error("Field `",name,"` of structure `",this->name,"` ought to be an array of size ",M);
  109|      0|        }
  110|       |
  111|    148|        db.reader->IncPtr(f.offset);
  112|       |
  113|       |        // size conversions are always allowed, regardless of error_policy
  114|    148|        unsigned int i = 0;
  115|  2.48k|        for(; i < std::min(f.array_sizes[0],M); ++i) {
  ------------------
  |  Branch (115:15): [True: 2.34k, False: 148]
  ------------------
  116|  2.34k|            s.Convert(out[i],db);
  117|  2.34k|        }
  118|    243|        for(; i < M; ++i) {
  ------------------
  |  Branch (118:15): [True: 95, False: 148]
  ------------------
  119|     95|            _defaultInitializer<ErrorPolicy_Igno>()(out[i]);
  120|     95|        }
  121|    148|    }
  122|    148|    catch (const Error& e) {
  123|     90|        _defaultInitializer<error_policy>()(out,e.what());
  124|     90|    }
  125|       |
  126|       |    // and recover the previous stream position
  127|    148|    db.reader->SetCurrentPos(old);
  128|       |
  129|    148|#ifndef ASSIMP_BUILD_BLENDER_NO_STATS
  130|    148|    ++db.stats().fields_read;
  131|    148|#endif
  132|    148|}
_ZNK6Assimp7Blender9Structure18ReadFieldPtrVectorILi1ENSt3__110shared_ptrENS0_15CustomDataLayerEEEbRNS0_6vectorIT0_IT1_EEEPKcRKNS0_12FileDatabaseE:
  354|    148|bool Structure::ReadFieldPtrVector(vector<TOUT<T>>&out, const char* name, const FileDatabase& db) const {
  355|    148|	out.clear();
  356|       |
  357|    148|	const StreamReaderAny::pos old = db.reader->GetCurrentPos();
  358|       |
  359|    148|	Pointer ptrval;
  360|    148|	const Field* f;
  361|    148|	try	{
  362|    148|		f = &(*this)[name];
  363|       |
  364|       |		// sanity check, should never happen if the genblenddna script is right
  365|    148|		if (!(f->flags & FieldFlag_Pointer)) {
  ------------------
  |  Branch (365:7): [True: 0, False: 148]
  ------------------
  366|      0|			throw Error("Field `", name, "` of structure `",
  367|      0|				this->name, "` ought to be a pointer");
  368|      0|		}
  369|       |
  370|    148|		db.reader->IncPtr(f->offset);
  371|    148|		Convert(ptrval, db);
  372|       |		// actually it is meaningless on which Structure the Convert is called
  373|       |		// because the `Pointer` argument triggers a special implementation.
  374|    148|	}
  375|    148|	catch (const Error& e) {
  376|      0|		_defaultInitializer<error_policy>()(out, e.what());
  377|      0|		out.clear();
  378|      0|		return false;
  379|      0|	}
  380|       |
  381|       |
  382|    148|	if (ptrval.val)	{
  ------------------
  |  Branch (382:6): [True: 137, False: 11]
  ------------------
  383|       |		// find the file block the pointer is pointing to
  384|    137|		const FileBlockHead* block = LocateFileBlockForAddress(ptrval, db);
  385|    137|		db.reader->SetCurrentPos(block->start + static_cast<size_t>((ptrval.val - block->address.val)));
  386|       |		// FIXME: basically, this could cause problems with 64 bit pointers on 32 bit systems.
  387|       |		// I really ought to improve StreamReader to work with 64 bit indices exclusively.
  388|       |
  389|    137|		const Structure& s = db.dna[f->type];
  390|    732|		for (size_t i = 0; i < block->num; ++i)	{
  ------------------
  |  Branch (390:22): [True: 595, False: 137]
  ------------------
  391|    595|			TOUT<T> p(new T);
  392|    595|			s.Convert(*p, db);
  393|    595|			out.push_back(p);
  394|    595|		}
  395|    137|	}
  396|       |
  397|    148|	db.reader->SetCurrentPos(old);
  398|       |
  399|    148|#ifndef ASSIMP_BUILD_BLENDER_NO_STATS
  400|    148|	++db.stats().fields_read;
  401|    148|#endif
  402|       |
  403|    148|	return true;
  404|    148|}
_ZNK6Assimp7Blender9Structure14ReadFieldArrayILi1EcLm64EEEvRAT1__T0_PKcRKNS0_12FileDatabaseE:
  100|    595|{
  101|    595|    const StreamReaderAny::pos old = db.reader->GetCurrentPos();
  102|    595|    try {
  103|    595|        const Field& f = (*this)[name];
  104|    595|        const Structure& s = db.dna[f.type];
  105|       |
  106|       |        // is the input actually an array?
  107|    595|        if (!(f.flags & FieldFlag_Array)) {
  ------------------
  |  Branch (107:13): [True: 0, False: 595]
  ------------------
  108|      0|            throw Error("Field `",name,"` of structure `",this->name,"` ought to be an array of size ",M);
  109|      0|        }
  110|       |
  111|    595|        db.reader->IncPtr(f.offset);
  112|       |
  113|       |        // size conversions are always allowed, regardless of error_policy
  114|    595|        unsigned int i = 0;
  115|  24.2k|        for(; i < std::min(f.array_sizes[0],M); ++i) {
  ------------------
  |  Branch (115:15): [True: 23.6k, False: 595]
  ------------------
  116|  23.6k|            s.Convert(out[i],db);
  117|  23.6k|        }
  118|  14.9k|        for(; i < M; ++i) {
  ------------------
  |  Branch (118:15): [True: 14.4k, False: 595]
  ------------------
  119|  14.4k|            _defaultInitializer<ErrorPolicy_Igno>()(out[i]);
  120|  14.4k|        }
  121|    595|    }
  122|    595|    catch (const Error& e) {
  123|      0|        _defaultInitializer<error_policy>()(out,e.what());
  124|      0|    }
  125|       |
  126|       |    // and recover the previous stream position
  127|    595|    db.reader->SetCurrentPos(old);
  128|       |
  129|    595|#ifndef ASSIMP_BUILD_BLENDER_NO_STATS
  130|    595|    ++db.stats().fields_read;
  131|    595|#endif
  132|    595|}
_ZNK6Assimp7Blender9Structure17ReadCustomDataPtrILi2EEEbRNSt3__110shared_ptrINS0_8ElemBaseEEEiPKcRKNS0_12FileDatabaseE:
  308|    595|bool Structure::ReadCustomDataPtr(std::shared_ptr<ElemBase>&out, int cdtype, const char* name, const FileDatabase& db) const {
  309|       |
  310|    595|	const StreamReaderAny::pos old = db.reader->GetCurrentPos();
  311|       |
  312|    595|	Pointer ptrval;
  313|    595|	const Field* f;
  314|    595|	try	{
  315|    595|		f = &(*this)[name];
  316|       |
  317|       |		// sanity check, should never happen if the genblenddna script is right
  318|    595|		if (!(f->flags & FieldFlag_Pointer)) {
  ------------------
  |  Branch (318:7): [True: 0, False: 595]
  ------------------
  319|      0|			throw Error("Field `", name, "` of structure `",
  320|      0|				this->name, "` ought to be a pointer");
  321|      0|		}
  322|       |
  323|    595|		db.reader->IncPtr(f->offset);
  324|    595|		Convert(ptrval, db);
  325|       |		// actually it is meaningless on which Structure the Convert is called
  326|       |		// because the `Pointer` argument triggers a special implementation.
  327|    595|	}
  328|    595|	catch (const Error& e) {
  329|      0|		_defaultInitializer<error_policy>()(out, e.what());
  330|      0|		out.reset();
  331|      0|	}
  332|       |
  333|    595|	bool readOk = true;
  334|    595|	if (ptrval.val)	{
  ------------------
  |  Branch (334:6): [True: 152, False: 443]
  ------------------
  335|       |		// get block for ptr
  336|    152|		const FileBlockHead* block = LocateFileBlockForAddress(ptrval, db);
  337|    152|		db.reader->SetCurrentPos(block->start + static_cast<size_t>((ptrval.val - block->address.val)));
  338|       |		// read block->num instances of given type to out
  339|    152|		readOk = readCustomData(out, cdtype, block->num, db);
  340|    152|	}
  341|       |
  342|       |	// and recover the previous stream position
  343|    595|	db.reader->SetCurrentPos(old);
  344|       |
  345|    595|#ifndef ASSIMP_BUILD_BLENDER_NO_STATS
  346|    595|	++db.stats().fields_read;
  347|    595|#endif
  348|       |
  349|    595|	return readOk;
  350|    595|}
_ZNK6Assimp7Blender9Structure8AllocateINS0_19SubsurfModifierDataEEENSt3__110shared_ptrINS0_8ElemBaseEEEv:
   85|      4|{
   86|      4|    return std::shared_ptr<T>(new T());
   87|      4|}
_ZNK6Assimp7Blender9Structure7ConvertINS0_19SubsurfModifierDataEEEvNSt3__110shared_ptrINS0_8ElemBaseEEERKNS0_12FileDatabaseE:
   93|      4|{
   94|      4|    Convert<T> (*static_cast<T*> ( in.get() ),db);
   95|      4|}
_ZNK6Assimp7Blender9Structure8AllocateINS0_4LampEEENSt3__110shared_ptrINS0_8ElemBaseEEEv:
   85|     31|{
   86|     31|    return std::shared_ptr<T>(new T());
   87|     31|}
_ZNK6Assimp7Blender9Structure7ConvertINS0_4LampEEEvNSt3__110shared_ptrINS0_8ElemBaseEEERKNS0_12FileDatabaseE:
   93|     31|{
   94|     31|    Convert<T> (*static_cast<T*> ( in.get() ),db);
   95|     31|}
_ZNK6Assimp7Blender9Structure8AllocateINS0_4BaseEEENSt3__110shared_ptrINS0_8ElemBaseEEEv:
   85|      8|{
   86|      8|    return std::shared_ptr<T>(new T());
   87|      8|}
_ZNK6Assimp7Blender9Structure7ConvertINS0_4BaseEEEvNSt3__110shared_ptrINS0_8ElemBaseEEERKNS0_12FileDatabaseE:
   93|      8|{
   94|      8|    Convert<T> (*static_cast<T*> ( in.get() ),db);
   95|      8|}
_ZNK6Assimp7Blender9Structure8AllocateINS0_4MeshEEENSt3__110shared_ptrINS0_8ElemBaseEEEv:
   85|     42|{
   86|     42|    return std::shared_ptr<T>(new T());
   87|     42|}
_ZNK6Assimp7Blender9Structure7ConvertINS0_4MeshEEEvNSt3__110shared_ptrINS0_8ElemBaseEEERKNS0_12FileDatabaseE:
   93|     42|{
   94|     42|    Convert<T> (*static_cast<T*> ( in.get() ),db);
   95|     42|}
_ZNK6Assimp7Blender9Structure8AllocateINS0_6CameraEEENSt3__110shared_ptrINS0_8ElemBaseEEEv:
   85|     27|{
   86|     27|    return std::shared_ptr<T>(new T());
   87|     27|}
_ZNK6Assimp7Blender9Structure7ConvertINS0_6CameraEEEvNSt3__110shared_ptrINS0_8ElemBaseEEERKNS0_12FileDatabaseE:
   93|     27|{
   94|     27|    Convert<T> (*static_cast<T*> ( in.get() ),db);
   95|     27|}
_ZNK6Assimp7Blender9Structure8AllocateINS0_18MirrorModifierDataEEENSt3__110shared_ptrINS0_8ElemBaseEEEv:
   85|      2|{
   86|      2|    return std::shared_ptr<T>(new T());
   87|      2|}
_ZNK6Assimp7Blender9Structure7ConvertINS0_18MirrorModifierDataEEEvNSt3__110shared_ptrINS0_8ElemBaseEEERKNS0_12FileDatabaseE:
   93|      2|{
   94|      2|    Convert<T> (*static_cast<T*> ( in.get() ),db);
   95|      2|}
_ZNK6Assimp7Blender9Structure8AllocateINS0_15CollectionChildEEENSt3__110shared_ptrINS0_8ElemBaseEEEv:
   85|      1|{
   86|      1|    return std::shared_ptr<T>(new T());
   87|      1|}
_ZNK6Assimp7Blender9Structure7ConvertINS0_15CollectionChildEEEvNSt3__110shared_ptrINS0_8ElemBaseEEERKNS0_12FileDatabaseE:
   93|      1|{
   94|      1|    Convert<T> (*static_cast<T*> ( in.get() ),db);
   95|      1|}
_ZNK6Assimp7Blender9Structure8AllocateINS0_16CollectionObjectEEENSt3__110shared_ptrINS0_8ElemBaseEEEv:
   85|      1|{
   86|      1|    return std::shared_ptr<T>(new T());
   87|      1|}
_ZNK6Assimp7Blender9Structure7ConvertINS0_16CollectionObjectEEEvNSt3__110shared_ptrINS0_8ElemBaseEEERKNS0_12FileDatabaseE:
   93|      1|{
   94|      1|    Convert<T> (*static_cast<T*> ( in.get() ),db);
   95|      1|}

_ZN6Assimp7Blender9TempArrayINSt3__16vectorENS0_15BlenderModifierEEC2Ev:
   67|    624|        TempArray() = default;
_ZN6Assimp7Blender9TempArrayINSt3__16vectorENS0_15BlenderModifierEED2Ev:
   69|    624|        ~TempArray () {
   70|    624|            for(T* elem : arr) {
  ------------------
  |  Branch (70:25): [True: 9, False: 624]
  ------------------
   71|      9|                delete elem;
   72|      9|            }
   73|    624|        }
_ZN6Assimp7Blender14ConversionDataC2ERKNS0_12FileDatabaseE:
  143|     25|            , db(db)
  144|     25|        {}
_ZN6Assimp7Blender9TempArrayINSt3__16vectorE6aiMeshEC2Ev:
   67|     25|        TempArray() = default;
_ZN6Assimp7Blender9TempArrayINSt3__16vectorE8aiCameraEC2Ev:
   67|     25|        TempArray() = default;
_ZN6Assimp7Blender9TempArrayINSt3__16vectorE7aiLightEC2Ev:
   67|     25|        TempArray() = default;
_ZN6Assimp7Blender9TempArrayINSt3__16vectorE10aiMaterialEC2Ev:
   67|     25|        TempArray() = default;
_ZN6Assimp7Blender9TempArrayINSt3__16vectorE9aiTextureEC2Ev:
   67|     25|        TempArray() = default;
_ZN6Assimp7Blender9TempArrayINSt3__16vectorE9aiTextureED2Ev:
   69|     25|        ~TempArray () {
   70|     25|            for(T* elem : arr) {
  ------------------
  |  Branch (70:25): [True: 0, False: 25]
  ------------------
   71|      0|                delete elem;
   72|      0|            }
   73|     25|        }
_ZN6Assimp7Blender9TempArrayINSt3__16vectorE10aiMaterialED2Ev:
   69|     25|        ~TempArray () {
   70|     25|            for(T* elem : arr) {
  ------------------
  |  Branch (70:25): [True: 0, False: 25]
  ------------------
   71|      0|                delete elem;
   72|      0|            }
   73|     25|        }
_ZN6Assimp7Blender9TempArrayINSt3__16vectorE7aiLightED2Ev:
   69|     25|        ~TempArray () {
   70|     25|            for(T* elem : arr) {
  ------------------
  |  Branch (70:25): [True: 0, False: 25]
  ------------------
   71|      0|                delete elem;
   72|      0|            }
   73|     25|        }
_ZN6Assimp7Blender9TempArrayINSt3__16vectorE8aiCameraED2Ev:
   69|     25|        ~TempArray () {
   70|     25|            for(T* elem : arr) {
  ------------------
  |  Branch (70:25): [True: 0, False: 25]
  ------------------
   71|      0|                delete elem;
   72|      0|            }
   73|     25|        }
_ZN6Assimp7Blender9TempArrayINSt3__16vectorE6aiMeshED2Ev:
   69|     25|        ~TempArray () {
   70|     25|            for(T* elem : arr) {
  ------------------
  |  Branch (70:25): [True: 0, False: 25]
  ------------------
   71|      0|                delete elem;
   72|      0|            }
   73|     25|        }
_ZN6Assimp7Blender27GetTextureTypeDisplayStringENS0_3Tex4TypeE:
  180|      1|{
  181|      1|    switch (t)  {
  182|      0|    case Tex::Type_CLOUDS       :  return  "Clouds";
  ------------------
  |  Branch (182:5): [True: 0, False: 1]
  ------------------
  183|      0|    case Tex::Type_WOOD         :  return  "Wood";
  ------------------
  |  Branch (183:5): [True: 0, False: 1]
  ------------------
  184|      0|    case Tex::Type_MARBLE       :  return  "Marble";
  ------------------
  |  Branch (184:5): [True: 0, False: 1]
  ------------------
  185|      0|    case Tex::Type_MAGIC        :  return  "Magic";
  ------------------
  |  Branch (185:5): [True: 0, False: 1]
  ------------------
  186|      0|    case Tex::Type_BLEND        :  return  "Blend";
  ------------------
  |  Branch (186:5): [True: 0, False: 1]
  ------------------
  187|      0|    case Tex::Type_STUCCI       :  return  "Stucci";
  ------------------
  |  Branch (187:5): [True: 0, False: 1]
  ------------------
  188|      0|    case Tex::Type_NOISE        :  return  "Noise";
  ------------------
  |  Branch (188:5): [True: 0, False: 1]
  ------------------
  189|      0|    case Tex::Type_PLUGIN       :  return  "Plugin";
  ------------------
  |  Branch (189:5): [True: 0, False: 1]
  ------------------
  190|      0|    case Tex::Type_MUSGRAVE     :  return  "Musgrave";
  ------------------
  |  Branch (190:5): [True: 0, False: 1]
  ------------------
  191|      1|    case Tex::Type_VORONOI      :  return  "Voronoi";
  ------------------
  |  Branch (191:5): [True: 1, False: 0]
  ------------------
  192|      0|    case Tex::Type_DISTNOISE    :  return  "DistortedNoise";
  ------------------
  |  Branch (192:5): [True: 0, False: 1]
  ------------------
  193|      0|    case Tex::Type_ENVMAP       :  return  "EnvMap";
  ------------------
  |  Branch (193:5): [True: 0, False: 1]
  ------------------
  194|      0|    case Tex::Type_IMAGE        :  return  "Image";
  ------------------
  |  Branch (194:5): [True: 0, False: 1]
  ------------------
  195|      0|    default:
  ------------------
  |  Branch (195:5): [True: 0, False: 1]
  ------------------
  196|      0|        break;
  197|      1|    }
  198|      0|    return "<Unknown>";
  199|      1|}
_ZNK6Assimp7Blender13ObjectCompareclEPKNS0_6ObjectES4_:
  126|     69|        bool operator() (const Object* left, const Object* right) const {
  127|     69|            return ::strncmp(left->id.name, right->id.name, strlen( left->id.name ) ) < 0;
  128|     69|        }
_ZN6Assimp7Blender9TempArrayINSt3__16vectorE6aiMeshEptEv:
   79|    491|        mywrap* operator -> () {
   80|    491|            return &arr;
   81|    491|        }
_ZN6Assimp7Blender9TempArrayINSt3__16vectorE6aiMeshE7dismissEv:
   75|     25|        void dismiss() {
   76|     25|            arr.clear();
   77|     25|        }
_ZN6Assimp7Blender9TempArrayINSt3__16vectorE7aiLightEptEv:
   79|    131|        mywrap* operator -> () {
   80|    131|            return &arr;
   81|    131|        }
_ZN6Assimp7Blender9TempArrayINSt3__16vectorE7aiLightE7dismissEv:
   75|     25|        void dismiss() {
   76|     25|            arr.clear();
   77|     25|        }
_ZN6Assimp7Blender9TempArrayINSt3__16vectorE8aiCameraEptEv:
   79|    126|        mywrap* operator -> () {
   80|    126|            return &arr;
   81|    126|        }
_ZN6Assimp7Blender9TempArrayINSt3__16vectorE8aiCameraE7dismissEv:
   75|     25|        void dismiss() {
   76|     25|            arr.clear();
   77|     25|        }
_ZN6Assimp7Blender9TempArrayINSt3__16vectorE10aiMaterialEptEv:
   79|    156|        mywrap* operator -> () {
   80|    156|            return &arr;
   81|    156|        }
_ZN6Assimp7Blender9TempArrayINSt3__16vectorE10aiMaterialE7dismissEv:
   75|     25|        void dismiss() {
   76|     25|            arr.clear();
   77|     25|        }
_ZN6Assimp7Blender9TempArrayINSt3__16vectorE9aiTextureEptEv:
   79|     31|        mywrap* operator -> () {
   80|     31|            return &arr;
   81|     31|        }
_ZN6Assimp7Blender9TempArrayINSt3__16vectorE9aiTextureE7dismissEv:
   75|      1|        void dismiss() {
   76|      1|            arr.clear();
   77|      1|        }
_ZN6Assimp7Blender9TempArrayINSt3__16vectorE6aiMeshE3getEv:
   91|     25|        mywrap& get () {
   92|     25|            return arr;
   93|     25|        }
_ZN6Assimp7Blender9TempArrayINSt3__16vectorE6aiMeshEixEm:
  103|  8.24k|        T*& operator[] (size_t idx) {
  104|  8.24k|            return arr[idx];
  105|  8.24k|        }
_ZN6Assimp7Blender9TempArrayINSt3__16vectorENS0_15BlenderModifierEEptEv:
   79|     30|        mywrap* operator -> () {
   80|     30|            return &arr;
   81|     30|        }

_ZN6Assimp15BlenderImporterC2Ev:
  101|    624|        modifier_cache(new BlenderModifierShowcase()) {
  102|       |    // empty
  103|    624|}
_ZN6Assimp15BlenderImporterD2Ev:
  107|    624|BlenderImporter::~BlenderImporter() {
  108|    624|    delete modifier_cache;
  109|    624|}
_ZNK6Assimp15BlenderImporter7CanReadERKNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEPNS_8IOSystemEb:
  115|     99|bool BlenderImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool /*checkSig*/) const {
  116|     99|    return ParseMagicToken(pFile, pIOHandler).error.empty();
  117|     99|}
_ZNK6Assimp15BlenderImporter7GetInfoEv:
  121|    666|const aiImporterDesc *BlenderImporter::GetInfo() const {
  122|    666|    return &blenderDesc;
  123|    666|}
_ZN6Assimp15BlenderImporter15SetupPropertiesEPKNS_8ImporterE:
  127|     32|void BlenderImporter::SetupProperties(const Importer * /*pImp*/) {
  128|       |    // nothing to be done for the moment
  129|     32|}
_ZN6Assimp15BlenderImporter14InternReadFileERKNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEP7aiScenePNS_8IOSystemE:
  134|     32|        aiScene *pScene, IOSystem *pIOHandler) {
  135|     32|    FileDatabase file;
  136|     32|    StreamOrError streamOrError = ParseMagicToken(pFile, pIOHandler);
  137|     32|    if (!streamOrError.error.empty()) {
  ------------------
  |  Branch (137:9): [True: 0, False: 32]
  ------------------
  138|      0|        ThrowException(streamOrError.error);
  139|      0|    }
  140|     32|    std::shared_ptr<IOStream> stream = std::move(streamOrError.stream);
  141|       |
  142|     32|    char version[4] = { 0 };
  143|     32|    file.i64bit = (stream->Read(version, 1, 1), version[0] == '-');
  144|     32|    file.little = (stream->Read(version, 1, 1), version[0] == 'v');
  145|       |
  146|     32|    stream->Read(version, 3, 1);
  147|     32|    version[3] = '\0';
  148|       |
  149|     32|    LogInfo("Blender version is ", version[0], ".", version + 1,
  150|     32|            " (64bit: ", file.i64bit ? "true" : "false",
  ------------------
  |  Branch (150:26): [True: 15, False: 17]
  ------------------
  151|     32|            ", little endian: ", file.little ? "true" : "false", ")");
  ------------------
  |  Branch (151:34): [True: 31, False: 1]
  ------------------
  152|       |
  153|     32|    ParseBlendFile(file, std::move(stream));
  154|       |
  155|     32|    Scene scene;
  156|     32|    ExtractScene(scene, file);
  157|       |
  158|     32|    ConvertBlendFile(pScene, scene, file);
  159|     32|}
_ZN6Assimp15BlenderImporter14ParseBlendFileERNS_7Blender12FileDatabaseENSt3__110shared_ptrINS_8IOStreamEEE:
  162|     32|void BlenderImporter::ParseBlendFile(FileDatabase &out, std::shared_ptr<IOStream> stream) {
  163|     32|    out.reader = std::make_shared<StreamReaderAny>(stream, out.little);
  164|       |
  165|     32|    DNAParser dna_reader(out);
  166|     32|    const DNA *dna = nullptr;
  167|       |
  168|     32|    out.entries.reserve(128);
  169|     32|    { // even small BLEND files tend to consist of many file blocks
  170|     32|        SectionParser parser(*out.reader, out.i64bit);
  171|       |
  172|       |        // first parse the file in search for the DNA and insert all other sections into the database
  173|  21.5k|        while ((parser.Next(), 1)) {
  ------------------
  |  Branch (173:16): [True: 21.5k, False: 6]
  ------------------
  174|  21.5k|            const FileBlockHead &head = parser.GetCurrent();
  175|       |
  176|  21.5k|            if (head.id == "ENDB") {
  ------------------
  |  Branch (176:17): [True: 26, False: 21.5k]
  ------------------
  177|     26|                break; // only valid end of the file
  178|  21.5k|            } else if (head.id == "DNA1") {
  ------------------
  |  Branch (178:24): [True: 28, False: 21.4k]
  ------------------
  179|     28|                dna_reader.Parse();
  180|     28|                dna = &dna_reader.GetDNA();
  181|     28|                continue;
  182|     28|            }
  183|       |
  184|  21.4k|            out.entries.push_back(head);
  185|  21.4k|        }
  186|     32|    }
  187|     32|    if (!dna) {
  ------------------
  |  Branch (187:9): [True: 0, False: 32]
  ------------------
  188|      0|        ThrowException("SDNA not found");
  189|      0|    }
  190|       |
  191|     32|    std::sort(out.entries.begin(), out.entries.end());
  192|     32|}
_ZN6Assimp15BlenderImporter12ExtractSceneERNS_7Blender5SceneERKNS1_12FileDatabaseE:
  195|     26|void BlenderImporter::ExtractScene(Scene &out, const FileDatabase &file) {
  196|     26|    const FileBlockHead *block = nullptr;
  197|     26|    std::map<std::string, size_t>::const_iterator it = file.dna.indices.find("Scene");
  198|     26|    if (it == file.dna.indices.end()) {
  ------------------
  |  Branch (198:9): [True: 0, False: 26]
  ------------------
  199|      0|        ThrowException("There is no `Scene` structure record");
  200|      0|    }
  201|       |
  202|     26|    const Structure &ss = file.dna.structures[(*it).second];
  203|       |
  204|       |    // we need a scene somewhere to start with.
  205|  13.0k|    for (const FileBlockHead &bl : file.entries) {
  ------------------
  |  Branch (205:34): [True: 13.0k, False: 0]
  ------------------
  206|       |
  207|       |        // Fix: using the DNA index is more reliable to locate scenes
  208|       |        //if (bl.id == "SC") {
  209|       |
  210|  13.0k|        if (bl.dna_index == (*it).second) {
  ------------------
  |  Branch (210:13): [True: 26, False: 13.0k]
  ------------------
  211|     26|            block = &bl;
  212|     26|            break;
  213|     26|        }
  214|  13.0k|    }
  215|       |
  216|     26|    if (!block) {
  ------------------
  |  Branch (216:9): [True: 0, False: 26]
  ------------------
  217|      0|        ThrowException("There is not a single `Scene` record to load");
  218|      0|    }
  219|       |
  220|     26|    file.reader->SetCurrentPos(block->start);
  221|     26|    ss.Convert(out, file);
  222|       |
  223|     26|#ifndef ASSIMP_BUILD_BLENDER_NO_STATS
  224|       |    ASSIMP_LOG_INFO(
  225|     26|            "(Stats) Fields read: ", file.stats().fields_read,
  226|     26|            ", pointers resolved: ", file.stats().pointers_resolved,
  227|     26|            ", cache hits: ", file.stats().cache_hits,
  228|     26|            ", cached objects: ", file.stats().cached_objects);
  229|     26|#endif
  230|     26|}
_ZN6Assimp15BlenderImporter18ParseSubCollectionERKNS_7Blender5SceneEP6aiNodeRKNSt3__110shared_ptrINS1_10CollectionEEERNS1_14ConversionDataE:
  233|      2|void BlenderImporter::ParseSubCollection(const Blender::Scene &in, aiNode *root, const std::shared_ptr<Collection>& collection, ConversionData &conv_data) {
  234|       |
  235|      2|    std::deque<Object *> root_objects;
  236|       |    // Count number of objects
  237|      5|    for (std::shared_ptr<CollectionObject> cur = std::static_pointer_cast<CollectionObject>(collection->gobject.first); cur; cur = cur->next) {
  ------------------
  |  Branch (237:121): [True: 3, False: 2]
  ------------------
  238|      3|        if (cur->ob) {
  ------------------
  |  Branch (238:13): [True: 3, False: 0]
  ------------------
  239|      3|            root_objects.push_back(cur->ob);
  240|      3|        }
  241|      3|    }
  242|      2|    std::deque<Collection *> root_children;
  243|       |    // Count number of child nodes
  244|      3|    for (std::shared_ptr<CollectionChild> cur = std::static_pointer_cast<CollectionChild>(collection->children.first); cur; cur = cur->next) {
  ------------------
  |  Branch (244:120): [True: 1, False: 2]
  ------------------
  245|      1|        if (cur->collection) {
  ------------------
  |  Branch (245:13): [True: 1, False: 0]
  ------------------
  246|      1|            root_children.push_back(cur->collection.get());
  247|      1|        }
  248|      1|    }
  249|      2|    root->mNumChildren = static_cast<unsigned int>(root_objects.size() + root_children.size());
  250|      2|    root->mChildren = new aiNode *[root->mNumChildren]();
  251|       |
  252|      5|    for (unsigned int i = 0; i < static_cast<unsigned int>(root_objects.size()); ++i) {
  ------------------
  |  Branch (252:30): [True: 3, False: 2]
  ------------------
  253|      3|        root->mChildren[i] = ConvertNode(in, root_objects[i], conv_data, aiMatrix4x4());
  254|      3|        root->mChildren[i]->mParent = root;
  255|      3|    }
  256|       |
  257|       |    // For each subcollection create a new node to represent it
  258|      2|    unsigned int iterator = static_cast<unsigned int>(root_objects.size());
  259|      3|    for (std::shared_ptr<CollectionChild> cur = std::static_pointer_cast<CollectionChild>(collection->children.first); cur; cur = cur->next) {
  ------------------
  |  Branch (259:120): [True: 1, False: 2]
  ------------------
  260|      1|        if (cur->collection) {
  ------------------
  |  Branch (260:13): [True: 1, False: 0]
  ------------------
  261|      1|            root->mChildren[iterator] = new aiNode(cur->collection->id.name + 2); // skip over the name prefix 'OB'
  262|      1|            root->mChildren[iterator]->mParent = root;
  263|      1|            ParseSubCollection(in, root->mChildren[iterator], cur->collection, conv_data);
  264|      1|        }
  265|      1|        iterator += 1;
  266|      1|    }
  267|      2|}
_ZN6Assimp15BlenderImporter16ConvertBlendFileEP7aiSceneRKNS_7Blender5SceneERKNS3_12FileDatabaseE:
  270|     25|void BlenderImporter::ConvertBlendFile(aiScene *out, const Scene &in, const FileDatabase &file) {
  271|     25|    ConversionData conv(file);
  272|       |
  273|     25|    aiNode *root = out->mRootNode = new aiNode("<BlenderRoot>");
  274|       |    // Iterate over all objects directly under master_collection,
  275|       |    // If in.master_collection == null, then we're parsing something older.
  276|     25|    if (in.master_collection) {
  ------------------
  |  Branch (276:9): [True: 1, False: 24]
  ------------------
  277|      1|        ParseSubCollection(in, root, in.master_collection, conv);
  278|     24|    } else {
  279|     24|        std::deque<const Object *> no_parents;
  280|    119|        for (std::shared_ptr<Base> cur = std::static_pointer_cast<Base>(in.base.first); cur; cur = cur->next) {
  ------------------
  |  Branch (280:89): [True: 95, False: 24]
  ------------------
  281|     95|            if (cur->object) {
  ------------------
  |  Branch (281:17): [True: 95, False: 0]
  ------------------
  282|     95|                if (!cur->object->parent) {
  ------------------
  |  Branch (282:21): [True: 86, False: 9]
  ------------------
  283|     86|                    no_parents.push_back(cur->object.get());
  284|     86|                } else {
  285|      9|                    conv.objects.insert(cur->object.get());
  286|      9|                }
  287|     95|            }
  288|     95|        }
  289|    102|        for (std::shared_ptr<Base> cur = in.basact; cur; cur = cur->next) {
  ------------------
  |  Branch (289:53): [True: 78, False: 24]
  ------------------
  290|     78|            if (cur->object) {
  ------------------
  |  Branch (290:17): [True: 78, False: 0]
  ------------------
  291|     78|                if (cur->object->parent) {
  ------------------
  |  Branch (291:21): [True: 9, False: 69]
  ------------------
  292|      9|                    conv.objects.insert(cur->object.get());
  293|      9|                }
  294|     78|            }
  295|     78|        }
  296|       |
  297|     24|        if (no_parents.empty()) {
  ------------------
  |  Branch (297:13): [True: 0, False: 24]
  ------------------
  298|      0|            ThrowException("Expected at least one object with no parent");
  299|      0|        }
  300|       |
  301|     24|        root->mNumChildren = static_cast<unsigned int>(no_parents.size());
  302|     24|        root->mChildren = new aiNode *[root->mNumChildren]();
  303|    110|        for (unsigned int i = 0; i < root->mNumChildren; ++i) {
  ------------------
  |  Branch (303:34): [True: 86, False: 24]
  ------------------
  304|     86|            root->mChildren[i] = ConvertNode(in, no_parents[i], conv, aiMatrix4x4());
  305|     86|            root->mChildren[i]->mParent = root;
  306|     86|        }
  307|     24|    }
  308|       |
  309|     25|    BuildMaterials(conv);
  310|       |
  311|     25|    if (conv.meshes->size()) {
  ------------------
  |  Branch (311:9): [True: 25, False: 0]
  ------------------
  312|     25|        out->mMeshes = new aiMesh *[out->mNumMeshes = static_cast<unsigned int>(conv.meshes->size())];
  313|     25|        std::copy(conv.meshes->begin(), conv.meshes->end(), out->mMeshes);
  314|     25|        conv.meshes.dismiss();
  315|     25|    }
  316|       |
  317|     25|    if (conv.lights->size()) {
  ------------------
  |  Branch (317:9): [True: 25, False: 0]
  ------------------
  318|     25|        out->mLights = new aiLight *[out->mNumLights = static_cast<unsigned int>(conv.lights->size())];
  319|     25|        std::copy(conv.lights->begin(), conv.lights->end(), out->mLights);
  320|     25|        conv.lights.dismiss();
  321|     25|    }
  322|       |
  323|     25|    if (conv.cameras->size()) {
  ------------------
  |  Branch (323:9): [True: 25, False: 0]
  ------------------
  324|     25|        out->mCameras = new aiCamera *[out->mNumCameras = static_cast<unsigned int>(conv.cameras->size())];
  325|     25|        std::copy(conv.cameras->begin(), conv.cameras->end(), out->mCameras);
  326|     25|        conv.cameras.dismiss();
  327|     25|    }
  328|       |
  329|     25|    if (conv.materials->size()) {
  ------------------
  |  Branch (329:9): [True: 25, False: 0]
  ------------------
  330|     25|        out->mMaterials = new aiMaterial *[out->mNumMaterials = static_cast<unsigned int>(conv.materials->size())];
  331|     25|        std::copy(conv.materials->begin(), conv.materials->end(), out->mMaterials);
  332|     25|        conv.materials.dismiss();
  333|     25|    }
  334|       |
  335|     25|    if (conv.textures->size()) {
  ------------------
  |  Branch (335:9): [True: 1, False: 24]
  ------------------
  336|      1|        out->mTextures = new aiTexture *[out->mNumTextures = static_cast<unsigned int>(conv.textures->size())];
  337|      1|        std::copy(conv.textures->begin(), conv.textures->end(), out->mTextures);
  338|      1|        conv.textures.dismiss();
  339|      1|    }
  340|       |
  341|       |    // acknowledge that the scene might come out incomplete
  342|       |    // by Assimp's definition of `complete`: blender scenes
  343|       |    // can consist of thousands of cameras or lights with
  344|       |    // not a single mesh between them.
  345|     25|    if (!out->mNumMeshes) {
  ------------------
  |  Branch (345:9): [True: 0, False: 25]
  ------------------
  346|       |        out->mFlags |= AI_SCENE_FLAGS_INCOMPLETE;
  347|      0|    }
  348|     25|}
_ZN6Assimp15BlenderImporter12ResolveImageEP10aiMaterialPKNS_7Blender8MaterialEPKNS3_4MTexEPKNS3_5ImageERNS3_14ConversionDataE:
  351|      9|void BlenderImporter::ResolveImage(aiMaterial *out, const Material *mat, const MTex *tex, const Image *img, ConversionData &conv_data) {
  352|      9|    (void)mat;
  353|      9|    (void)tex;
  354|      9|    (void)conv_data;
  355|      9|    aiString name;
  356|       |
  357|       |    // check if the file contents are bundled with the BLEND file
  358|      9|    if (img->packedfile) {
  ------------------
  |  Branch (358:9): [True: 1, False: 8]
  ------------------
  359|      1|        name.data[0] = '*';
  360|      1|        name.length = 1 + ASSIMP_itoa10(name.data + 1, static_cast<unsigned int>(AI_MAXLEN - 1), static_cast<int32_t>(conv_data.textures->size()));
  361|       |
  362|      1|        conv_data.textures->push_back(new aiTexture());
  363|      1|        aiTexture *curTex = conv_data.textures->back();
  364|       |
  365|       |        // usually 'img->name' will be the original file name of the embedded textures,
  366|       |        // so we can extract the file extension from it.
  367|      1|        const size_t nlen = strlen(img->name);
  368|      1|        const char *s = img->name + nlen, *e = s;
  369|      5|        while (s >= img->name && *s != '.') {
  ------------------
  |  Branch (369:16): [True: 5, False: 0]
  |  Branch (369:34): [True: 4, False: 1]
  ------------------
  370|      4|            --s;
  371|      4|        }
  372|       |
  373|      1|        curTex->achFormatHint[0] = s + 1 > e ? '\0' : (char)::tolower((unsigned char)s[1]);
  ------------------
  |  Branch (373:36): [True: 0, False: 1]
  ------------------
  374|      1|        curTex->achFormatHint[1] = s + 2 > e ? '\0' : (char)::tolower((unsigned char)s[2]);
  ------------------
  |  Branch (374:36): [True: 0, False: 1]
  ------------------
  375|      1|        curTex->achFormatHint[2] = s + 3 > e ? '\0' : (char)::tolower((unsigned char)s[3]);
  ------------------
  |  Branch (375:36): [True: 0, False: 1]
  ------------------
  376|      1|        curTex->achFormatHint[3] = '\0';
  377|       |
  378|       |        // tex->mHeight = 0;
  379|      1|        curTex->mWidth = img->packedfile->size;
  380|      1|        uint8_t *ch = new uint8_t[curTex->mWidth];
  381|       |
  382|      1|        conv_data.db.reader->SetCurrentPos(static_cast<size_t>(img->packedfile->data->val));
  383|      1|        conv_data.db.reader->CopyAndAdvance(ch, curTex->mWidth);
  384|       |
  385|      1|        curTex->pcData = reinterpret_cast<aiTexel *>(ch);
  386|       |
  387|      1|        LogInfo("Reading embedded texture, original file was ", img->name);
  388|      8|    } else {
  389|      8|        name = aiString(img->name);
  390|      8|    }
  391|       |
  392|      9|    aiTextureType texture_type = aiTextureType_UNKNOWN;
  393|      9|    MTex::MapType map_type = tex->mapto;
  394|       |
  395|      9|    if (map_type & MTex::MapType_COL)
  ------------------
  |  Branch (395:9): [True: 8, False: 1]
  ------------------
  396|      8|        texture_type = aiTextureType_DIFFUSE;
  397|      1|    else if (map_type & MTex::MapType_NORM) {
  ------------------
  |  Branch (397:14): [True: 0, False: 1]
  ------------------
  398|      0|        if (tex->tex->imaflag & Tex::ImageFlags_NORMALMAP) {
  ------------------
  |  Branch (398:13): [True: 0, False: 0]
  ------------------
  399|      0|            texture_type = aiTextureType_NORMALS;
  400|      0|        } else {
  401|      0|            texture_type = aiTextureType_HEIGHT;
  402|      0|        }
  403|      0|        out->AddProperty(&tex->norfac, 1, AI_MATKEY_BUMPSCALING);
  404|      1|    } else if (map_type & MTex::MapType_COLSPEC)
  ------------------
  |  Branch (404:16): [True: 0, False: 1]
  ------------------
  405|      0|        texture_type = aiTextureType_SPECULAR;
  406|      1|    else if (map_type & MTex::MapType_COLMIR)
  ------------------
  |  Branch (406:14): [True: 0, False: 1]
  ------------------
  407|      0|        texture_type = aiTextureType_REFLECTION;
  408|       |    //else if (map_type & MTex::MapType_REF)
  409|      1|    else if (map_type & MTex::MapType_SPEC)
  ------------------
  |  Branch (409:14): [True: 0, False: 1]
  ------------------
  410|      0|        texture_type = aiTextureType_SHININESS;
  411|      1|    else if (map_type & MTex::MapType_EMIT)
  ------------------
  |  Branch (411:14): [True: 0, False: 1]
  ------------------
  412|      0|        texture_type = aiTextureType_EMISSIVE;
  413|       |    //else if (map_type & MTex::MapType_ALPHA)
  414|       |    //else if (map_type & MTex::MapType_HAR)
  415|       |    //else if (map_type & MTex::MapType_RAYMIRR)
  416|       |    //else if (map_type & MTex::MapType_TRANSLU)
  417|      1|    else if (map_type & MTex::MapType_AMB)
  ------------------
  |  Branch (417:14): [True: 1, False: 0]
  ------------------
  418|      1|        texture_type = aiTextureType_AMBIENT;
  419|      0|    else if (map_type & MTex::MapType_DISPLACE)
  ------------------
  |  Branch (419:14): [True: 0, False: 0]
  ------------------
  420|      0|        texture_type = aiTextureType_DISPLACEMENT;
  421|       |    //else if (map_type & MTex::MapType_WARP)
  422|       |
  423|       |    out->AddProperty(&name, AI_MATKEY_TEXTURE(texture_type,
  424|      9|                                    conv_data.next_texture[texture_type]++));
  425|      9|}
_ZN6Assimp15BlenderImporter18AddSentinelTextureEP10aiMaterialPKNS_7Blender8MaterialEPKNS3_4MTexERNS3_14ConversionDataE:
  428|      1|void BlenderImporter::AddSentinelTexture(aiMaterial *out, const Material *mat, const MTex *tex, ConversionData &conv_data) {
  429|      1|    (void)mat;
  430|      1|    (void)tex;
  431|      1|    (void)conv_data;
  432|       |
  433|      1|    aiString name;
  434|      1|    name.length = ai_snprintf(name.data, AI_MAXLEN, "Procedural,num=%i,type=%s", conv_data.sentinel_cnt++,
  435|      1|            GetTextureTypeDisplayString(tex->tex->type));
  436|       |    out->AddProperty(&name, AI_MATKEY_TEXTURE_DIFFUSE(
  437|      1|                                    conv_data.next_texture[aiTextureType_DIFFUSE]++));
  438|      1|}
_ZN6Assimp15BlenderImporter14ResolveTextureEP10aiMaterialPKNS_7Blender8MaterialEPKNS3_4MTexERNS3_14ConversionDataE:
  441|     27|void BlenderImporter::ResolveTexture(aiMaterial *out, const Material *mat, const MTex *tex, ConversionData &conv_data) {
  442|     27|    const Tex *rtex = tex->tex.get();
  443|     27|    if (!rtex || !rtex->type) {
  ------------------
  |  Branch (443:9): [True: 0, False: 27]
  |  Branch (443:18): [True: 17, False: 10]
  ------------------
  444|     17|        return;
  445|     17|    }
  446|       |
  447|       |    // We can't support most of the texture types because they're mostly procedural.
  448|       |    // These are substituted by a dummy texture.
  449|     10|    const char *dispnam = "";
  450|     10|    switch (rtex->type) {
  451|       |        // these are listed in blender's UI
  452|      0|    case Tex::Type_CLOUDS:
  ------------------
  |  Branch (452:5): [True: 0, False: 10]
  ------------------
  453|      0|    case Tex::Type_WOOD:
  ------------------
  |  Branch (453:5): [True: 0, False: 10]
  ------------------
  454|      0|    case Tex::Type_MARBLE:
  ------------------
  |  Branch (454:5): [True: 0, False: 10]
  ------------------
  455|      0|    case Tex::Type_MAGIC:
  ------------------
  |  Branch (455:5): [True: 0, False: 10]
  ------------------
  456|      0|    case Tex::Type_BLEND:
  ------------------
  |  Branch (456:5): [True: 0, False: 10]
  ------------------
  457|      0|    case Tex::Type_STUCCI:
  ------------------
  |  Branch (457:5): [True: 0, False: 10]
  ------------------
  458|      0|    case Tex::Type_NOISE:
  ------------------
  |  Branch (458:5): [True: 0, False: 10]
  ------------------
  459|      0|    case Tex::Type_PLUGIN:
  ------------------
  |  Branch (459:5): [True: 0, False: 10]
  ------------------
  460|      0|    case Tex::Type_MUSGRAVE:
  ------------------
  |  Branch (460:5): [True: 0, False: 10]
  ------------------
  461|      1|    case Tex::Type_VORONOI:
  ------------------
  |  Branch (461:5): [True: 1, False: 9]
  ------------------
  462|      1|    case Tex::Type_DISTNOISE:
  ------------------
  |  Branch (462:5): [True: 0, False: 10]
  ------------------
  463|      1|    case Tex::Type_ENVMAP:
  ------------------
  |  Branch (463:5): [True: 0, False: 10]
  ------------------
  464|       |
  465|       |        // these do no appear in the UI, why?
  466|      1|    case Tex::Type_POINTDENSITY:
  ------------------
  |  Branch (466:5): [True: 0, False: 10]
  ------------------
  467|      1|    case Tex::Type_VOXELDATA:
  ------------------
  |  Branch (467:5): [True: 0, False: 10]
  ------------------
  468|       |
  469|      1|        LogWarn("Encountered a texture with an unsupported type: ", dispnam);
  470|      1|        AddSentinelTexture(out, mat, tex, conv_data);
  471|      1|        break;
  472|       |
  473|      9|    case Tex::Type_IMAGE:
  ------------------
  |  Branch (473:5): [True: 9, False: 1]
  ------------------
  474|      9|        if (!rtex->ima) {
  ------------------
  |  Branch (474:13): [True: 0, False: 9]
  ------------------
  475|      0|            LogError("A texture claims to be an Image, but no image reference is given");
  476|      0|            break;
  477|      0|        }
  478|      9|        ResolveImage(out, mat, tex, rtex->ima.get(), conv_data);
  479|      9|        break;
  480|       |
  481|      0|    default:
  ------------------
  |  Branch (481:5): [True: 0, False: 10]
  ------------------
  482|      0|        ai_assert(false);
  483|     10|    };
  484|     10|}
_ZN6Assimp15BlenderImporter20BuildDefaultMaterialERNS_7Blender14ConversionDataE:
  487|     25|void BlenderImporter::BuildDefaultMaterial(Blender::ConversionData &conv_data) {
  488|       |    // add a default material if necessary
  489|     25|    unsigned int index = static_cast<unsigned int>(-1);
  490|     41|    for (aiMesh *mesh : conv_data.meshes.get()) {
  ------------------
  |  Branch (490:23): [True: 41, False: 25]
  ------------------
  491|     41|        if (mesh->mMaterialIndex == static_cast<unsigned int>(-1)) {
  ------------------
  |  Branch (491:13): [True: 4, False: 37]
  ------------------
  492|       |
  493|      4|            if (index == static_cast<unsigned int>(-1)) {
  ------------------
  |  Branch (493:17): [True: 4, False: 0]
  ------------------
  494|       |                // Setup a default material.
  495|      4|                std::shared_ptr<Material> p(new Material());
  496|      4|                const size_t len = ::strlen(AI_DEFAULT_MATERIAL_NAME);
  497|      4|                ai_assert(len < sizeof(p->id.name) - 2);
  498|      4|                memcpy(p->id.name + 2, AI_DEFAULT_MATERIAL_NAME, len);
  499|       |
  500|       |                // Note: MSVC11 does not zero-initialize Material here, although it should.
  501|       |                // Thus all relevant fields should be explicitly initialized. We cannot add
  502|       |                // a default constructor to Material since the DNA codegen does not support
  503|       |                // parsing it.
  504|      4|                p->r = p->g = p->b = 0.6f;
  505|      4|                p->specr = p->specg = p->specb = 0.6f;
  506|      4|                p->ambr = p->ambg = p->ambb = 0.0f;
  507|      4|                p->mirr = p->mirg = p->mirb = 0.0f;
  508|      4|                p->emit = 0.f;
  509|      4|                p->alpha = 0.f;
  510|      4|                p->har = 0;
  511|       |
  512|      4|                index = static_cast<unsigned int>(conv_data.materials_raw.size());
  513|      4|                conv_data.materials_raw.push_back(p);
  514|      4|                LogInfo("Adding default material");
  515|      4|            }
  516|      4|            mesh->mMaterialIndex = index;
  517|      4|        }
  518|     41|    }
  519|     25|}
_ZN6Assimp15BlenderImporter14AddBlendParamsEP10aiMaterialPKNS_7Blender8MaterialE:
  521|     31|void BlenderImporter::AddBlendParams(aiMaterial *result, const Material *source) {
  522|     31|    aiColor3D diffuseColor(source->r, source->g, source->b);
  523|     31|    result->AddProperty(&diffuseColor, 1, "$mat.blend.diffuse.color", 0, 0);
  524|       |
  525|     31|    float diffuseIntensity = source->ref;
  526|     31|    result->AddProperty(&diffuseIntensity, 1, "$mat.blend.diffuse.intensity", 0, 0);
  527|       |
  528|     31|    int diffuseShader = source->diff_shader;
  529|     31|    result->AddProperty(&diffuseShader, 1, "$mat.blend.diffuse.shader", 0, 0);
  530|       |
  531|     31|    int diffuseRamp = 0;
  532|     31|    result->AddProperty(&diffuseRamp, 1, "$mat.blend.diffuse.ramp", 0, 0);
  533|       |
  534|     31|    aiColor3D specularColor(source->specr, source->specg, source->specb);
  535|     31|    result->AddProperty(&specularColor, 1, "$mat.blend.specular.color", 0, 0);
  536|       |
  537|     31|    float specularIntensity = source->spec;
  538|     31|    result->AddProperty(&specularIntensity, 1, "$mat.blend.specular.intensity", 0, 0);
  539|       |
  540|     31|    int specularShader = source->spec_shader;
  541|     31|    result->AddProperty(&specularShader, 1, "$mat.blend.specular.shader", 0, 0);
  542|       |
  543|     31|    int specularRamp = 0;
  544|     31|    result->AddProperty(&specularRamp, 1, "$mat.blend.specular.ramp", 0, 0);
  545|       |
  546|     31|    int specularHardness = source->har;
  547|     31|    result->AddProperty(&specularHardness, 1, "$mat.blend.specular.hardness", 0, 0);
  548|       |
  549|     31|    int transparencyUse = source->mode & MA_TRANSPARENCY ? 1 : 0;
  ------------------
  |  Branch (549:27): [True: 14, False: 17]
  ------------------
  550|     31|    result->AddProperty(&transparencyUse, 1, "$mat.blend.transparency.use", 0, 0);
  551|       |
  552|     31|    int transparencyMethod = source->mode & MA_RAYTRANSP ? 2 : (source->mode & MA_ZTRANSP ? 1 : 0);
  ------------------
  |  Branch (552:30): [True: 1, False: 30]
  |  Branch (552:65): [True: 13, False: 17]
  ------------------
  553|     31|    result->AddProperty(&transparencyMethod, 1, "$mat.blend.transparency.method", 0, 0);
  554|       |
  555|     31|    float transparencyAlpha = source->alpha;
  556|     31|    result->AddProperty(&transparencyAlpha, 1, "$mat.blend.transparency.alpha", 0, 0);
  557|       |
  558|     31|    float transparencySpecular = source->spectra;
  559|     31|    result->AddProperty(&transparencySpecular, 1, "$mat.blend.transparency.specular", 0, 0);
  560|       |
  561|     31|    float transparencyFresnel = source->fresnel_tra;
  562|     31|    result->AddProperty(&transparencyFresnel, 1, "$mat.blend.transparency.fresnel", 0, 0);
  563|       |
  564|     31|    float transparencyBlend = source->fresnel_tra_i;
  565|     31|    result->AddProperty(&transparencyBlend, 1, "$mat.blend.transparency.blend", 0, 0);
  566|       |
  567|     31|    float transparencyIor = source->ang;
  568|     31|    result->AddProperty(&transparencyIor, 1, "$mat.blend.transparency.ior", 0, 0);
  569|       |
  570|     31|    float transparencyFilter = source->filter;
  571|     31|    result->AddProperty(&transparencyFilter, 1, "$mat.blend.transparency.filter", 0, 0);
  572|       |
  573|     31|    float transparencyFalloff = source->tx_falloff;
  574|     31|    result->AddProperty(&transparencyFalloff, 1, "$mat.blend.transparency.falloff", 0, 0);
  575|       |
  576|     31|    float transparencyLimit = source->tx_limit;
  577|     31|    result->AddProperty(&transparencyLimit, 1, "$mat.blend.transparency.limit", 0, 0);
  578|       |
  579|     31|    int transparencyDepth = source->ray_depth_tra;
  580|     31|    result->AddProperty(&transparencyDepth, 1, "$mat.blend.transparency.depth", 0, 0);
  581|       |
  582|     31|    float transparencyGlossAmount = source->gloss_tra;
  583|     31|    result->AddProperty(&transparencyGlossAmount, 1, "$mat.blend.transparency.glossAmount", 0, 0);
  584|       |
  585|     31|    float transparencyGlossThreshold = source->adapt_thresh_tra;
  586|     31|    result->AddProperty(&transparencyGlossThreshold, 1, "$mat.blend.transparency.glossThreshold", 0, 0);
  587|       |
  588|     31|    int transparencyGlossSamples = source->samp_gloss_tra;
  589|     31|    result->AddProperty(&transparencyGlossSamples, 1, "$mat.blend.transparency.glossSamples", 0, 0);
  590|       |
  591|     31|    int mirrorUse = source->mode & MA_RAYMIRROR ? 1 : 0;
  ------------------
  |  Branch (591:21): [True: 1, False: 30]
  ------------------
  592|     31|    result->AddProperty(&mirrorUse, 1, "$mat.blend.mirror.use", 0, 0);
  593|       |
  594|     31|    float mirrorReflectivity = source->ray_mirror;
  595|     31|    result->AddProperty(&mirrorReflectivity, 1, "$mat.blend.mirror.reflectivity", 0, 0);
  596|       |
  597|     31|    aiColor3D mirrorColor(source->mirr, source->mirg, source->mirb);
  598|     31|    result->AddProperty(&mirrorColor, 1, "$mat.blend.mirror.color", 0, 0);
  599|       |
  600|     31|    float mirrorFresnel = source->fresnel_mir;
  601|     31|    result->AddProperty(&mirrorFresnel, 1, "$mat.blend.mirror.fresnel", 0, 0);
  602|       |
  603|     31|    float mirrorBlend = source->fresnel_mir_i;
  604|     31|    result->AddProperty(&mirrorBlend, 1, "$mat.blend.mirror.blend", 0, 0);
  605|       |
  606|     31|    int mirrorDepth = source->ray_depth;
  607|     31|    result->AddProperty(&mirrorDepth, 1, "$mat.blend.mirror.depth", 0, 0);
  608|       |
  609|     31|    float mirrorMaxDist = source->dist_mir;
  610|     31|    result->AddProperty(&mirrorMaxDist, 1, "$mat.blend.mirror.maxDist", 0, 0);
  611|       |
  612|     31|    int mirrorFadeTo = source->fadeto_mir;
  613|     31|    result->AddProperty(&mirrorFadeTo, 1, "$mat.blend.mirror.fadeTo", 0, 0);
  614|       |
  615|     31|    float mirrorGlossAmount = source->gloss_mir;
  616|     31|    result->AddProperty(&mirrorGlossAmount, 1, "$mat.blend.mirror.glossAmount", 0, 0);
  617|       |
  618|     31|    float mirrorGlossThreshold = source->adapt_thresh_mir;
  619|     31|    result->AddProperty(&mirrorGlossThreshold, 1, "$mat.blend.mirror.glossThreshold", 0, 0);
  620|       |
  621|     31|    int mirrorGlossSamples = source->samp_gloss_mir;
  622|     31|    result->AddProperty(&mirrorGlossSamples, 1, "$mat.blend.mirror.glossSamples", 0, 0);
  623|       |
  624|     31|    float mirrorGlossAnisotropic = source->aniso_gloss_mir;
  625|     31|    result->AddProperty(&mirrorGlossAnisotropic, 1, "$mat.blend.mirror.glossAnisotropic", 0, 0);
  626|     31|}
_ZN6Assimp15BlenderImporter14BuildMaterialsERNS_7Blender14ConversionDataE:
  628|     25|void BlenderImporter::BuildMaterials(ConversionData &conv_data) {
  629|     25|    conv_data.materials->reserve(conv_data.materials_raw.size());
  630|       |
  631|     25|    BuildDefaultMaterial(conv_data);
  632|       |
  633|     31|    for (const std::shared_ptr<Material> &mat : conv_data.materials_raw) {
  ------------------
  |  Branch (633:47): [True: 31, False: 25]
  ------------------
  634|       |
  635|       |        // reset per material global counters
  636|    620|        for (size_t i = 0; i < sizeof(conv_data.next_texture) / sizeof(conv_data.next_texture[0]); ++i) {
  ------------------
  |  Branch (636:28): [True: 589, False: 31]
  ------------------
  637|    589|            conv_data.next_texture[i] = 0;
  638|    589|        }
  639|       |
  640|     31|        aiMaterial *mout = new aiMaterial();
  641|     31|        conv_data.materials->push_back(mout);
  642|       |        // For any new material field handled here, the default material above must be updated with an appropriate default value.
  643|       |
  644|       |        // set material name
  645|     31|        aiString name = aiString(mat->id.name + 2); // skip over the name prefix 'MA'
  646|     31|        mout->AddProperty(&name, AI_MATKEY_NAME);
  647|       |
  648|       |        // basic material colors
  649|     31|        aiColor3D col(mat->r, mat->g, mat->b);
  650|     31|        if (mat->r || mat->g || mat->b) {
  ------------------
  |  Branch (650:13): [True: 31, False: 0]
  |  Branch (650:23): [True: 0, False: 0]
  |  Branch (650:33): [True: 0, False: 0]
  ------------------
  651|       |
  652|       |            // Usually, zero diffuse color means no diffuse color at all in the equation.
  653|       |            // So we omit this member to express this intent.
  654|     31|            mout->AddProperty(&col, 1, AI_MATKEY_COLOR_DIFFUSE);
  655|       |
  656|     31|            if (mat->emit) {
  ------------------
  |  Branch (656:17): [True: 1, False: 30]
  ------------------
  657|      1|                aiColor3D emit_col(mat->emit * mat->r, mat->emit * mat->g, mat->emit * mat->b);
  658|      1|                mout->AddProperty(&emit_col, 1, AI_MATKEY_COLOR_EMISSIVE);
  659|      1|            }
  660|     31|        }
  661|       |
  662|     31|        col = aiColor3D(mat->specr, mat->specg, mat->specb);
  663|     31|        mout->AddProperty(&col, 1, AI_MATKEY_COLOR_SPECULAR);
  664|       |
  665|       |        // is hardness/shininess set?
  666|     31|        if (mat->har) {
  ------------------
  |  Branch (666:13): [True: 26, False: 5]
  ------------------
  667|     26|            const float har = mat->har;
  668|     26|            mout->AddProperty(&har, 1, AI_MATKEY_SHININESS);
  669|     26|        }
  670|       |
  671|     31|        col = aiColor3D(mat->ambr, mat->ambg, mat->ambb);
  672|     31|        mout->AddProperty(&col, 1, AI_MATKEY_COLOR_AMBIENT);
  673|       |
  674|       |        // is mirror enabled?
  675|     31|        if (mat->mode & MA_RAYMIRROR) {
  ------------------
  |  Branch (675:13): [True: 1, False: 30]
  ------------------
  676|      1|            const float ray_mirror = mat->ray_mirror;
  677|      1|            mout->AddProperty(&ray_mirror, 1, AI_MATKEY_REFLECTIVITY);
  678|      1|        }
  679|       |
  680|     31|        col = aiColor3D(mat->mirr, mat->mirg, mat->mirb);
  681|     31|        mout->AddProperty(&col, 1, AI_MATKEY_COLOR_REFLECTIVE);
  682|       |
  683|    589|        for (size_t i = 0; i < sizeof(mat->mtex) / sizeof(mat->mtex[0]); ++i) {
  ------------------
  |  Branch (683:28): [True: 558, False: 31]
  ------------------
  684|    558|            if (!mat->mtex[i]) {
  ------------------
  |  Branch (684:17): [True: 531, False: 27]
  ------------------
  685|    531|                continue;
  686|    531|            }
  687|       |
  688|     27|            ResolveTexture(mout, mat.get(), mat->mtex[i].get(), conv_data);
  689|     27|        }
  690|       |
  691|     31|        AddBlendParams(mout, mat.get());
  692|     31|    }
  693|     25|}
_ZN6Assimp15BlenderImporter15CheckActualTypeEPKNS_7Blender8ElemBaseEPKc:
  696|     95|void BlenderImporter::CheckActualType(const ElemBase *dt, const char *check) {
  697|     95|    ai_assert(dt);
  698|     95|    if (strcmp(dt->dna_type, check)) {
  ------------------
  |  Branch (698:9): [True: 0, False: 95]
  ------------------
  699|      0|        ThrowException("Expected object at ", std::hex, dt, " to be of type `", check,
  700|      0|                "`, but it claims to be a `", dt->dna_type, "`instead");
  701|      0|    }
  702|     95|}
_ZN6Assimp15BlenderImporter11ConvertMeshERKNS_7Blender5SceneEPKNS1_6ObjectEPKNS1_4MeshERNS1_14ConversionDataERNS1_9TempArrayINSt3__16vectorE6aiMeshEE:
  711|     38|        ConversionData &conv_data, TempArray<std::vector, aiMesh> &temp) {
  712|       |    // TODO: Resolve various problems with BMesh triangulation before re-enabling.
  713|       |    //       See issues #400, #373, #318  #315 and #132.
  714|       |#if defined(TODO_FIX_BMESH_CONVERSION)
  715|       |    BlenderBMeshConverter BMeshConverter(mesh);
  716|       |    if (BMeshConverter.ContainsBMesh()) {
  717|       |        mesh = BMeshConverter.TriangulateBMesh();
  718|       |    }
  719|       |#endif
  720|       |
  721|     38|    typedef std::pair<const int, size_t> MyPair;
  722|     38|    if ((!mesh->totface && !mesh->totloop) || !mesh->totvert) {
  ------------------
  |  Branch (722:10): [True: 11, False: 27]
  |  Branch (722:28): [True: 0, False: 11]
  |  Branch (722:47): [True: 0, False: 38]
  ------------------
  723|      0|        return;
  724|      0|    }
  725|       |
  726|       |    // some sanity checks
  727|     38|    if (static_cast<size_t>(mesh->totface) > mesh->mface.size()) {
  ------------------
  |  Branch (727:9): [True: 0, False: 38]
  ------------------
  728|      0|        ThrowException("Number of faces is larger than the corresponding array");
  729|      0|    }
  730|       |
  731|     38|    if (static_cast<size_t>(mesh->totvert) > mesh->mvert.size()) {
  ------------------
  |  Branch (731:9): [True: 0, False: 38]
  ------------------
  732|      0|        ThrowException("Number of vertices is larger than the corresponding array");
  733|      0|    }
  734|       |
  735|     38|    if (static_cast<size_t>(mesh->totloop) > mesh->mloop.size()) {
  ------------------
  |  Branch (735:9): [True: 0, False: 38]
  ------------------
  736|      0|        ThrowException("Number of vertices is larger than the corresponding array");
  737|      0|    }
  738|       |
  739|       |    // collect per-submesh numbers
  740|     38|    std::map<int, size_t> per_mat;
  741|     38|    std::map<int, size_t> per_mat_verts;
  742|  7.52k|    for (int i = 0; i < mesh->totface; ++i) {
  ------------------
  |  Branch (742:21): [True: 7.48k, False: 38]
  ------------------
  743|       |
  744|  7.48k|        const MFace &mf = mesh->mface[i];
  745|  7.48k|        per_mat[mf.mat_nr]++;
  746|  7.48k|        per_mat_verts[mf.mat_nr] += mf.v4 ? 4 : 3;
  ------------------
  |  Branch (746:37): [True: 7.32k, False: 161]
  ------------------
  747|  7.48k|    }
  748|       |
  749|    721|    for (int i = 0; i < mesh->totpoly; ++i) {
  ------------------
  |  Branch (749:21): [True: 683, False: 38]
  ------------------
  750|    683|        const MPoly &mp = mesh->mpoly[i];
  751|    683|        per_mat[mp.mat_nr]++;
  752|    683|        per_mat_verts[mp.mat_nr] += mp.totloop;
  753|    683|    }
  754|       |
  755|       |    // ... and allocate the corresponding meshes
  756|     38|    const size_t old = temp->size();
  757|     38|    temp->reserve(temp->size() + per_mat.size());
  758|       |
  759|     38|    std::map<size_t, size_t> mat_num_to_mesh_idx;
  760|     39|    for (MyPair &it : per_mat) {
  ------------------
  |  Branch (760:21): [True: 39, False: 38]
  ------------------
  761|       |
  762|     39|        mat_num_to_mesh_idx[it.first] = temp->size();
  763|     39|        temp->push_back(new aiMesh());
  764|       |
  765|     39|        aiMesh *out = temp->back();
  766|     39|        out->mVertices = new aiVector3D[per_mat_verts[it.first]];
  767|     39|        out->mNormals = new aiVector3D[per_mat_verts[it.first]];
  768|       |
  769|       |        //out->mNumFaces = 0
  770|       |        //out->mNumVertices = 0
  771|     39|        out->mFaces = new aiFace[it.second]();
  772|       |
  773|       |        // all sub-meshes created from this mesh are named equally. this allows
  774|       |        // curious users to recover the original adjacency.
  775|     39|        out->mName = aiString(mesh->id.name + 2);
  776|       |        // skip over the name prefix 'ME'
  777|       |
  778|       |        // resolve the material reference and add this material to the set of
  779|       |        // output materials. The (temporary) material index is the index
  780|       |        // of the material entry within the list of resolved materials.
  781|     39|        if (mesh->mat) {
  ------------------
  |  Branch (781:13): [True: 35, False: 4]
  ------------------
  782|       |
  783|     35|            if (static_cast<size_t>(it.first) >= mesh->mat.size()) {
  ------------------
  |  Branch (783:17): [True: 0, False: 35]
  ------------------
  784|      0|                ThrowException("Material index is out of range");
  785|      0|            }
  786|       |
  787|     35|            std::shared_ptr<Material> mat = mesh->mat[it.first];
  788|     35|            const std::deque<std::shared_ptr<Material>>::iterator has = std::find(
  789|     35|                    conv_data.materials_raw.begin(),
  790|     35|                    conv_data.materials_raw.end(), mat);
  791|       |
  792|     35|            if (has != conv_data.materials_raw.end()) {
  ------------------
  |  Branch (792:17): [True: 8, False: 27]
  ------------------
  793|      8|                out->mMaterialIndex = static_cast<unsigned int>(std::distance(conv_data.materials_raw.begin(), has));
  794|     27|            } else {
  795|     27|                out->mMaterialIndex = static_cast<unsigned int>(conv_data.materials_raw.size());
  796|     27|                conv_data.materials_raw.push_back(mat);
  797|     27|            }
  798|     35|        } else
  799|      4|            out->mMaterialIndex = static_cast<unsigned int>(-1);
  800|     39|    }
  801|       |
  802|  7.52k|    for (int i = 0; i < mesh->totface; ++i) {
  ------------------
  |  Branch (802:21): [True: 7.48k, False: 38]
  ------------------
  803|       |
  804|  7.48k|        const MFace &mf = mesh->mface[i];
  805|       |
  806|  7.48k|        aiMesh *const out = temp[mat_num_to_mesh_idx[mf.mat_nr]];
  807|  7.48k|        aiFace &f = out->mFaces[out->mNumFaces++];
  808|       |
  809|  7.48k|        f.mIndices = new unsigned int[f.mNumIndices = mf.v4 ? 4 : 3];
  ------------------
  |  Branch (809:55): [True: 7.32k, False: 161]
  ------------------
  810|  7.48k|        aiVector3D *vo = out->mVertices + out->mNumVertices;
  811|  7.48k|        aiVector3D *vn = out->mNormals + out->mNumVertices;
  812|       |
  813|       |        // XXX we can't fold this easily, because we are restricted
  814|       |        // to the member names from the BLEND file (v1,v2,v3,v4)
  815|       |        // which are assigned by the genblenddna.py script and
  816|       |        // cannot be changed without breaking the entire
  817|       |        // import process.
  818|       |
  819|  7.48k|        if (mf.v1 >= mesh->totvert) {
  ------------------
  |  Branch (819:13): [True: 0, False: 7.48k]
  ------------------
  820|      0|            ThrowException("Vertex index v1 out of range");
  821|      0|        }
  822|  7.48k|        const MVert *v = &mesh->mvert[mf.v1];
  823|  7.48k|        vo->x = v->co[0];
  824|  7.48k|        vo->y = v->co[1];
  825|  7.48k|        vo->z = v->co[2];
  826|  7.48k|        vn->x = v->no[0];
  827|  7.48k|        vn->y = v->no[1];
  828|  7.48k|        vn->z = v->no[2];
  829|  7.48k|        f.mIndices[0] = out->mNumVertices++;
  830|  7.48k|        ++vo;
  831|  7.48k|        ++vn;
  832|       |
  833|       |        //  if (f.mNumIndices >= 2) {
  834|  7.48k|        if (mf.v2 >= mesh->totvert) {
  ------------------
  |  Branch (834:13): [True: 0, False: 7.48k]
  ------------------
  835|      0|            ThrowException("Vertex index v2 out of range");
  836|      0|        }
  837|  7.48k|        v = &mesh->mvert[mf.v2];
  838|  7.48k|        vo->x = v->co[0];
  839|  7.48k|        vo->y = v->co[1];
  840|  7.48k|        vo->z = v->co[2];
  841|  7.48k|        vn->x = v->no[0];
  842|  7.48k|        vn->y = v->no[1];
  843|  7.48k|        vn->z = v->no[2];
  844|  7.48k|        f.mIndices[1] = out->mNumVertices++;
  845|  7.48k|        ++vo;
  846|  7.48k|        ++vn;
  847|       |
  848|  7.48k|        if (mf.v3 >= mesh->totvert) {
  ------------------
  |  Branch (848:13): [True: 0, False: 7.48k]
  ------------------
  849|      0|            ThrowException("Vertex index v3 out of range");
  850|      0|        }
  851|       |        //  if (f.mNumIndices >= 3) {
  852|  7.48k|        v = &mesh->mvert[mf.v3];
  853|  7.48k|        vo->x = v->co[0];
  854|  7.48k|        vo->y = v->co[1];
  855|  7.48k|        vo->z = v->co[2];
  856|  7.48k|        vn->x = v->no[0];
  857|  7.48k|        vn->y = v->no[1];
  858|  7.48k|        vn->z = v->no[2];
  859|  7.48k|        f.mIndices[2] = out->mNumVertices++;
  860|  7.48k|        ++vo;
  861|  7.48k|        ++vn;
  862|       |
  863|  7.48k|        if (mf.v4 >= mesh->totvert) {
  ------------------
  |  Branch (863:13): [True: 0, False: 7.48k]
  ------------------
  864|      0|            ThrowException("Vertex index v4 out of range");
  865|      0|        }
  866|       |        //  if (f.mNumIndices >= 4) {
  867|  7.48k|        if (mf.v4) {
  ------------------
  |  Branch (867:13): [True: 7.32k, False: 161]
  ------------------
  868|  7.32k|            v = &mesh->mvert[mf.v4];
  869|  7.32k|            vo->x = v->co[0];
  870|  7.32k|            vo->y = v->co[1];
  871|  7.32k|            vo->z = v->co[2];
  872|  7.32k|            vn->x = v->no[0];
  873|  7.32k|            vn->y = v->no[1];
  874|  7.32k|            vn->z = v->no[2];
  875|  7.32k|            f.mIndices[3] = out->mNumVertices++;
  876|  7.32k|            ++vo;
  877|  7.32k|            ++vn;
  878|       |
  879|  7.32k|            out->mPrimitiveTypes |= aiPrimitiveType_POLYGON;
  880|  7.32k|        } else
  881|    161|            out->mPrimitiveTypes |= aiPrimitiveType_TRIANGLE;
  882|       |
  883|       |        //  }
  884|       |        //  }
  885|       |        //  }
  886|  7.48k|    }
  887|       |
  888|    721|    for (int i = 0; i < mesh->totpoly; ++i) {
  ------------------
  |  Branch (888:21): [True: 683, False: 38]
  ------------------
  889|       |
  890|    683|        const MPoly &mf = mesh->mpoly[i];
  891|       |
  892|    683|        aiMesh *const out = temp[mat_num_to_mesh_idx[mf.mat_nr]];
  893|    683|        aiFace &f = out->mFaces[out->mNumFaces++];
  894|       |
  895|    683|        f.mIndices = new unsigned int[f.mNumIndices = mf.totloop];
  896|    683|        aiVector3D *vo = out->mVertices + out->mNumVertices;
  897|    683|        aiVector3D *vn = out->mNormals + out->mNumVertices;
  898|       |
  899|       |        // XXX we can't fold this easily, because we are restricted
  900|       |        // to the member names from the BLEND file (v1,v2,v3,v4)
  901|       |        // which are assigned by the genblenddna.py script and
  902|       |        // cannot be changed without breaking the entire
  903|       |        // import process.
  904|  3.33k|        for (int j = 0; j < mf.totloop; ++j) {
  ------------------
  |  Branch (904:25): [True: 2.65k, False: 683]
  ------------------
  905|  2.65k|            const MLoop &loop = mesh->mloop[mf.loopstart + j];
  906|       |
  907|  2.65k|            if (loop.v >= mesh->totvert) {
  ------------------
  |  Branch (907:17): [True: 0, False: 2.65k]
  ------------------
  908|      0|                ThrowException("Vertex index out of range");
  909|      0|            }
  910|       |
  911|  2.65k|            const MVert &v = mesh->mvert[loop.v];
  912|       |
  913|  2.65k|            vo->x = v.co[0];
  914|  2.65k|            vo->y = v.co[1];
  915|  2.65k|            vo->z = v.co[2];
  916|  2.65k|            vn->x = v.no[0];
  917|  2.65k|            vn->y = v.no[1];
  918|  2.65k|            vn->z = v.no[2];
  919|  2.65k|            f.mIndices[j] = out->mNumVertices++;
  920|       |
  921|  2.65k|            ++vo;
  922|  2.65k|            ++vn;
  923|  2.65k|        }
  924|    683|        if (mf.totloop == 3) {
  ------------------
  |  Branch (924:13): [True: 76, False: 607]
  ------------------
  925|     76|            out->mPrimitiveTypes |= aiPrimitiveType_TRIANGLE;
  926|    607|        } else {
  927|    607|            out->mPrimitiveTypes |= aiPrimitiveType_POLYGON;
  928|    607|        }
  929|    683|    }
  930|       |
  931|       |    // TODO should we create the TextureUVMapping map in Convert<Material> to prevent redundant processing?
  932|       |
  933|       |    // create texture <-> uvname mapping for all materials
  934|       |    // key is texture number, value is data *
  935|     38|    typedef std::map<uint32_t, const MLoopUV *> TextureUVMapping;
  936|       |    // key is material number, value is the TextureUVMapping for the material
  937|     38|    typedef std::map<uint32_t, TextureUVMapping> MaterialTextureUVMappings;
  938|     38|    MaterialTextureUVMappings matTexUvMappings;
  939|     38|    const uint32_t maxMat = static_cast<uint32_t>(mesh->mat.size());
  940|     73|    for (uint32_t m = 0; m < maxMat; ++m) {
  ------------------
  |  Branch (940:26): [True: 35, False: 38]
  ------------------
  941|       |        // get material by index
  942|     35|        const std::shared_ptr<Material> pMat = mesh->mat[m];
  943|     35|        TextureUVMapping texuv;
  944|     35|        const uint32_t maxTex = sizeof(pMat->mtex) / sizeof(pMat->mtex[0]);
  945|    665|        for (uint32_t t = 0; t < maxTex; ++t) {
  ------------------
  |  Branch (945:30): [True: 630, False: 35]
  ------------------
  946|    630|            if (pMat->mtex[t] && pMat->mtex[t]->uvname[0]) {
  ------------------
  |  Branch (946:17): [True: 35, False: 595]
  |  Branch (946:34): [True: 2, False: 33]
  ------------------
  947|       |                // get the CustomData layer for given uvname and correct type
  948|      2|                const ElemBase *pLoop = getCustomDataLayerData(mesh->ldata, CD_MLOOPUV, pMat->mtex[t]->uvname);
  949|      2|                if (pLoop) {
  ------------------
  |  Branch (949:21): [True: 2, False: 0]
  ------------------
  950|      2|                    texuv.insert(std::make_pair(t, dynamic_cast<const MLoopUV *>(pLoop)));
  951|      2|                }
  952|      2|            }
  953|    630|        }
  954|     35|        if (texuv.size()) {
  ------------------
  |  Branch (954:13): [True: 1, False: 34]
  ------------------
  955|      1|            matTexUvMappings.insert(std::make_pair(m, texuv));
  956|      1|        }
  957|     35|    }
  958|       |
  959|       |    // collect texture coordinates, they're stored in a separate per-face buffer
  960|     38|    if (mesh->mtface || mesh->mloopuv) {
  ------------------
  |  Branch (960:9): [True: 4, False: 34]
  |  Branch (960:25): [True: 3, False: 31]
  ------------------
  961|      7|        if (mesh->totface > static_cast<int>(mesh->mtface.size())) {
  ------------------
  |  Branch (961:13): [True: 0, False: 7]
  ------------------
  962|      0|            ThrowException("Number of UV faces is larger than the corresponding UV face array (#1)");
  963|      0|        }
  964|     14|        for (std::vector<aiMesh *>::iterator it = temp->begin() + old; it != temp->end(); ++it) {
  ------------------
  |  Branch (964:72): [True: 7, False: 7]
  ------------------
  965|      7|            ai_assert(0 != (*it)->mNumVertices);
  966|      7|            ai_assert(0 != (*it)->mNumFaces);
  967|      7|            const auto itMatTexUvMapping = matTexUvMappings.find((*it)->mMaterialIndex);
  968|      7|            if (itMatTexUvMapping == matTexUvMappings.end()) {
  ------------------
  |  Branch (968:17): [True: 6, False: 1]
  ------------------
  969|       |                // default behaviour like before
  970|      6|                (*it)->mTextureCoords[0] = new aiVector3D[(*it)->mNumVertices];
  971|      6|            } else {
  972|       |                // create texture coords for every mapped tex
  973|      3|                for (uint32_t i = 0; i < itMatTexUvMapping->second.size(); ++i) {
  ------------------
  |  Branch (973:38): [True: 2, False: 1]
  ------------------
  974|      2|                    (*it)->mTextureCoords[i] = new aiVector3D[(*it)->mNumVertices];
  975|      2|                }
  976|      1|            }
  977|      7|            (*it)->mNumFaces = (*it)->mNumVertices = 0;
  978|      7|        }
  979|       |
  980|     21|        for (int i = 0; i < mesh->totface; ++i) {
  ------------------
  |  Branch (980:25): [True: 14, False: 7]
  ------------------
  981|     14|            const MTFace *v = &mesh->mtface[i];
  982|       |
  983|     14|            aiMesh *const out = temp[mat_num_to_mesh_idx[mesh->mface[i].mat_nr]];
  984|     14|            const aiFace &f = out->mFaces[out->mNumFaces++];
  985|       |
  986|     14|            aiVector3D *vo = &out->mTextureCoords[0][out->mNumVertices];
  987|     70|            for (unsigned int j = 0; j < f.mNumIndices; ++j, ++vo, ++out->mNumVertices) {
  ------------------
  |  Branch (987:38): [True: 56, False: 14]
  ------------------
  988|     56|                vo->x = v->uv[j][0];
  989|     56|                vo->y = v->uv[j][1];
  990|     56|            }
  991|     14|        }
  992|       |
  993|     58|        for (int i = 0; i < mesh->totpoly; ++i) {
  ------------------
  |  Branch (993:25): [True: 51, False: 7]
  ------------------
  994|     51|            const MPoly &v = mesh->mpoly[i];
  995|     51|            aiMesh *const out = temp[mat_num_to_mesh_idx[v.mat_nr]];
  996|     51|            const aiFace &f = out->mFaces[out->mNumFaces++];
  997|       |
  998|     51|            const auto itMatTexUvMapping = matTexUvMappings.find(v.mat_nr);
  999|     51|            if (itMatTexUvMapping == matTexUvMappings.end()) {
  ------------------
  |  Branch (999:17): [True: 50, False: 1]
  ------------------
 1000|       |                // old behavior
 1001|     50|                aiVector3D *vo = &out->mTextureCoords[0][out->mNumVertices];
 1002|    206|                for (unsigned int j = 0; j < f.mNumIndices; ++j, ++vo, ++out->mNumVertices) {
  ------------------
  |  Branch (1002:42): [True: 156, False: 50]
  ------------------
 1003|    156|                    const MLoopUV &uv = mesh->mloopuv[v.loopstart + j];
 1004|    156|                    vo->x = uv.uv[0];
 1005|    156|                    vo->y = uv.uv[1];
 1006|    156|                }
 1007|     50|            } else {
 1008|       |                // create textureCoords for every mapped tex
 1009|      3|                for (uint32_t m = 0; m < itMatTexUvMapping->second.size(); ++m) {
  ------------------
  |  Branch (1009:38): [True: 2, False: 1]
  ------------------
 1010|      2|                    const MLoopUV *tm = itMatTexUvMapping->second[m];
 1011|      2|                    aiVector3D *vo = &out->mTextureCoords[m][out->mNumVertices];
 1012|      2|                    uint32_t j = 0;
 1013|     10|                    for (; j < f.mNumIndices; ++j, ++vo) {
  ------------------
  |  Branch (1013:28): [True: 8, False: 2]
  ------------------
 1014|      8|                        const MLoopUV &uv = tm[v.loopstart + j];
 1015|      8|                        vo->x = uv.uv[0];
 1016|      8|                        vo->y = uv.uv[1];
 1017|      8|                    }
 1018|       |                    // only update written mNumVertices in last loop
 1019|       |                    // TODO why must the numVertices be incremented here?
 1020|      2|                    if (m == itMatTexUvMapping->second.size() - 1) {
  ------------------
  |  Branch (1020:25): [True: 1, False: 1]
  ------------------
 1021|      1|                        out->mNumVertices += j;
 1022|      1|                    }
 1023|      2|                }
 1024|      1|            }
 1025|     51|        }
 1026|      7|    }
 1027|       |
 1028|       |    // collect texture coordinates, old-style (marked as deprecated in current blender sources)
 1029|     38|    if (mesh->tface) {
  ------------------
  |  Branch (1029:9): [True: 0, False: 38]
  ------------------
 1030|      0|        if (mesh->totface > static_cast<int>(mesh->tface.size())) {
  ------------------
  |  Branch (1030:13): [True: 0, False: 0]
  ------------------
 1031|      0|            ThrowException("Number of faces is larger than the corresponding UV face array (#2)");
 1032|      0|        }
 1033|      0|        for (std::vector<aiMesh *>::iterator it = temp->begin() + old; it != temp->end(); ++it) {
  ------------------
  |  Branch (1033:72): [True: 0, False: 0]
  ------------------
 1034|      0|            ai_assert(0 != (*it)->mNumVertices);
 1035|      0|            ai_assert(0 != (*it)->mNumFaces);
 1036|       |
 1037|      0|            (*it)->mTextureCoords[0] = new aiVector3D[(*it)->mNumVertices];
 1038|      0|            (*it)->mNumFaces = (*it)->mNumVertices = 0;
 1039|      0|        }
 1040|       |
 1041|      0|        for (int i = 0; i < mesh->totface; ++i) {
  ------------------
  |  Branch (1041:25): [True: 0, False: 0]
  ------------------
 1042|      0|            const TFace *v = &mesh->tface[i];
 1043|       |
 1044|      0|            aiMesh *const out = temp[mat_num_to_mesh_idx[mesh->mface[i].mat_nr]];
 1045|      0|            const aiFace &f = out->mFaces[out->mNumFaces++];
 1046|       |
 1047|      0|            aiVector3D *vo = &out->mTextureCoords[0][out->mNumVertices];
 1048|      0|            for (unsigned int j = 0; j < f.mNumIndices; ++j, ++vo, ++out->mNumVertices) {
  ------------------
  |  Branch (1048:38): [True: 0, False: 0]
  ------------------
 1049|      0|                vo->x = v->uv[j][0];
 1050|      0|                vo->y = v->uv[j][1];
 1051|      0|            }
 1052|      0|        }
 1053|      0|    }
 1054|       |
 1055|       |    // collect vertex colors, stored separately as well
 1056|     38|    if (mesh->mcol || mesh->mloopcol) {
  ------------------
  |  Branch (1056:9): [True: 1, False: 37]
  |  Branch (1056:23): [True: 0, False: 37]
  ------------------
 1057|      1|        if (mesh->totface > static_cast<int>((mesh->mcol.size() / 4))) {
  ------------------
  |  Branch (1057:13): [True: 0, False: 1]
  ------------------
 1058|      0|            ThrowException("Number of faces is larger than the corresponding color face array");
 1059|      0|        }
 1060|      2|        for (std::vector<aiMesh *>::iterator it = temp->begin() + old; it != temp->end(); ++it) {
  ------------------
  |  Branch (1060:72): [True: 1, False: 1]
  ------------------
 1061|      1|            ai_assert(0 != (*it)->mNumVertices);
 1062|      1|            ai_assert(0 != (*it)->mNumFaces);
 1063|       |
 1064|      1|            (*it)->mColors[0] = new aiColor4D[(*it)->mNumVertices];
 1065|      1|            (*it)->mNumFaces = (*it)->mNumVertices = 0;
 1066|      1|        }
 1067|       |
 1068|      7|        for (int i = 0; i < mesh->totface; ++i) {
  ------------------
  |  Branch (1068:25): [True: 6, False: 1]
  ------------------
 1069|       |
 1070|      6|            aiMesh *const out = temp[mat_num_to_mesh_idx[mesh->mface[i].mat_nr]];
 1071|      6|            const aiFace &f = out->mFaces[out->mNumFaces++];
 1072|       |
 1073|      6|            aiColor4D *vo = &out->mColors[0][out->mNumVertices];
 1074|     30|            for (unsigned int n = 0; n < f.mNumIndices; ++n, ++vo, ++out->mNumVertices) {
  ------------------
  |  Branch (1074:38): [True: 24, False: 6]
  ------------------
 1075|     24|                const MCol *col = &mesh->mcol[(i << 2) + n];
 1076|       |
 1077|     24|                vo->r = col->r;
 1078|     24|                vo->g = col->g;
 1079|     24|                vo->b = col->b;
 1080|     24|                vo->a = col->a;
 1081|     24|            }
 1082|      6|            for (unsigned int n = f.mNumIndices; n < 4; ++n)
  ------------------
  |  Branch (1082:50): [True: 0, False: 6]
  ------------------
 1083|      0|                ;
 1084|      6|        }
 1085|       |
 1086|      1|        for (int i = 0; i < mesh->totpoly; ++i) {
  ------------------
  |  Branch (1086:25): [True: 0, False: 1]
  ------------------
 1087|      0|            const MPoly &v = mesh->mpoly[i];
 1088|      0|            aiMesh *const out = temp[mat_num_to_mesh_idx[v.mat_nr]];
 1089|      0|            const aiFace &f = out->mFaces[out->mNumFaces++];
 1090|       |
 1091|      0|            aiColor4D *vo = &out->mColors[0][out->mNumVertices];
 1092|      0|            const ai_real scaleZeroToOne = 1.f / 255.f;
 1093|      0|            for (unsigned int j = 0; j < f.mNumIndices; ++j, ++vo, ++out->mNumVertices) {
  ------------------
  |  Branch (1093:38): [True: 0, False: 0]
  ------------------
 1094|      0|                const MLoopCol &col = mesh->mloopcol[v.loopstart + j];
 1095|      0|                vo->r = ai_real(col.r) * scaleZeroToOne;
 1096|      0|                vo->g = ai_real(col.g) * scaleZeroToOne;
 1097|      0|                vo->b = ai_real(col.b) * scaleZeroToOne;
 1098|      0|                vo->a = ai_real(col.a) * scaleZeroToOne;
 1099|      0|            }
 1100|      0|        }
 1101|      1|    }
 1102|       |
 1103|     38|    return;
 1104|     38|}
_ZN6Assimp15BlenderImporter13ConvertCameraERKNS_7Blender5SceneEPKNS1_6ObjectEPKNS1_6CameraERNS1_14ConversionDataE:
 1107|     26|aiCamera *BlenderImporter::ConvertCamera(const Scene & /*in*/, const Object *obj, const Camera *cam, ConversionData & /*conv_data*/) {
 1108|     26|    std::unique_ptr<aiCamera> out(new aiCamera());
 1109|     26|    out->mName = obj->id.name + 2;
 1110|     26|    out->mPosition = aiVector3D(0.f, 0.f, 0.f);
 1111|     26|    out->mUp = aiVector3D(0.f, 1.f, 0.f);
 1112|     26|    out->mLookAt = aiVector3D(0.f, 0.f, -1.f);
 1113|     26|    if (cam->sensor_x && cam->lens) {
  ------------------
  |  Branch (1113:9): [True: 10, False: 16]
  |  Branch (1113:26): [True: 10, False: 0]
  ------------------
 1114|     10|        out->mHorizontalFOV = 2.f * std::atan2(cam->sensor_x, 2.f * cam->lens);
 1115|     10|    }
 1116|     26|    out->mClipPlaneNear = cam->clipsta;
 1117|     26|    out->mClipPlaneFar = cam->clipend;
 1118|       |
 1119|     26|    return out.release();
 1120|     26|}
_ZN6Assimp15BlenderImporter12ConvertLightERKNS_7Blender5SceneEPKNS1_6ObjectEPKNS1_4LampERNS1_14ConversionDataE:
 1123|     31|aiLight *BlenderImporter::ConvertLight(const Scene & /*in*/, const Object *obj, const Lamp *lamp, ConversionData & /*conv_data*/) {
 1124|     31|    std::unique_ptr<aiLight> out(new aiLight());
 1125|     31|    out->mName = obj->id.name + 2;
 1126|       |
 1127|     31|    switch (lamp->type) {
 1128|     29|    case Lamp::Type_Local:
  ------------------
  |  Branch (1128:5): [True: 29, False: 2]
  ------------------
 1129|     29|        out->mType = aiLightSource_POINT;
 1130|     29|        break;
 1131|      0|    case Lamp::Type_Spot:
  ------------------
  |  Branch (1131:5): [True: 0, False: 31]
  ------------------
 1132|      0|        out->mType = aiLightSource_SPOT;
 1133|       |
 1134|       |        // blender orients directional lights as facing toward -z
 1135|      0|        out->mDirection = aiVector3D(0.f, 0.f, -1.f);
 1136|      0|        out->mUp = aiVector3D(0.f, 1.f, 0.f);
 1137|       |
 1138|      0|        out->mAngleInnerCone = lamp->spotsize * (1.0f - lamp->spotblend);
 1139|      0|        out->mAngleOuterCone = lamp->spotsize;
 1140|      0|        break;
 1141|      0|    case Lamp::Type_Sun:
  ------------------
  |  Branch (1141:5): [True: 0, False: 31]
  ------------------
 1142|      0|        out->mType = aiLightSource_DIRECTIONAL;
 1143|       |
 1144|       |        // blender orients directional lights as facing toward -z
 1145|      0|        out->mDirection = aiVector3D(0.f, 0.f, -1.f);
 1146|      0|        out->mUp = aiVector3D(0.f, 1.f, 0.f);
 1147|      0|        break;
 1148|       |
 1149|      2|    case Lamp::Type_Area:
  ------------------
  |  Branch (1149:5): [True: 2, False: 29]
  ------------------
 1150|      2|        out->mType = aiLightSource_AREA;
 1151|       |
 1152|      2|        if (lamp->area_shape == 0) {
  ------------------
  |  Branch (1152:13): [True: 1, False: 1]
  ------------------
 1153|      1|            out->mSize = aiVector2D(lamp->area_size, lamp->area_size);
 1154|      1|        } else {
 1155|      1|            out->mSize = aiVector2D(lamp->area_size, lamp->area_sizey);
 1156|      1|        }
 1157|       |
 1158|       |        // blender orients directional lights as facing toward -z
 1159|      2|        out->mDirection = aiVector3D(0.f, 0.f, -1.f);
 1160|      2|        out->mUp = aiVector3D(0.f, 1.f, 0.f);
 1161|      2|        break;
 1162|       |
 1163|      0|    default:
  ------------------
  |  Branch (1163:5): [True: 0, False: 31]
  ------------------
 1164|      0|        break;
 1165|     31|    }
 1166|       |
 1167|     31|    out->mColorAmbient = aiColor3D(lamp->r, lamp->g, lamp->b) * lamp->energy;
 1168|     31|    out->mColorSpecular = aiColor3D(lamp->r, lamp->g, lamp->b) * lamp->energy;
 1169|     31|    out->mColorDiffuse = aiColor3D(lamp->r, lamp->g, lamp->b) * lamp->energy;
 1170|       |
 1171|       |    // If default values are supplied, compute the coefficients from light's max distance
 1172|       |    // Read this: https://imdoingitwrong.wordpress.com/2011/01/31/light-attenuation/
 1173|       |    //
 1174|     31|    if (lamp->constant_coefficient == 1.0f && lamp->linear_coefficient == 0.0f && lamp->quadratic_coefficient == 0.0f && lamp->dist > 0.0f) {
  ------------------
  |  Branch (1174:9): [True: 0, False: 31]
  |  Branch (1174:47): [True: 0, False: 0]
  |  Branch (1174:83): [True: 0, False: 0]
  |  Branch (1174:122): [True: 0, False: 0]
  ------------------
 1175|      0|        out->mAttenuationConstant = 1.0f;
 1176|      0|        out->mAttenuationLinear = 2.0f / lamp->dist;
 1177|      0|        out->mAttenuationQuadratic = 1.0f / (lamp->dist * lamp->dist);
 1178|     31|    } else {
 1179|     31|        out->mAttenuationConstant = lamp->constant_coefficient;
 1180|     31|        out->mAttenuationLinear = lamp->linear_coefficient;
 1181|     31|        out->mAttenuationQuadratic = lamp->quadratic_coefficient;
 1182|     31|    }
 1183|       |
 1184|     31|    return out.release();
 1185|     31|}
_ZN6Assimp15BlenderImporter11ConvertNodeERKNS_7Blender5SceneEPKNS1_6ObjectERNS1_14ConversionDataERK12aiMatrix4x4tIfE:
 1188|     95|aiNode *BlenderImporter::ConvertNode(const Scene &in, const Object *obj, ConversionData &conv_data, const aiMatrix4x4 &parentTransform) {
 1189|     95|    std::deque<const Object *> children;
 1190|    138|    for (ObjectSet::iterator it = conv_data.objects.begin(); it != conv_data.objects.end();) {
  ------------------
  |  Branch (1190:62): [True: 43, False: 95]
  ------------------
 1191|     43|        const Object *object = *it;
 1192|     43|        if (object->parent == obj) {
  ------------------
  |  Branch (1192:13): [True: 6, False: 37]
  ------------------
 1193|      6|            children.push_back(object);
 1194|       |
 1195|      6|            conv_data.objects.erase(it++);
 1196|      6|            continue;
 1197|      6|        }
 1198|     37|        ++it;
 1199|     37|    }
 1200|       |
 1201|     95|    std::unique_ptr<aiNode> node(new aiNode(obj->id.name + 2)); // skip over the name prefix 'OB'
 1202|     95|    if (obj->data) {
  ------------------
  |  Branch (1202:9): [True: 95, False: 0]
  ------------------
 1203|     95|        switch (obj->type) {
 1204|      0|        case Object ::Type_EMPTY:
  ------------------
  |  Branch (1204:9): [True: 0, False: 95]
  ------------------
 1205|      0|            break; // do nothing
 1206|       |
 1207|       |            // supported object types
 1208|     38|        case Object ::Type_MESH: {
  ------------------
  |  Branch (1208:9): [True: 38, False: 57]
  ------------------
 1209|     38|            const size_t old = conv_data.meshes->size();
 1210|       |
 1211|     38|            CheckActualType(obj->data.get(), "Mesh");
 1212|     38|            ConvertMesh(in, obj, static_cast<const Mesh *>(obj->data.get()), conv_data, conv_data.meshes);
 1213|       |
 1214|     38|            if (conv_data.meshes->size() > old) {
  ------------------
  |  Branch (1214:17): [True: 38, False: 0]
  ------------------
 1215|     38|                node->mMeshes = new unsigned int[node->mNumMeshes = static_cast<unsigned int>(conv_data.meshes->size() - old)];
 1216|     77|                for (unsigned int i = 0; i < node->mNumMeshes; ++i) {
  ------------------
  |  Branch (1216:42): [True: 39, False: 38]
  ------------------
 1217|     39|                    node->mMeshes[i] = static_cast<unsigned int>(i + old);
 1218|     39|                }
 1219|     38|            }
 1220|     38|        } break;
 1221|     31|        case Object ::Type_LAMP: {
  ------------------
  |  Branch (1221:9): [True: 31, False: 64]
  ------------------
 1222|     31|            CheckActualType(obj->data.get(), "Lamp");
 1223|     31|            aiLight *mesh = ConvertLight(in, obj, static_cast<const Lamp *>(obj->data.get()), conv_data);
 1224|       |
 1225|     31|            if (mesh) {
  ------------------
  |  Branch (1225:17): [True: 31, False: 0]
  ------------------
 1226|     31|                conv_data.lights->push_back(mesh);
 1227|     31|            }
 1228|     31|        } break;
 1229|     26|        case Object ::Type_CAMERA: {
  ------------------
  |  Branch (1229:9): [True: 26, False: 69]
  ------------------
 1230|     26|            CheckActualType(obj->data.get(), "Camera");
 1231|     26|            aiCamera *mesh = ConvertCamera(in, obj, static_cast<const Camera *>(obj->data.get()), conv_data);
 1232|       |
 1233|     26|            if (mesh) {
  ------------------
  |  Branch (1233:17): [True: 26, False: 0]
  ------------------
 1234|     26|                conv_data.cameras->push_back(mesh);
 1235|     26|            }
 1236|     26|        } break;
 1237|       |
 1238|       |            // unsupported object types / log, but do not break
 1239|      0|        case Object ::Type_CURVE:
  ------------------
  |  Branch (1239:9): [True: 0, False: 95]
  ------------------
 1240|      0|            NotSupportedObjectType(obj, "Curve");
 1241|      0|            break;
 1242|      0|        case Object ::Type_SURF:
  ------------------
  |  Branch (1242:9): [True: 0, False: 95]
  ------------------
 1243|      0|            NotSupportedObjectType(obj, "Surface");
 1244|      0|            break;
 1245|      0|        case Object ::Type_FONT:
  ------------------
  |  Branch (1245:9): [True: 0, False: 95]
  ------------------
 1246|      0|            NotSupportedObjectType(obj, "Font");
 1247|      0|            break;
 1248|      0|        case Object ::Type_MBALL:
  ------------------
  |  Branch (1248:9): [True: 0, False: 95]
  ------------------
 1249|      0|            NotSupportedObjectType(obj, "MetaBall");
 1250|      0|            break;
 1251|      0|        case Object ::Type_WAVE:
  ------------------
  |  Branch (1251:9): [True: 0, False: 95]
  ------------------
 1252|      0|            NotSupportedObjectType(obj, "Wave");
 1253|      0|            break;
 1254|      0|        case Object ::Type_LATTICE:
  ------------------
  |  Branch (1254:9): [True: 0, False: 95]
  ------------------
 1255|      0|            NotSupportedObjectType(obj, "Lattice");
 1256|      0|            break;
 1257|       |
 1258|       |            // invalid or unknown type
 1259|      0|        default:
  ------------------
  |  Branch (1259:9): [True: 0, False: 95]
  ------------------
 1260|      0|            break;
 1261|     95|        }
 1262|     95|    }
 1263|       |
 1264|    475|    for (unsigned int x = 0; x < 4; ++x) {
  ------------------
  |  Branch (1264:30): [True: 380, False: 95]
  ------------------
 1265|  1.90k|        for (unsigned int y = 0; y < 4; ++y) {
  ------------------
  |  Branch (1265:34): [True: 1.52k, False: 380]
  ------------------
 1266|  1.52k|            node->mTransformation[y][x] = obj->obmat[x][y];
 1267|  1.52k|        }
 1268|    380|    }
 1269|       |
 1270|     95|    aiMatrix4x4 m = parentTransform;
 1271|     95|    m = m.Inverse();
 1272|       |
 1273|     95|    node->mTransformation = m * node->mTransformation;
 1274|       |
 1275|     95|    if (children.size()) {
  ------------------
  |  Branch (1275:9): [True: 4, False: 91]
  ------------------
 1276|      4|        node->mNumChildren = static_cast<unsigned int>(children.size());
 1277|      4|        aiNode **nd = node->mChildren = new aiNode *[node->mNumChildren]();
 1278|      6|        for (const Object *nobj : children) {
  ------------------
  |  Branch (1278:33): [True: 6, False: 4]
  ------------------
 1279|      6|            *nd = ConvertNode(in, nobj, conv_data, node->mTransformation * parentTransform);
 1280|      6|            (*nd++)->mParent = node.get();
 1281|      6|        }
 1282|      4|    }
 1283|       |
 1284|       |    // apply modifiers
 1285|     95|    modifier_cache->ApplyModifiers(*node, conv_data, in, *obj);
 1286|       |
 1287|     95|    return node.release();
 1288|     95|}
_ZNK6Assimp15BlenderImporter15ParseMagicTokenERKNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEPNS_8IOSystemE:
 1290|    131|BlenderImporter::StreamOrError BlenderImporter::ParseMagicToken(const std::string &pFile, IOSystem *pIOHandler) const {
 1291|    131|    std::shared_ptr<IOStream> stream(pIOHandler->Open(pFile, "rb"));
 1292|    131|    if (stream == nullptr) {
  ------------------
  |  Branch (1292:9): [True: 0, False: 131]
  ------------------
 1293|      0|        return {{}, {}, "Could not open file for reading"};
 1294|      0|    }
 1295|       |
 1296|    131|    char magic[8] = { 0 };
 1297|    131|    stream->Read(magic, 7, 1);
 1298|    131|    if (strcmp(magic, Token) == 0) {
  ------------------
  |  Branch (1298:9): [True: 56, False: 75]
  ------------------
 1299|     56|        return {stream, {}, {}};
 1300|     56|    }
 1301|       |
 1302|       |    // Check for presence of the gzip header. If yes, assume it is a
 1303|       |    // compressed blend file and try uncompressing it, else fail. This is to
 1304|       |    // avoid uncompressing random files which our loader might end up with.
 1305|       |#ifdef ASSIMP_BUILD_NO_COMPRESSED_BLEND
 1306|       |    return {{}, {}, "BLENDER magic bytes are missing, is this file compressed (Assimp was built without decompression support)?"};
 1307|       |#else
 1308|     75|    if (magic[0] != 0x1f || static_cast<uint8_t>(magic[1]) != 0x8b) {
  ------------------
  |  Branch (1308:9): [True: 57, False: 18]
  |  Branch (1308:29): [True: 0, False: 18]
  ------------------
 1309|     57|        return {{}, {}, "BLENDER magic bytes are missing, couldn't find GZIP header either"};
 1310|     57|    }
 1311|       |
 1312|     18|    LogDebug("Found no BLENDER magic word but a GZIP header, might be a compressed file");
 1313|     18|    if (magic[2] != 8) {
  ------------------
  |  Branch (1313:9): [True: 0, False: 18]
  ------------------
 1314|      0|        return {{}, {}, "Unsupported GZIP compression method"};
 1315|      0|    }
 1316|       |
 1317|       |    // http://www.gzip.org/zlib/rfc-gzip.html#header-trailer
 1318|     18|    stream->Seek(0L, aiOrigin_SET);
 1319|     18|    std::shared_ptr<StreamReaderLE> reader = std::shared_ptr<StreamReaderLE>(new StreamReaderLE(stream));
 1320|       |
 1321|     18|    size_t total = 0;
 1322|     18|    Compression compression;
 1323|     18|    auto uncompressed = std::make_shared<std::vector<char>>();
 1324|     18|    if (compression.open(Compression::Format::Binary, Compression::FlushMode::NoFlush, 16 + Compression::MaxWBits)) {
  ------------------
  |  Branch (1324:9): [True: 18, False: 0]
  ------------------
 1325|     18|        total = compression.decompress((unsigned char *)reader->GetPtr(), reader->GetRemainingSize(), *uncompressed);
 1326|     18|        compression.close();
 1327|     18|    }
 1328|       |
 1329|       |    // replace the input stream with a memory stream
 1330|     18|    stream = std::make_shared<MemoryIOStream>(reinterpret_cast<uint8_t *>(uncompressed->data()), total);
 1331|       |
 1332|       |    // .. and retry
 1333|     18|    stream->Read(magic, 7, 1);
 1334|     18|    if (strcmp(magic, Token) == 0) {
  ------------------
  |  Branch (1334:9): [True: 8, False: 10]
  ------------------
 1335|      8|        return {stream, uncompressed, {}};
 1336|      8|    }
 1337|     10|    return {{}, {}, "Found no BLENDER magic word in decompressed GZIP file"};
 1338|     18|#endif
 1339|     18|}

_ZN6Assimp7Blender23BlenderModifierShowcase14ApplyModifiersER6aiNodeRNS0_14ConversionDataERKNS0_5SceneERKNS0_6ObjectE:
   75|     95|void BlenderModifierShowcase::ApplyModifiers(aiNode &out, ConversionData &conv_data, const Scene &in, const Object &orig_object) {
   76|     95|    size_t cnt = 0u, ful = 0u;
   77|       |
   78|       |    // NOTE: this cast is potentially unsafe by design, so we need to perform type checks before
   79|       |    // we're allowed to dereference the pointers without risking to crash. We might still be
   80|       |    // invoking UB btw - we're assuming that the ModifierData member of the respective modifier
   81|       |    // structures is at offset sizeof(vftable) with no padding.
   82|     95|    const SharedModifierData *cur = static_cast<const SharedModifierData *>(orig_object.modifiers.first.get());
   83|    101|    for (; cur; cur = static_cast<const SharedModifierData *>(cur->modifier.next.get()), ++ful) {
  ------------------
  |  Branch (83:12): [True: 6, False: 95]
  ------------------
   84|      6|        ai_assert(cur->dna_type);
   85|       |
   86|      6|        const Structure *s = conv_data.db.dna.Get(cur->dna_type);
   87|      6|        if (!s) {
  ------------------
  |  Branch (87:13): [True: 0, False: 6]
  ------------------
   88|      0|            ASSIMP_LOG_WARN("BlendModifier: could not resolve DNA name: ", cur->dna_type);
   89|      0|            continue;
   90|      0|        }
   91|       |
   92|       |        // this is a common trait of all XXXMirrorData structures in BlenderDNA
   93|      6|        const Field *f = s->Get("modifier");
   94|      6|        if (!f || f->offset != 0) {
  ------------------
  |  Branch (94:13): [True: 0, False: 6]
  |  Branch (94:19): [True: 0, False: 6]
  ------------------
   95|      0|            ASSIMP_LOG_WARN("BlendModifier: expected a `modifier` member at offset 0");
   96|      0|            continue;
   97|      0|        }
   98|       |
   99|      6|        s = conv_data.db.dna.Get(f->type);
  100|      6|        if (!s || s->name != "ModifierData") {
  ------------------
  |  Branch (100:13): [True: 0, False: 6]
  |  Branch (100:19): [True: 0, False: 6]
  ------------------
  101|      0|            ASSIMP_LOG_WARN("BlendModifier: expected a ModifierData structure as first member");
  102|      0|            continue;
  103|      0|        }
  104|       |
  105|       |        // now, we can be sure that we should be fine to dereference *cur* as
  106|       |        // ModifierData (with the above note).
  107|      6|        const ModifierData &dat = cur->modifier;
  108|       |
  109|      6|        const fpCreateModifier *curgod = creators;
  110|      6|        std::vector<BlenderModifier *>::iterator curmod = cached_modifiers->begin(), endmod = cached_modifiers->end();
  111|       |
  112|     10|        for (; *curgod; ++curgod, ++curmod) { // allocate modifiers on the fly
  ------------------
  |  Branch (112:16): [True: 10, False: 0]
  ------------------
  113|     10|            if (curmod == endmod) {
  ------------------
  |  Branch (113:17): [True: 9, False: 1]
  ------------------
  114|      9|                cached_modifiers->push_back((*curgod)());
  115|       |
  116|      9|                endmod = cached_modifiers->end();
  117|      9|                curmod = endmod - 1;
  118|      9|            }
  119|       |
  120|     10|            BlenderModifier *const modifier = *curmod;
  121|     10|            if (modifier->IsActive(dat)) {
  ------------------
  |  Branch (121:17): [True: 6, False: 4]
  ------------------
  122|      6|                modifier->DoIt(out, conv_data, *static_cast<const ElemBase *>(cur), in, orig_object);
  123|      6|                cnt++;
  124|       |
  125|      6|                curgod = nullptr;
  126|      6|                break;
  127|      6|            }
  128|     10|        }
  129|      6|        if (curgod) {
  ------------------
  |  Branch (129:13): [True: 0, False: 6]
  ------------------
  130|      0|            ASSIMP_LOG_WARN("Couldn't find a handler for modifier: ", dat.name);
  131|      0|        }
  132|      6|    }
  133|       |
  134|       |    // Even though we managed to resolve some or all of the modifiers on this
  135|       |    // object, we still can't say whether our modifier implementations were
  136|       |    // able to fully do their job.
  137|     95|    if (ful) {
  ------------------
  |  Branch (137:9): [True: 5, False: 90]
  ------------------
  138|       |        ASSIMP_LOG_DEBUG("BlendModifier: found handlers for ", cnt, " of ", ful, " modifiers on `", orig_object.id.name,
  139|      5|                "`, check log messages above for errors");
  140|      5|    }
  141|     95|}
_ZN6Assimp7Blender22BlenderModifier_Mirror8IsActiveERKNS0_12ModifierDataE:
  144|      6|bool BlenderModifier_Mirror ::IsActive(const ModifierData &modin) {
  145|      6|    return modin.type == ModifierData::eModifierType_Mirror;
  146|      6|}
_ZN6Assimp7Blender22BlenderModifier_Mirror4DoItER6aiNodeRNS0_14ConversionDataERKNS0_8ElemBaseERKNS0_5SceneERKNS0_6ObjectE:
  151|      2|        const Object &orig_object) {
  152|       |    // hijacking the ABI, see the big note in BlenderModifierShowcase::ApplyModifiers()
  153|      2|    const MirrorModifierData &mir = static_cast<const MirrorModifierData &>(orig_modifier);
  154|      2|    ai_assert(mir.modifier.type == ModifierData::eModifierType_Mirror);
  155|      2|    std::shared_ptr<Object> mirror_ob = mir.mirror_ob.lock();
  156|       |
  157|      2|    conv_data.meshes->reserve(conv_data.meshes->size() + out.mNumMeshes);
  158|       |
  159|       |    // XXX not entirely correct, mirroring on two axes results in 4 distinct objects in blender ...
  160|       |
  161|       |    // take all input meshes and clone them
  162|      4|    for (unsigned int i = 0; i < out.mNumMeshes; ++i) {
  ------------------
  |  Branch (162:30): [True: 2, False: 2]
  ------------------
  163|      2|        aiMesh *mesh;
  164|      2|        SceneCombiner::Copy(&mesh, conv_data.meshes[out.mMeshes[i]]);
  165|       |
  166|      2|        const float xs = mir.flag & MirrorModifierData::Flags_AXIS_X ? -1.f : 1.f;
  ------------------
  |  Branch (166:26): [True: 2, False: 0]
  ------------------
  167|      2|        const float ys = mir.flag & MirrorModifierData::Flags_AXIS_Y ? -1.f : 1.f;
  ------------------
  |  Branch (167:26): [True: 1, False: 1]
  ------------------
  168|      2|        const float zs = mir.flag & MirrorModifierData::Flags_AXIS_Z ? -1.f : 1.f;
  ------------------
  |  Branch (168:26): [True: 1, False: 1]
  ------------------
  169|       |
  170|      2|        if (mirror_ob) {
  ------------------
  |  Branch (170:13): [True: 1, False: 1]
  ------------------
  171|      1|            const aiVector3D center(mirror_ob->obmat[3][0], mirror_ob->obmat[3][1], mirror_ob->obmat[3][2]);
  172|     25|            for (unsigned int j = 0; j < mesh->mNumVertices; ++j) {
  ------------------
  |  Branch (172:38): [True: 24, False: 1]
  ------------------
  173|     24|                aiVector3D &v = mesh->mVertices[j];
  174|       |
  175|     24|                v.x = center.x + xs * (center.x - v.x);
  176|     24|                v.y = center.y + ys * (center.y - v.y);
  177|     24|                v.z = center.z + zs * (center.z - v.z);
  178|     24|            }
  179|      1|        } else {
  180|    536|            for (unsigned int j = 0; j < mesh->mNumVertices; ++j) {
  ------------------
  |  Branch (180:38): [True: 535, False: 1]
  ------------------
  181|    535|                aiVector3D &v = mesh->mVertices[j];
  182|    535|                v.x *= xs;
  183|    535|                v.y *= ys;
  184|    535|                v.z *= zs;
  185|    535|            }
  186|      1|        }
  187|       |
  188|      2|        if (mesh->mNormals) {
  ------------------
  |  Branch (188:13): [True: 2, False: 0]
  ------------------
  189|    561|            for (unsigned int j = 0; j < mesh->mNumVertices; ++j) {
  ------------------
  |  Branch (189:38): [True: 559, False: 2]
  ------------------
  190|    559|                aiVector3D &v = mesh->mNormals[j];
  191|    559|                v.x *= xs;
  192|    559|                v.y *= ys;
  193|    559|                v.z *= zs;
  194|    559|            }
  195|      2|        }
  196|       |
  197|      2|        if (mesh->mTangents) {
  ------------------
  |  Branch (197:13): [True: 0, False: 2]
  ------------------
  198|      0|            for (unsigned int j = 0; j < mesh->mNumVertices; ++j) {
  ------------------
  |  Branch (198:38): [True: 0, False: 0]
  ------------------
  199|      0|                aiVector3D &v = mesh->mTangents[j];
  200|      0|                v.x *= xs;
  201|      0|                v.y *= ys;
  202|      0|                v.z *= zs;
  203|      0|            }
  204|      0|        }
  205|       |
  206|      2|        if (mesh->mBitangents) {
  ------------------
  |  Branch (206:13): [True: 0, False: 2]
  ------------------
  207|      0|            for (unsigned int j = 0; j < mesh->mNumVertices; ++j) {
  ------------------
  |  Branch (207:38): [True: 0, False: 0]
  ------------------
  208|      0|                aiVector3D &v = mesh->mBitangents[j];
  209|      0|                v.x *= xs;
  210|      0|                v.y *= ys;
  211|      0|                v.z *= zs;
  212|      0|            }
  213|      0|        }
  214|       |
  215|      2|        const float us = mir.flag & MirrorModifierData::Flags_MIRROR_U ? -1.f : 1.f;
  ------------------
  |  Branch (215:26): [True: 0, False: 2]
  ------------------
  216|      2|        const float vs = mir.flag & MirrorModifierData::Flags_MIRROR_V ? -1.f : 1.f;
  ------------------
  |  Branch (216:26): [True: 0, False: 2]
  ------------------
  217|       |
  218|      2|        for (unsigned int n = 0; mesh->HasTextureCoords(n); ++n) {
  ------------------
  |  Branch (218:34): [True: 0, False: 2]
  ------------------
  219|      0|            for (unsigned int j = 0; j < mesh->mNumVertices; ++j) {
  ------------------
  |  Branch (219:38): [True: 0, False: 0]
  ------------------
  220|      0|                aiVector3D &v = mesh->mTextureCoords[n][j];
  221|      0|                v.x *= us;
  222|      0|                v.y *= vs;
  223|      0|            }
  224|      0|        }
  225|       |
  226|       |        // Only reverse the winding order if an odd number of axes were mirrored.
  227|      2|        if (xs * ys * zs < 0) {
  ------------------
  |  Branch (227:13): [True: 2, False: 0]
  ------------------
  228|    142|            for (unsigned int j = 0; j < mesh->mNumFaces; ++j) {
  ------------------
  |  Branch (228:38): [True: 140, False: 2]
  ------------------
  229|    140|                aiFace &face = mesh->mFaces[j];
  230|    419|                for (unsigned int fi = 0; fi < face.mNumIndices / 2; ++fi)
  ------------------
  |  Branch (230:43): [True: 279, False: 140]
  ------------------
  231|    279|                    std::swap(face.mIndices[fi], face.mIndices[face.mNumIndices - 1 - fi]);
  232|    140|            }
  233|      2|        }
  234|       |
  235|      2|        conv_data.meshes->push_back(mesh);
  236|      2|    }
  237|      2|    unsigned int *nind = new unsigned int[out.mNumMeshes * 2];
  238|       |
  239|      2|    std::copy(out.mMeshes, out.mMeshes + out.mNumMeshes, nind);
  240|      2|    std::transform(out.mMeshes, out.mMeshes + out.mNumMeshes, nind + out.mNumMeshes,
  241|      2|            [&out](unsigned int n) { return out.mNumMeshes + n; });
  242|       |
  243|      2|    delete[] out.mMeshes;
  244|      2|    out.mMeshes = nind;
  245|      2|    out.mNumMeshes *= 2;
  246|       |
  247|       |    ASSIMP_LOG_INFO("BlendModifier: Applied the `Mirror` modifier to `",
  248|      2|            orig_object.id.name, "`");
  249|      2|}
_ZN6Assimp7Blender27BlenderModifier_Subdivision8IsActiveERKNS0_12ModifierDataE:
  252|      4|bool BlenderModifier_Subdivision ::IsActive(const ModifierData &modin) {
  253|      4|    return modin.type == ModifierData::eModifierType_Subsurf;
  254|      4|}
_ZN6Assimp7Blender27BlenderModifier_Subdivision4DoItER6aiNodeRNS0_14ConversionDataERKNS0_8ElemBaseERKNS0_5SceneERKNS0_6ObjectE:
  259|      4|        const Object &orig_object) {
  260|       |    // hijacking the ABI, see the big note in BlenderModifierShowcase::ApplyModifiers()
  261|      4|    const SubsurfModifierData &mir = static_cast<const SubsurfModifierData &>(orig_modifier);
  262|      4|    ai_assert(mir.modifier.type == ModifierData::eModifierType_Subsurf);
  263|       |
  264|      4|    Subdivider::Algorithm algo;
  265|      4|    switch (mir.subdivType) {
  266|      4|    case SubsurfModifierData::TYPE_CatmullClarke:
  ------------------
  |  Branch (266:5): [True: 4, False: 0]
  ------------------
  267|      4|        algo = Subdivider::CATMULL_CLARKE;
  268|      4|        break;
  269|       |
  270|      0|    case SubsurfModifierData::TYPE_Simple:
  ------------------
  |  Branch (270:5): [True: 0, False: 4]
  ------------------
  271|      0|        ASSIMP_LOG_WARN("BlendModifier: The `SIMPLE` subdivision algorithm is not currently implemented, using Catmull-Clarke");
  272|      0|        algo = Subdivider::CATMULL_CLARKE;
  273|      0|        break;
  274|       |
  275|      0|    default:
  ------------------
  |  Branch (275:5): [True: 0, False: 4]
  ------------------
  276|      0|        ASSIMP_LOG_WARN("BlendModifier: Unrecognized subdivision algorithm: ", mir.subdivType);
  277|      0|        return;
  278|      4|    };
  279|       |
  280|      4|    std::unique_ptr<Subdivider> subd(Subdivider::Create(algo));
  281|      4|    ai_assert(subd);
  282|      4|    if (conv_data.meshes->empty()) {
  ------------------
  |  Branch (282:9): [True: 0, False: 4]
  ------------------
  283|      0|        return;
  284|      0|    }
  285|      4|    const size_t meshIndex = conv_data.meshes->size() - out.mNumMeshes;
  286|      4|    if (meshIndex >= conv_data.meshes->size()) {
  ------------------
  |  Branch (286:9): [True: 0, False: 4]
  ------------------
  287|      0|        ASSIMP_LOG_ERROR("Invalid index detected.");
  288|      0|        return;
  289|      0|    }
  290|      4|    aiMesh **const meshes = &conv_data.meshes[conv_data.meshes->size() - out.mNumMeshes];
  291|      4|    std::unique_ptr<aiMesh *[]> tempmeshes(new aiMesh *[out.mNumMeshes]());
  292|       |
  293|      4|    subd->Subdivide(meshes, out.mNumMeshes, tempmeshes.get(), std::max(mir.renderLevels, mir.levels), true);
  294|      4|    std::copy(tempmeshes.get(), tempmeshes.get() + out.mNumMeshes, meshes);
  295|       |
  296|       |    ASSIMP_LOG_INFO("BlendModifier: Applied the `Subdivision` modifier to `",
  297|      4|            orig_object.id.name, "`");
  298|      4|}
_Z3godIN6Assimp7Blender22BlenderModifier_MirrorEEPNS1_15BlenderModifierEv:
   60|      5|BlenderModifier *god() {
   61|      5|    return new T();
   62|      5|}
_Z3godIN6Assimp7Blender27BlenderModifier_SubdivisionEEPNS1_15BlenderModifierEv:
   60|      4|BlenderModifier *god() {
   61|      4|    return new T();
   62|      4|}
BlenderModifier.cpp:_ZZN6Assimp7Blender22BlenderModifier_Mirror4DoItER6aiNodeRNS0_14ConversionDataERKNS0_8ElemBaseERKNS0_5SceneERKNS0_6ObjectEENK3$_0clEj:
  241|      2|            [&out](unsigned int n) { return out.mNumMeshes + n; });

_ZN6Assimp7Blender15BlenderModifierD2Ev:
   64|      9|    virtual ~BlenderModifier() = default;

_ZNK6Assimp7Blender9Structure7ConvertINS0_6ObjectEEEvRT_RKNS0_12FileDatabaseE:
   59|    100|        const FileDatabase &db) const {
   60|       |
   61|    100|    ReadField<ErrorPolicy_Fail>(dest.id, "id", db);
   62|    100|    int temp = 0;
   63|    100|    ReadField<ErrorPolicy_Fail>(temp, "type", db);
   64|    100|    dest.type = static_cast<Assimp::Blender::Object::Type>(temp);
   65|    100|    ReadFieldArray2<ErrorPolicy_Warn>(dest.obmat, "obmat", db);
   66|    100|    ReadFieldArray2<ErrorPolicy_Warn>(dest.parentinv, "parentinv", db);
   67|    100|    ReadFieldArray<ErrorPolicy_Warn>(dest.parsubstr, "parsubstr", db);
   68|    100|    {
   69|    100|        std::shared_ptr<Object> parent;
   70|    100|        ReadFieldPtr<ErrorPolicy_Warn>(parent, "*parent", db);
   71|    100|        dest.parent = parent.get();
   72|    100|    }
   73|    100|    ReadFieldPtr<ErrorPolicy_Warn>(dest.track, "*track", db);
   74|    100|    ReadFieldPtr<ErrorPolicy_Warn>(dest.proxy, "*proxy", db);
   75|    100|    ReadFieldPtr<ErrorPolicy_Warn>(dest.proxy_from, "*proxy_from", db);
   76|    100|    ReadFieldPtr<ErrorPolicy_Warn>(dest.proxy_group, "*proxy_group", db);
   77|    100|    ReadFieldPtr<ErrorPolicy_Warn>(dest.dup_group, "*dup_group", db);
   78|    100|    ReadFieldPtr<ErrorPolicy_Fail>(dest.data, "*data", db);
   79|    100|    ReadField<ErrorPolicy_Igno>(dest.modifiers, "modifiers", db);
   80|       |
   81|    100|    db.reader->IncPtr(size);
   82|    100|}
_ZNK6Assimp7Blender9Structure7ConvertINS0_16CollectionObjectEEEvRT_RKNS0_12FileDatabaseE:
  101|      3|        const FileDatabase &db) const {
  102|       |
  103|      3|    ReadFieldPtr<ErrorPolicy_Fail>(dest.next, "*next", db);
  104|      3|    {
  105|      3|        std::shared_ptr<Object> ob;
  106|      3|        ReadFieldPtr<ErrorPolicy_Igno>(ob, "*ob", db);
  107|      3|        dest.ob = ob.get();
  108|      3|    }
  109|       |
  110|      3|    db.reader->IncPtr(size);
  111|      3|}
_ZNK6Assimp7Blender9Structure7ConvertINS0_15CollectionChildEEEvRT_RKNS0_12FileDatabaseE:
  117|      1|        const FileDatabase &db) const {
  118|       |
  119|      1|    ReadFieldPtr<ErrorPolicy_Fail>(dest.prev, "*prev", db);
  120|      1|    ReadFieldPtr<ErrorPolicy_Fail>(dest.next, "*next", db);
  121|      1|    ReadFieldPtr<ErrorPolicy_Igno>(dest.collection, "*collection", db);
  122|       |
  123|      1|    db.reader->IncPtr(size);
  124|      1|}
_ZNK6Assimp7Blender9Structure7ConvertINS0_10CollectionEEEvRT_RKNS0_12FileDatabaseE:
  130|      2|        const FileDatabase &db) const {
  131|       |
  132|      2|    ReadField<ErrorPolicy_Fail>(dest.id, "id", db);
  133|      2|    ReadField<ErrorPolicy_Fail>(dest.gobject, "gobject", db);
  134|      2|    ReadField<ErrorPolicy_Fail>(dest.children, "children", db);
  135|       |
  136|      2|    db.reader->IncPtr(size);
  137|      2|}
_ZNK6Assimp7Blender9Structure7ConvertINS0_4MTexEEEvRT_RKNS0_12FileDatabaseE:
  143|     28|        const FileDatabase &db) const {
  144|       |
  145|     28|    int temp_short = 0;
  146|     28|    ReadField<ErrorPolicy_Igno>(temp_short, "mapto", db);
  147|     28|    dest.mapto = static_cast<Assimp::Blender::MTex::MapType>(temp_short);
  148|     28|    int temp = 0;
  149|     28|    ReadField<ErrorPolicy_Igno>(temp, "blendtype", db);
  150|     28|    dest.blendtype = static_cast<Assimp::Blender::MTex::BlendType>(temp);
  151|     28|    ReadFieldPtr<ErrorPolicy_Igno>(dest.object, "*object", db);
  152|     28|    ReadFieldPtr<ErrorPolicy_Igno>(dest.tex, "*tex", db);
  153|     28|    ReadFieldArray<ErrorPolicy_Igno>(dest.uvname, "uvname", db);
  154|     28|    ReadField<ErrorPolicy_Igno>(temp, "projx", db);
  155|     28|    dest.projx = static_cast<Assimp::Blender::MTex::Projection>(temp);
  156|     28|    ReadField<ErrorPolicy_Igno>(temp, "projy", db);
  157|     28|    dest.projy = static_cast<Assimp::Blender::MTex::Projection>(temp);
  158|     28|    ReadField<ErrorPolicy_Igno>(temp, "projz", db);
  159|     28|    dest.projz = static_cast<Assimp::Blender::MTex::Projection>(temp);
  160|     28|    ReadField<ErrorPolicy_Igno>(dest.mapping, "mapping", db);
  161|     28|    ReadFieldArray<ErrorPolicy_Igno>(dest.ofs, "ofs", db);
  162|     28|    ReadFieldArray<ErrorPolicy_Igno>(dest.size, "size", db);
  163|     28|    ReadField<ErrorPolicy_Igno>(dest.rot, "rot", db);
  164|     28|    ReadField<ErrorPolicy_Igno>(dest.texflag, "texflag", db);
  165|     28|    ReadField<ErrorPolicy_Igno>(dest.colormodel, "colormodel", db);
  166|     28|    ReadField<ErrorPolicy_Igno>(dest.pmapto, "pmapto", db);
  167|     28|    ReadField<ErrorPolicy_Igno>(dest.pmaptoneg, "pmaptoneg", db);
  168|     28|    ReadField<ErrorPolicy_Warn>(dest.r, "r", db);
  169|     28|    ReadField<ErrorPolicy_Warn>(dest.g, "g", db);
  170|     28|    ReadField<ErrorPolicy_Warn>(dest.b, "b", db);
  171|     28|    ReadField<ErrorPolicy_Warn>(dest.k, "k", db);
  172|     28|    ReadField<ErrorPolicy_Igno>(dest.colspecfac, "colspecfac", db);
  173|     28|    ReadField<ErrorPolicy_Igno>(dest.mirrfac, "mirrfac", db);
  174|     28|    ReadField<ErrorPolicy_Igno>(dest.alphafac, "alphafac", db);
  175|     28|    ReadField<ErrorPolicy_Igno>(dest.difffac, "difffac", db);
  176|     28|    ReadField<ErrorPolicy_Igno>(dest.specfac, "specfac", db);
  177|     28|    ReadField<ErrorPolicy_Igno>(dest.emitfac, "emitfac", db);
  178|     28|    ReadField<ErrorPolicy_Igno>(dest.hardfac, "hardfac", db);
  179|     28|    ReadField<ErrorPolicy_Igno>(dest.norfac, "norfac", db);
  180|       |
  181|     28|    db.reader->IncPtr(size);
  182|     28|}
_ZNK6Assimp7Blender9Structure7ConvertINS0_19SubsurfModifierDataEEEvRT_RKNS0_12FileDatabaseE:
  204|      4|        const FileDatabase &db) const {
  205|       |
  206|      4|    ReadField<ErrorPolicy_Fail>(dest.modifier, "modifier", db);
  207|      4|    ReadField<ErrorPolicy_Warn>(dest.subdivType, "subdivType", db);
  208|      4|    ReadField<ErrorPolicy_Fail>(dest.levels, "levels", db);
  209|      4|    ReadField<ErrorPolicy_Igno>(dest.renderLevels, "renderLevels", db);
  210|      4|    ReadField<ErrorPolicy_Igno>(dest.flags, "flags", db);
  211|       |
  212|      4|    db.reader->IncPtr(size);
  213|      4|}
_ZNK6Assimp7Blender9Structure7ConvertINS0_5MFaceEEEvRT_RKNS0_12FileDatabaseE:
  219|  15.0k|        const FileDatabase &db) const {
  220|       |
  221|  15.0k|    ReadField<ErrorPolicy_Fail>(dest.v1, "v1", db);
  222|  15.0k|    ReadField<ErrorPolicy_Fail>(dest.v2, "v2", db);
  223|  15.0k|    ReadField<ErrorPolicy_Fail>(dest.v3, "v3", db);
  224|  15.0k|    ReadField<ErrorPolicy_Fail>(dest.v4, "v4", db);
  225|  15.0k|    ReadField<ErrorPolicy_Fail>(dest.mat_nr, "mat_nr", db);
  226|  15.0k|    ReadField<ErrorPolicy_Igno>(dest.flag, "flag", db);
  227|       |
  228|  15.0k|    db.reader->IncPtr(size);
  229|  15.0k|}
_ZNK6Assimp7Blender9Structure7ConvertINS0_4LampEEEvRT_RKNS0_12FileDatabaseE:
  235|     31|        const FileDatabase &db) const {
  236|       |
  237|     31|    ReadField<ErrorPolicy_Fail>(dest.id, "id", db);
  238|     31|    int temp = 0;
  239|     31|    ReadField<ErrorPolicy_Fail>(temp, "type", db);
  240|     31|    dest.type = static_cast<Assimp::Blender::Lamp::Type>(temp);
  241|     31|    ReadField<ErrorPolicy_Igno>(dest.flags, "flag", db);
  242|     31|    ReadField<ErrorPolicy_Igno>(dest.colormodel, "colormodel", db);
  243|     31|    ReadField<ErrorPolicy_Igno>(dest.totex, "totex", db);
  244|     31|    ReadField<ErrorPolicy_Warn>(dest.r, "r", db);
  245|     31|    ReadField<ErrorPolicy_Warn>(dest.g, "g", db);
  246|     31|    ReadField<ErrorPolicy_Warn>(dest.b, "b", db);
  247|     31|    ReadField<ErrorPolicy_Warn>(dest.k, "k", db);
  248|     31|    ReadField<ErrorPolicy_Igno>(dest.energy, "energy", db);
  249|     31|    ReadField<ErrorPolicy_Warn>(dest.dist, "dist", db);
  250|     31|    ReadField<ErrorPolicy_Igno>(dest.spotsize, "spotsize", db);
  251|     31|    ReadField<ErrorPolicy_Igno>(dest.spotblend, "spotblend", db);
  252|     31|    ReadField<ErrorPolicy_Warn>(dest.constant_coefficient, "coeff_const", db);
  253|     31|    ReadField<ErrorPolicy_Warn>(dest.linear_coefficient, "coeff_lin", db);
  254|     31|    ReadField<ErrorPolicy_Warn>(dest.quadratic_coefficient, "coeff_quad", db);
  255|     31|    ReadField<ErrorPolicy_Igno>(dest.att1, "att1", db);
  256|     31|    ReadField<ErrorPolicy_Igno>(dest.att2, "att2", db);
  257|     31|    ReadField<ErrorPolicy_Igno>(temp, "falloff_type", db);
  258|     31|    dest.falloff_type = static_cast<Assimp::Blender::Lamp::FalloffType>(temp);
  259|     31|    ReadField<ErrorPolicy_Igno>(dest.sun_brightness, "sun_brightness", db);
  260|     31|    ReadField<ErrorPolicy_Igno>(dest.area_size, "area_size", db);
  261|     31|    ReadField<ErrorPolicy_Igno>(dest.area_sizey, "area_sizey", db);
  262|     31|    ReadField<ErrorPolicy_Igno>(dest.area_sizez, "area_sizez", db);
  263|     31|    ReadField<ErrorPolicy_Igno>(dest.area_shape, "area_shape", db);
  264|       |
  265|     31|    db.reader->IncPtr(size);
  266|     31|}
_ZNK6Assimp7Blender9Structure7ConvertINS0_10PackedFileEEEvRT_RKNS0_12FileDatabaseE:
  284|      1|        const FileDatabase &db) const {
  285|       |
  286|      1|    ReadField<ErrorPolicy_Warn>(dest.size, "size", db);
  287|      1|    ReadField<ErrorPolicy_Warn>(dest.seek, "seek", db);
  288|      1|    ReadFieldPtr<ErrorPolicy_Warn>(dest.data, "*data", db);
  289|       |
  290|      1|    db.reader->IncPtr(size);
  291|      1|}
_ZNK6Assimp7Blender9Structure7ConvertINS0_4BaseEEEvRT_RKNS0_12FileDatabaseE:
  297|     31|        const FileDatabase &db) const {
  298|       |    // note: as per https://github.com/assimp/assimp/issues/128,
  299|       |    // reading the Object linked list recursively is prone to stack overflow.
  300|       |    // This structure converter is therefore a hand-written exception that
  301|       |    // does it iteratively.
  302|       |
  303|     31|    const int initial_pos = db.reader->GetCurrentPos();
  304|       |
  305|     31|    std::pair<Base *, int> todo = std::make_pair(&dest, initial_pos);
  306|     96|    for (;;) {
  307|       |
  308|     96|        Base &cur_dest = *todo.first;
  309|     96|        db.reader->SetCurrentPos(todo.second);
  310|       |
  311|       |        // we know that this is a double-linked, circular list which we never
  312|       |        // traverse backwards, so don't bother resolving the back links.
  313|     96|        cur_dest.prev = nullptr;
  314|       |
  315|     96|        ReadFieldPtr<ErrorPolicy_Warn>(cur_dest.object, "*object", db);
  316|       |
  317|       |        // the return value of ReadFieldPtr indicates whether the object
  318|       |        // was already cached. In this case, we don't need to resolve
  319|       |        // it again.
  320|     96|        if (!ReadFieldPtr<ErrorPolicy_Warn>(cur_dest.next, "*next", db, true) && cur_dest.next) {
  ------------------
  |  Branch (320:13): [True: 89, False: 7]
  |  Branch (320:82): [True: 65, False: 24]
  ------------------
  321|     65|            todo = std::make_pair(&*cur_dest.next, db.reader->GetCurrentPos());
  322|     65|            continue;
  323|     65|        }
  324|     31|        break;
  325|     96|    }
  326|       |
  327|     31|    db.reader->SetCurrentPos(initial_pos + size);
  328|     31|}
_ZNK6Assimp7Blender9Structure7ConvertINS0_6MTFaceEEEvRT_RKNS0_12FileDatabaseE:
  334|     28|        const FileDatabase &db) const {
  335|       |
  336|     28|    ReadFieldArray2<ErrorPolicy_Fail>(dest.uv, "uv", db);
  337|     28|    ReadField<ErrorPolicy_Igno>(dest.flag, "flag", db);
  338|     28|    ReadField<ErrorPolicy_Igno>(dest.mode, "mode", db);
  339|     28|    ReadField<ErrorPolicy_Igno>(dest.tile, "tile", db);
  340|     28|    ReadField<ErrorPolicy_Igno>(dest.unwrap, "unwrap", db);
  341|       |
  342|     28|    db.reader->IncPtr(size);
  343|     28|}
_ZNK6Assimp7Blender9Structure7ConvertINS0_8MaterialEEEvRT_RKNS0_12FileDatabaseE:
  349|     28|        const FileDatabase &db) const {
  350|     28|    ReadField<ErrorPolicy_Fail>(dest.id, "id", db);
  351|     28|    ReadField<ErrorPolicy_Warn>(dest.r, "r", db);
  352|     28|    ReadField<ErrorPolicy_Warn>(dest.g, "g", db);
  353|     28|    ReadField<ErrorPolicy_Warn>(dest.b, "b", db);
  354|     28|    ReadField<ErrorPolicy_Warn>(dest.specr, "specr", db);
  355|     28|    ReadField<ErrorPolicy_Warn>(dest.specg, "specg", db);
  356|     28|    ReadField<ErrorPolicy_Warn>(dest.specb, "specb", db);
  357|     28|    ReadField<ErrorPolicy_Igno>(dest.har, "har", db);
  358|     28|    ReadField<ErrorPolicy_Warn>(dest.ambr, "ambr", db);
  359|     28|    ReadField<ErrorPolicy_Warn>(dest.ambg, "ambg", db);
  360|     28|    ReadField<ErrorPolicy_Warn>(dest.ambb, "ambb", db);
  361|     28|    ReadField<ErrorPolicy_Igno>(dest.mirr, "mirr", db);
  362|     28|    ReadField<ErrorPolicy_Igno>(dest.mirg, "mirg", db);
  363|     28|    ReadField<ErrorPolicy_Igno>(dest.mirb, "mirb", db);
  364|     28|    ReadField<ErrorPolicy_Warn>(dest.emit, "emit", db);
  365|     28|    ReadField<ErrorPolicy_Igno>(dest.ray_mirror, "ray_mirror", db);
  366|     28|    ReadField<ErrorPolicy_Warn>(dest.alpha, "alpha", db);
  367|     28|    ReadField<ErrorPolicy_Igno>(dest.ref, "ref", db);
  368|     28|    ReadField<ErrorPolicy_Igno>(dest.translucency, "translucency", db);
  369|     28|    ReadField<ErrorPolicy_Igno>(dest.mode, "mode", db);
  370|     28|    ReadField<ErrorPolicy_Igno>(dest.roughness, "roughness", db);
  371|     28|    ReadField<ErrorPolicy_Igno>(dest.darkness, "darkness", db);
  372|     28|    ReadField<ErrorPolicy_Igno>(dest.refrac, "refrac", db);
  373|     28|    ReadFieldPtr<ErrorPolicy_Igno>(dest.group, "*group", db);
  374|     28|    ReadField<ErrorPolicy_Warn>(dest.diff_shader, "diff_shader", db);
  375|     28|    ReadField<ErrorPolicy_Warn>(dest.spec_shader, "spec_shader", db);
  376|     28|    ReadFieldPtr<ErrorPolicy_Igno>(dest.mtex, "*mtex", db);
  377|       |
  378|     28|    ReadField<ErrorPolicy_Igno>(dest.amb, "amb", db);
  379|     28|    ReadField<ErrorPolicy_Igno>(dest.ang, "ang", db);
  380|     28|    ReadField<ErrorPolicy_Igno>(dest.spectra, "spectra", db);
  381|     28|    ReadField<ErrorPolicy_Igno>(dest.spec, "spec", db);
  382|     28|    ReadField<ErrorPolicy_Igno>(dest.zoffs, "zoffs", db);
  383|     28|    ReadField<ErrorPolicy_Igno>(dest.add, "add", db);
  384|     28|    ReadField<ErrorPolicy_Igno>(dest.fresnel_mir, "fresnel_mir", db);
  385|     28|    ReadField<ErrorPolicy_Igno>(dest.fresnel_mir_i, "fresnel_mir_i", db);
  386|     28|    ReadField<ErrorPolicy_Igno>(dest.fresnel_tra, "fresnel_tra", db);
  387|     28|    ReadField<ErrorPolicy_Igno>(dest.fresnel_tra_i, "fresnel_tra_i", db);
  388|     28|    ReadField<ErrorPolicy_Igno>(dest.filter, "filter", db);
  389|     28|    ReadField<ErrorPolicy_Igno>(dest.tx_limit, "tx_limit", db);
  390|     28|    ReadField<ErrorPolicy_Igno>(dest.tx_falloff, "tx_falloff", db);
  391|     28|    ReadField<ErrorPolicy_Igno>(dest.gloss_mir, "gloss_mir", db);
  392|     28|    ReadField<ErrorPolicy_Igno>(dest.gloss_tra, "gloss_tra", db);
  393|     28|    ReadField<ErrorPolicy_Igno>(dest.adapt_thresh_mir, "adapt_thresh_mir", db);
  394|     28|    ReadField<ErrorPolicy_Igno>(dest.adapt_thresh_tra, "adapt_thresh_tra", db);
  395|     28|    ReadField<ErrorPolicy_Igno>(dest.aniso_gloss_mir, "aniso_gloss_mir", db);
  396|     28|    ReadField<ErrorPolicy_Igno>(dest.dist_mir, "dist_mir", db);
  397|     28|    ReadField<ErrorPolicy_Igno>(dest.hasize, "hasize", db);
  398|     28|    ReadField<ErrorPolicy_Igno>(dest.flaresize, "flaresize", db);
  399|     28|    ReadField<ErrorPolicy_Igno>(dest.subsize, "subsize", db);
  400|     28|    ReadField<ErrorPolicy_Igno>(dest.flareboost, "flareboost", db);
  401|     28|    ReadField<ErrorPolicy_Igno>(dest.strand_sta, "strand_sta", db);
  402|     28|    ReadField<ErrorPolicy_Igno>(dest.strand_end, "strand_end", db);
  403|     28|    ReadField<ErrorPolicy_Igno>(dest.strand_ease, "strand_ease", db);
  404|     28|    ReadField<ErrorPolicy_Igno>(dest.strand_surfnor, "strand_surfnor", db);
  405|     28|    ReadField<ErrorPolicy_Igno>(dest.strand_min, "strand_min", db);
  406|     28|    ReadField<ErrorPolicy_Igno>(dest.strand_widthfade, "strand_widthfade", db);
  407|     28|    ReadField<ErrorPolicy_Igno>(dest.sbias, "sbias", db);
  408|     28|    ReadField<ErrorPolicy_Igno>(dest.lbias, "lbias", db);
  409|     28|    ReadField<ErrorPolicy_Igno>(dest.shad_alpha, "shad_alpha", db);
  410|     28|    ReadField<ErrorPolicy_Igno>(dest.param, "param", db);
  411|     28|    ReadField<ErrorPolicy_Igno>(dest.rms, "rms", db);
  412|     28|    ReadField<ErrorPolicy_Igno>(dest.rampfac_col, "rampfac_col", db);
  413|     28|    ReadField<ErrorPolicy_Igno>(dest.rampfac_spec, "rampfac_spec", db);
  414|     28|    ReadField<ErrorPolicy_Igno>(dest.friction, "friction", db);
  415|     28|    ReadField<ErrorPolicy_Igno>(dest.fh, "fh", db);
  416|     28|    ReadField<ErrorPolicy_Igno>(dest.reflect, "reflect", db);
  417|     28|    ReadField<ErrorPolicy_Igno>(dest.fhdist, "fhdist", db);
  418|     28|    ReadField<ErrorPolicy_Igno>(dest.xyfrict, "xyfrict", db);
  419|     28|    ReadField<ErrorPolicy_Igno>(dest.sss_radius, "sss_radius", db);
  420|     28|    ReadField<ErrorPolicy_Igno>(dest.sss_col, "sss_col", db);
  421|     28|    ReadField<ErrorPolicy_Igno>(dest.sss_error, "sss_error", db);
  422|     28|    ReadField<ErrorPolicy_Igno>(dest.sss_scale, "sss_scale", db);
  423|     28|    ReadField<ErrorPolicy_Igno>(dest.sss_ior, "sss_ior", db);
  424|     28|    ReadField<ErrorPolicy_Igno>(dest.sss_colfac, "sss_colfac", db);
  425|     28|    ReadField<ErrorPolicy_Igno>(dest.sss_texfac, "sss_texfac", db);
  426|     28|    ReadField<ErrorPolicy_Igno>(dest.sss_front, "sss_front", db);
  427|     28|    ReadField<ErrorPolicy_Igno>(dest.sss_back, "sss_back", db);
  428|       |
  429|     28|    ReadField<ErrorPolicy_Igno>(dest.material_type, "material_type", db);
  430|     28|    ReadField<ErrorPolicy_Igno>(dest.flag, "flag", db);
  431|     28|    ReadField<ErrorPolicy_Igno>(dest.ray_depth, "ray_depth", db);
  432|     28|    ReadField<ErrorPolicy_Igno>(dest.ray_depth_tra, "ray_depth_tra", db);
  433|     28|    ReadField<ErrorPolicy_Igno>(dest.samp_gloss_mir, "samp_gloss_mir", db);
  434|     28|    ReadField<ErrorPolicy_Igno>(dest.samp_gloss_tra, "samp_gloss_tra", db);
  435|     28|    ReadField<ErrorPolicy_Igno>(dest.fadeto_mir, "fadeto_mir", db);
  436|     28|    ReadField<ErrorPolicy_Igno>(dest.shade_flag, "shade_flag", db);
  437|     28|    ReadField<ErrorPolicy_Igno>(dest.flarec, "flarec", db);
  438|     28|    ReadField<ErrorPolicy_Igno>(dest.starc, "starc", db);
  439|     28|    ReadField<ErrorPolicy_Igno>(dest.linec, "linec", db);
  440|     28|    ReadField<ErrorPolicy_Igno>(dest.ringc, "ringc", db);
  441|     28|    ReadField<ErrorPolicy_Igno>(dest.pr_lamp, "pr_lamp", db);
  442|     28|    ReadField<ErrorPolicy_Igno>(dest.pr_texture, "pr_texture", db);
  443|     28|    ReadField<ErrorPolicy_Igno>(dest.ml_flag, "ml_flag", db);
  444|     28|    ReadField<ErrorPolicy_Igno>(dest.diff_shader, "diff_shader", db);
  445|     28|    ReadField<ErrorPolicy_Igno>(dest.spec_shader, "spec_shader", db);
  446|     28|    ReadField<ErrorPolicy_Igno>(dest.texco, "texco", db);
  447|     28|    ReadField<ErrorPolicy_Igno>(dest.mapto, "mapto", db);
  448|     28|    ReadField<ErrorPolicy_Igno>(dest.ramp_show, "ramp_show", db);
  449|     28|    ReadField<ErrorPolicy_Igno>(dest.pad3, "pad3", db);
  450|     28|    ReadField<ErrorPolicy_Igno>(dest.dynamode, "dynamode", db);
  451|     28|    ReadField<ErrorPolicy_Igno>(dest.pad2, "pad2", db);
  452|     28|    ReadField<ErrorPolicy_Igno>(dest.sss_flag, "sss_flag", db);
  453|     28|    ReadField<ErrorPolicy_Igno>(dest.sss_preset, "sss_preset", db);
  454|     28|    ReadField<ErrorPolicy_Igno>(dest.shadowonly_flag, "shadowonly_flag", db);
  455|     28|    ReadField<ErrorPolicy_Igno>(dest.index, "index", db);
  456|     28|    ReadField<ErrorPolicy_Igno>(dest.vcol_alpha, "vcol_alpha", db);
  457|     28|    ReadField<ErrorPolicy_Igno>(dest.pad4, "pad4", db);
  458|       |
  459|     28|    ReadField<ErrorPolicy_Igno>(dest.seed1, "seed1", db);
  460|     28|    ReadField<ErrorPolicy_Igno>(dest.seed2, "seed2", db);
  461|       |
  462|     28|    db.reader->IncPtr(size);
  463|     28|}
_ZNK6Assimp7Blender9Structure7ConvertINS0_8MTexPolyEEEvRT_RKNS0_12FileDatabaseE:
  469|     91|        const FileDatabase &db) const {
  470|       |
  471|     91|    {
  472|     91|        std::shared_ptr<Image> tpage;
  473|     91|        ReadFieldPtr<ErrorPolicy_Igno>(tpage, "*tpage", db);
  474|     91|        dest.tpage = tpage.get();
  475|     91|    }
  476|     91|    ReadField<ErrorPolicy_Igno>(dest.flag, "flag", db);
  477|     91|    ReadField<ErrorPolicy_Igno>(dest.transp, "transp", db);
  478|     91|    ReadField<ErrorPolicy_Igno>(dest.mode, "mode", db);
  479|     91|    ReadField<ErrorPolicy_Igno>(dest.tile, "tile", db);
  480|     91|    ReadField<ErrorPolicy_Igno>(dest.pad, "pad", db);
  481|       |
  482|     91|    db.reader->IncPtr(size);
  483|     91|}
_ZNK6Assimp7Blender9Structure7ConvertINS0_4MeshEEEvRT_RKNS0_12FileDatabaseE:
  489|     42|        const FileDatabase &db) const {
  490|       |
  491|     42|    ReadField<ErrorPolicy_Fail>(dest.id, "id", db);
  492|     42|    ReadField<ErrorPolicy_Fail>(dest.totface, "totface", db);
  493|     42|    ReadField<ErrorPolicy_Fail>(dest.totedge, "totedge", db);
  494|     42|    ReadField<ErrorPolicy_Fail>(dest.totvert, "totvert", db);
  495|     42|    ReadField<ErrorPolicy_Igno>(dest.totloop, "totloop", db);
  496|     42|    ReadField<ErrorPolicy_Igno>(dest.totpoly, "totpoly", db);
  497|     42|    ReadField<ErrorPolicy_Igno>(dest.subdiv, "subdiv", db);
  498|     42|    ReadField<ErrorPolicy_Igno>(dest.subdivr, "subdivr", db);
  499|     42|    ReadField<ErrorPolicy_Igno>(dest.subsurftype, "subsurftype", db);
  500|     42|    ReadField<ErrorPolicy_Igno>(dest.smoothresh, "smoothresh", db);
  501|     42|    ReadFieldPtr<ErrorPolicy_Fail>(dest.mface, "*mface", db);
  502|     42|    ReadFieldPtr<ErrorPolicy_Igno>(dest.mtface, "*mtface", db);
  503|     42|    ReadFieldPtr<ErrorPolicy_Igno>(dest.tface, "*tface", db);
  504|     42|    ReadFieldPtr<ErrorPolicy_Fail>(dest.mvert, "*mvert", db);
  505|     42|    ReadFieldPtr<ErrorPolicy_Warn>(dest.medge, "*medge", db);
  506|     42|    ReadFieldPtr<ErrorPolicy_Igno>(dest.mloop, "*mloop", db);
  507|     42|    ReadFieldPtr<ErrorPolicy_Igno>(dest.mloopuv, "*mloopuv", db);
  508|     42|    ReadFieldPtr<ErrorPolicy_Igno>(dest.mloopcol, "*mloopcol", db);
  509|     42|    ReadFieldPtr<ErrorPolicy_Igno>(dest.mpoly, "*mpoly", db);
  510|     42|    ReadFieldPtr<ErrorPolicy_Igno>(dest.mtpoly, "*mtpoly", db);
  511|     42|    ReadFieldPtr<ErrorPolicy_Igno>(dest.dvert, "*dvert", db);
  512|     42|    ReadFieldPtr<ErrorPolicy_Igno>(dest.mcol, "*mcol", db);
  513|     42|    ReadFieldPtr<ErrorPolicy_Fail>(dest.mat, "**mat", db);
  514|       |
  515|     42|    ReadField<ErrorPolicy_Igno>(dest.vdata, "vdata", db);
  516|     42|    ReadField<ErrorPolicy_Igno>(dest.edata, "edata", db);
  517|     42|    ReadField<ErrorPolicy_Igno>(dest.fdata, "fdata", db);
  518|     42|    ReadField<ErrorPolicy_Igno>(dest.pdata, "pdata", db);
  519|     42|    ReadField<ErrorPolicy_Warn>(dest.ldata, "ldata", db);
  520|       |
  521|     42|    db.reader->IncPtr(size);
  522|     42|}
_ZNK6Assimp7Blender9Structure7ConvertINS0_5WorldEEEvRT_RKNS0_12FileDatabaseE:
  540|     26|        const FileDatabase &db) const {
  541|       |
  542|     26|    ReadField<ErrorPolicy_Fail>(dest.id, "id", db);
  543|       |
  544|     26|    db.reader->IncPtr(size);
  545|     26|}
_ZNK6Assimp7Blender9Structure7ConvertINS0_5MVertEEEvRT_RKNS0_12FileDatabaseE:
  565|  18.0k|        const FileDatabase &db) const {
  566|       |
  567|  18.0k|    ReadFieldArray<ErrorPolicy_Fail>(dest.co, "co", db);
  568|  18.0k|    ReadFieldArray<ErrorPolicy_Warn>(dest.no, "no", db);
  569|  18.0k|    ReadField<ErrorPolicy_Igno>(dest.flag, "flag", db);
  570|       |    //ReadField<ErrorPolicy_Warn>(dest.mat_nr,"mat_nr",db);
  571|  18.0k|    ReadField<ErrorPolicy_Igno>(dest.bweight, "bweight", db);
  572|       |
  573|  18.0k|    db.reader->IncPtr(size);
  574|  18.0k|}
_ZNK6Assimp7Blender9Structure7ConvertINS0_5MEdgeEEEvRT_RKNS0_12FileDatabaseE:
  580|  33.9k|        const FileDatabase &db) const {
  581|       |
  582|  33.9k|    ReadField<ErrorPolicy_Fail>(dest.v1, "v1", db);
  583|  33.9k|    ReadField<ErrorPolicy_Fail>(dest.v2, "v2", db);
  584|  33.9k|    ReadField<ErrorPolicy_Igno>(dest.crease, "crease", db);
  585|  33.9k|    ReadField<ErrorPolicy_Igno>(dest.bweight, "bweight", db);
  586|  33.9k|    ReadField<ErrorPolicy_Igno>(dest.flag, "flag", db);
  587|       |
  588|  33.9k|    db.reader->IncPtr(size);
  589|  33.9k|}
_ZNK6Assimp7Blender9Structure7ConvertINS0_7MLoopUVEEEvRT_RKNS0_12FileDatabaseE:
  595|    324|        const FileDatabase &db) const {
  596|       |
  597|    324|    ReadFieldArray<ErrorPolicy_Igno>(dest.uv, "uv", db);
  598|    324|    ReadField<ErrorPolicy_Igno>(dest.flag, "flag", db);
  599|       |
  600|    324|    db.reader->IncPtr(size);
  601|    324|}
_ZNK6Assimp7Blender9Structure7ConvertINS0_8ListBaseEEEvRT_RKNS0_12FileDatabaseE:
  620|    128|        const FileDatabase &db) const {
  621|       |
  622|    128|    ReadFieldPtr<ErrorPolicy_Igno>(dest.first, "*first", db);
  623|    128|    std::shared_ptr<ElemBase> last;
  624|    128|    ReadFieldPtr<ErrorPolicy_Igno>(last, "*last", db);
  625|    128|    dest.last = last;
  626|       |
  627|    128|    db.reader->IncPtr(size);
  628|    128|}
_ZNK6Assimp7Blender9Structure7ConvertINS0_5MLoopEEEvRT_RKNS0_12FileDatabaseE:
  634|  5.31k|        const FileDatabase &db) const {
  635|       |
  636|  5.31k|    ReadField<ErrorPolicy_Igno>(dest.v, "v", db);
  637|  5.31k|    ReadField<ErrorPolicy_Igno>(dest.e, "e", db);
  638|       |
  639|  5.31k|    db.reader->IncPtr(size);
  640|  5.31k|}
_ZNK6Assimp7Blender9Structure7ConvertINS0_12ModifierDataEEEvRT_RKNS0_12FileDatabaseE:
  646|      6|        const FileDatabase &db) const {
  647|       |
  648|      6|    ReadFieldPtr<ErrorPolicy_Warn>(dest.next, "*next", db);
  649|      6|    std::shared_ptr<ElemBase> prev;
  650|      6|    ReadFieldPtr<ErrorPolicy_Warn>(prev, "*prev", db);
  651|      6|    dest.prev = prev;
  652|      6|    ReadField<ErrorPolicy_Igno>(dest.type, "type", db);
  653|      6|    ReadField<ErrorPolicy_Igno>(dest.mode, "mode", db);
  654|      6|    ReadFieldArray<ErrorPolicy_Igno>(dest.name, "name", db);
  655|       |
  656|      6|    db.reader->IncPtr(size);
  657|      6|}
_ZNK6Assimp7Blender9Structure7ConvertINS0_2IDEEEvRT_RKNS0_12FileDatabaseE:
  663|    290|        const FileDatabase &db) const {
  664|       |
  665|    290|    ReadFieldArray<ErrorPolicy_Warn>(dest.name, "name", db);
  666|    290|    ReadField<ErrorPolicy_Igno>(dest.flag, "flag", db);
  667|       |
  668|    290|    db.reader->IncPtr(size);
  669|    290|}
_ZNK6Assimp7Blender9Structure7ConvertINS0_4MColEEEvRT_RKNS0_12FileDatabaseE:
  675|     24|        const FileDatabase &db) const {
  676|       |
  677|     24|    ReadField<ErrorPolicy_Fail>(dest.r, "r", db);
  678|     24|    ReadField<ErrorPolicy_Fail>(dest.g, "g", db);
  679|     24|    ReadField<ErrorPolicy_Fail>(dest.b, "b", db);
  680|     24|    ReadField<ErrorPolicy_Fail>(dest.a, "a", db);
  681|       |
  682|     24|    db.reader->IncPtr(size);
  683|     24|}
_ZNK6Assimp7Blender9Structure7ConvertINS0_5MPolyEEEvRT_RKNS0_12FileDatabaseE:
  689|  1.36k|        const FileDatabase &db) const {
  690|       |
  691|  1.36k|    ReadField<ErrorPolicy_Igno>(dest.loopstart, "loopstart", db);
  692|  1.36k|    ReadField<ErrorPolicy_Igno>(dest.totloop, "totloop", db);
  693|  1.36k|    ReadField<ErrorPolicy_Igno>(dest.mat_nr, "mat_nr", db);
  694|  1.36k|    ReadField<ErrorPolicy_Igno>(dest.flag, "flag", db);
  695|       |
  696|  1.36k|    db.reader->IncPtr(size);
  697|  1.36k|}
_ZNK6Assimp7Blender9Structure7ConvertINS0_5SceneEEEvRT_RKNS0_12FileDatabaseE:
  703|     26|        const FileDatabase &db) const {
  704|       |
  705|     26|    ReadField<ErrorPolicy_Fail>(dest.id, "id", db);
  706|     26|    ReadFieldPtr<ErrorPolicy_Warn>(dest.camera, "*camera", db);
  707|     26|    ReadFieldPtr<ErrorPolicy_Warn>(dest.world, "*world", db);
  708|     26|    ReadFieldPtr<ErrorPolicy_Warn>(dest.basact, "*basact", db);
  709|     26|    ReadFieldPtr<ErrorPolicy_Warn>(dest.master_collection, "*master_collection", db);
  710|     26|    ReadField<ErrorPolicy_Igno>(dest.base, "base", db);
  711|       |
  712|     26|    db.reader->IncPtr(size);
  713|     26|}
_ZNK6Assimp7Blender9Structure7ConvertINS0_3TexEEEvRT_RKNS0_12FileDatabaseE:
  733|     24|        const FileDatabase &db) const {
  734|     24|    short temp_short = 0;
  735|     24|    ReadField<ErrorPolicy_Igno>(temp_short, "imaflag", db);
  736|     24|    dest.imaflag = static_cast<Assimp::Blender::Tex::ImageFlags>(temp_short);
  737|     24|    int temp = 0;
  738|     24|    ReadField<ErrorPolicy_Fail>(temp, "type", db);
  739|     24|    dest.type = static_cast<Assimp::Blender::Tex::Type>(temp);
  740|     24|    ReadFieldPtr<ErrorPolicy_Warn>(dest.ima, "*ima", db);
  741|       |
  742|     24|    db.reader->IncPtr(size);
  743|     24|}
_ZNK6Assimp7Blender9Structure7ConvertINS0_6CameraEEEvRT_RKNS0_12FileDatabaseE:
  749|     27|        const FileDatabase &db) const {
  750|       |
  751|     27|    ReadField<ErrorPolicy_Fail>(dest.id, "id", db);
  752|     27|    int temp = 0;
  753|     27|    ReadField<ErrorPolicy_Warn>(temp, "type", db);
  754|     27|    dest.type = static_cast<Assimp::Blender::Camera::Type>(temp);
  755|     27|    ReadField<ErrorPolicy_Warn>(temp, "flag", db);
  756|     27|    dest.flag = static_cast<Assimp::Blender::Camera::Type>(temp);
  757|     27|    ReadField<ErrorPolicy_Warn>(dest.lens, "lens", db);
  758|     27|    ReadField<ErrorPolicy_Warn>(dest.sensor_x, "sensor_x", db);
  759|     27|    ReadField<ErrorPolicy_Igno>(dest.clipsta, "clipsta", db);
  760|     27|    ReadField<ErrorPolicy_Igno>(dest.clipend, "clipend", db);
  761|       |
  762|     27|    db.reader->IncPtr(size);
  763|     27|}
_ZNK6Assimp7Blender9Structure7ConvertINS0_18MirrorModifierDataEEEvRT_RKNS0_12FileDatabaseE:
  769|      2|        const FileDatabase &db) const {
  770|       |
  771|      2|    ReadField<ErrorPolicy_Fail>(dest.modifier, "modifier", db);
  772|      2|    ReadField<ErrorPolicy_Igno>(dest.axis, "axis", db);
  773|      2|    ReadField<ErrorPolicy_Igno>(dest.flag, "flag", db);
  774|      2|    ReadField<ErrorPolicy_Igno>(dest.tolerance, "tolerance", db);
  775|      2|    std::shared_ptr<Object> mirror_ob;
  776|      2|    ReadFieldPtr<ErrorPolicy_Igno>(mirror_ob, "*mirror_ob", db);
  777|      2|    dest.mirror_ob = mirror_ob;
  778|       |
  779|      2|    db.reader->IncPtr(size);
  780|      2|}
_ZNK6Assimp7Blender9Structure7ConvertINS0_5ImageEEEvRT_RKNS0_12FileDatabaseE:
  786|      8|        const FileDatabase &db) const {
  787|       |
  788|      8|    ReadField<ErrorPolicy_Fail>(dest.id, "id", db);
  789|      8|    ReadFieldArray<ErrorPolicy_Warn>(dest.name, "name", db);
  790|      8|    ReadField<ErrorPolicy_Igno>(dest.ok, "ok", db);
  791|      8|    ReadField<ErrorPolicy_Igno>(dest.flag, "flag", db);
  792|      8|    ReadField<ErrorPolicy_Igno>(dest.source, "source", db);
  793|      8|    ReadField<ErrorPolicy_Igno>(dest.type, "type", db);
  794|      8|    ReadField<ErrorPolicy_Igno>(dest.pad, "pad", db);
  795|      8|    ReadField<ErrorPolicy_Igno>(dest.pad1, "pad1", db);
  796|      8|    ReadField<ErrorPolicy_Igno>(dest.lastframe, "lastframe", db);
  797|      8|    ReadField<ErrorPolicy_Igno>(dest.tpageflag, "tpageflag", db);
  798|      8|    ReadField<ErrorPolicy_Igno>(dest.totbind, "totbind", db);
  799|      8|    ReadField<ErrorPolicy_Igno>(dest.xrep, "xrep", db);
  800|      8|    ReadField<ErrorPolicy_Igno>(dest.yrep, "yrep", db);
  801|      8|    ReadField<ErrorPolicy_Igno>(dest.twsta, "twsta", db);
  802|      8|    ReadField<ErrorPolicy_Igno>(dest.twend, "twend", db);
  803|      8|    ReadFieldPtr<ErrorPolicy_Igno>(dest.packedfile, "*packedfile", db);
  804|      8|    ReadField<ErrorPolicy_Igno>(dest.lastupdate, "lastupdate", db);
  805|      8|    ReadField<ErrorPolicy_Igno>(dest.lastused, "lastused", db);
  806|      8|    ReadField<ErrorPolicy_Igno>(dest.animspeed, "animspeed", db);
  807|      8|    ReadField<ErrorPolicy_Igno>(dest.gen_x, "gen_x", db);
  808|      8|    ReadField<ErrorPolicy_Igno>(dest.gen_y, "gen_y", db);
  809|      8|    ReadField<ErrorPolicy_Igno>(dest.gen_type, "gen_type", db);
  810|       |
  811|      8|    db.reader->IncPtr(size);
  812|      8|}
_ZNK6Assimp7Blender9Structure7ConvertINS0_10CustomDataEEEvRT_RKNS0_12FileDatabaseE:
  818|    148|        const FileDatabase &db) const {
  819|    148|    ReadFieldArray<ErrorPolicy_Warn>(dest.typemap, "typemap", db);
  820|    148|    ReadField<ErrorPolicy_Warn>(dest.totlayer, "totlayer", db);
  821|    148|    ReadField<ErrorPolicy_Warn>(dest.maxlayer, "maxlayer", db);
  822|    148|    ReadField<ErrorPolicy_Warn>(dest.totsize, "totsize", db);
  823|    148|    ReadFieldPtrVector<ErrorPolicy_Warn>(dest.layers, "*layers", db);
  824|       |
  825|    148|    db.reader->IncPtr(size);
  826|    148|}
_ZNK6Assimp7Blender9Structure7ConvertINS0_15CustomDataLayerEEEvRT_RKNS0_12FileDatabaseE:
  832|    595|        const FileDatabase &db) const {
  833|    595|    ReadField<ErrorPolicy_Fail>(dest.type, "type", db);
  834|    595|    ReadField<ErrorPolicy_Fail>(dest.offset, "offset", db);
  835|    595|    ReadField<ErrorPolicy_Fail>(dest.flag, "flag", db);
  836|    595|    ReadField<ErrorPolicy_Fail>(dest.active, "active", db);
  837|    595|    ReadField<ErrorPolicy_Fail>(dest.active_rnd, "active_rnd", db);
  838|    595|    ReadField<ErrorPolicy_Warn>(dest.active_clone, "active_clone", db);
  839|    595|    ReadField<ErrorPolicy_Warn>(dest.active_mask, "active_mask", db);
  840|    595|    ReadField<ErrorPolicy_Warn>(dest.uid, "uid", db);
  841|    595|    ReadFieldArray<ErrorPolicy_Warn>(dest.name, "name", db);
  842|    595|    ReadCustomDataPtr<ErrorPolicy_Fail>(dest.data, dest.type, "*data", db);
  843|       |
  844|    595|    db.reader->IncPtr(size);
  845|    595|}
_ZN6Assimp7Blender3DNA18RegisterConvertersEv:
  848|     26|void DNA::RegisterConverters() {
  849|       |
  850|     26|    converters["Object"] = DNA::FactoryPair(&Structure::Allocate<Object>, &Structure::Convert<Object>);
  851|     26|    converters["Group"] = DNA::FactoryPair(&Structure::Allocate<Group>, &Structure::Convert<Group>);
  852|     26|    converters["MTex"] = DNA::FactoryPair(&Structure::Allocate<MTex>, &Structure::Convert<MTex>);
  853|     26|    converters["TFace"] = DNA::FactoryPair(&Structure::Allocate<TFace>, &Structure::Convert<TFace>);
  854|     26|    converters["SubsurfModifierData"] = DNA::FactoryPair(&Structure::Allocate<SubsurfModifierData>, &Structure::Convert<SubsurfModifierData>);
  855|     26|    converters["MFace"] = DNA::FactoryPair(&Structure::Allocate<MFace>, &Structure::Convert<MFace>);
  856|     26|    converters["Lamp"] = DNA::FactoryPair(&Structure::Allocate<Lamp>, &Structure::Convert<Lamp>);
  857|     26|    converters["MDeformWeight"] = DNA::FactoryPair(&Structure::Allocate<MDeformWeight>, &Structure::Convert<MDeformWeight>);
  858|     26|    converters["PackedFile"] = DNA::FactoryPair(&Structure::Allocate<PackedFile>, &Structure::Convert<PackedFile>);
  859|     26|    converters["Base"] = DNA::FactoryPair(&Structure::Allocate<Base>, &Structure::Convert<Base>);
  860|     26|    converters["MTFace"] = DNA::FactoryPair(&Structure::Allocate<MTFace>, &Structure::Convert<MTFace>);
  861|     26|    converters["Material"] = DNA::FactoryPair(&Structure::Allocate<Material>, &Structure::Convert<Material>);
  862|     26|    converters["MTexPoly"] = DNA::FactoryPair(&Structure::Allocate<MTexPoly>, &Structure::Convert<MTexPoly>);
  863|     26|    converters["Mesh"] = DNA::FactoryPair(&Structure::Allocate<Mesh>, &Structure::Convert<Mesh>);
  864|     26|    converters["MDeformVert"] = DNA::FactoryPair(&Structure::Allocate<MDeformVert>, &Structure::Convert<MDeformVert>);
  865|     26|    converters["World"] = DNA::FactoryPair(&Structure::Allocate<World>, &Structure::Convert<World>);
  866|     26|    converters["MLoopCol"] = DNA::FactoryPair(&Structure::Allocate<MLoopCol>, &Structure::Convert<MLoopCol>);
  867|     26|    converters["MVert"] = DNA::FactoryPair(&Structure::Allocate<MVert>, &Structure::Convert<MVert>);
  868|     26|    converters["MEdge"] = DNA::FactoryPair(&Structure::Allocate<MEdge>, &Structure::Convert<MEdge>);
  869|     26|    converters["MLoopUV"] = DNA::FactoryPair(&Structure::Allocate<MLoopUV>, &Structure::Convert<MLoopUV>);
  870|     26|    converters["GroupObject"] = DNA::FactoryPair(&Structure::Allocate<GroupObject>, &Structure::Convert<GroupObject>);
  871|     26|    converters["ListBase"] = DNA::FactoryPair(&Structure::Allocate<ListBase>, &Structure::Convert<ListBase>);
  872|     26|    converters["MLoop"] = DNA::FactoryPair(&Structure::Allocate<MLoop>, &Structure::Convert<MLoop>);
  873|     26|    converters["ModifierData"] = DNA::FactoryPair(&Structure::Allocate<ModifierData>, &Structure::Convert<ModifierData>);
  874|     26|    converters["ID"] = DNA::FactoryPair(&Structure::Allocate<ID>, &Structure::Convert<ID>);
  875|     26|    converters["MCol"] = DNA::FactoryPair(&Structure::Allocate<MCol>, &Structure::Convert<MCol>);
  876|     26|    converters["MPoly"] = DNA::FactoryPair(&Structure::Allocate<MPoly>, &Structure::Convert<MPoly>);
  877|     26|    converters["Scene"] = DNA::FactoryPair(&Structure::Allocate<Scene>, &Structure::Convert<Scene>);
  878|     26|    converters["Library"] = DNA::FactoryPair(&Structure::Allocate<Library>, &Structure::Convert<Library>);
  879|     26|    converters["Tex"] = DNA::FactoryPair(&Structure::Allocate<Tex>, &Structure::Convert<Tex>);
  880|     26|    converters["Camera"] = DNA::FactoryPair(&Structure::Allocate<Camera>, &Structure::Convert<Camera>);
  881|     26|    converters["MirrorModifierData"] = DNA::FactoryPair(&Structure::Allocate<MirrorModifierData>, &Structure::Convert<MirrorModifierData>);
  882|     26|    converters["Image"] = DNA::FactoryPair(&Structure::Allocate<Image>, &Structure::Convert<Image>);
  883|     26|    converters["CustomData"] = DNA::FactoryPair(&Structure::Allocate<CustomData>, &Structure::Convert<CustomData>);
  884|     26|    converters["CustomDataLayer"] = DNA::FactoryPair(&Structure::Allocate<CustomDataLayer>, &Structure::Convert<CustomDataLayer>);
  885|     26|    converters["Collection"] = DNA::FactoryPair(&Structure::Allocate<Collection>, &Structure::Convert<Collection>);
  886|     26|    converters["CollectionChild"] = DNA::FactoryPair(&Structure::Allocate<CollectionChild>, &Structure::Convert<CollectionChild>);
  887|     26|    converters["CollectionObject"] = DNA::FactoryPair(&Structure::Allocate<CollectionObject>, &Structure::Convert<CollectionObject>);
  888|     26|}

_ZN6Assimp7Blender5SceneC2Ev:
  756|     26|    Scene() = default;
_ZN6Assimp7Blender5MVertC2Ev:
  183|  27.0k|            flag(0), mat_nr(0), bweight(0) {}
_ZN6Assimp7Blender6MTFaceC2Ev:
  250|     42|            flag(0),
  251|     42|            mode(0),
  252|     42|            tile(0),
  253|     42|            unwrap(0) {
  254|     42|    }
_ZN6Assimp7Blender15CustomDataLayerC2Ev:
  418|    595|            type(0),
  419|    595|            offset(0),
  420|    595|            flag(0),
  421|    595|            active(0),
  422|    595|            active_rnd(0),
  423|    595|            active_clone(0),
  424|    595|            active_mask(0),
  425|    595|            uid(0),
  426|    595|            data(nullptr) {
  427|    595|        memset(name, 0, sizeof name);
  428|    595|    }
_ZN6Assimp7Blender6ObjectC2Ev:
  728|    100|            type(Type_EMPTY), parent(nullptr) {
  729|       |        // empty
  730|    100|    }
_ZN6Assimp7Blender4BaseC2Ev:
  740|     96|            prev(nullptr) {
  741|       |        // empty
  742|     96|    }
_ZN6Assimp7Blender3TexC2Ev:
  875|     24|    Tex() : imaflag(ImageFlags_INTERPOL), type(Type_CLOUDS) {
  876|       |        // empty
  877|     24|    }
_ZN6Assimp7Blender4MTexC2Ev:
  967|     28|    MTex() = default;
_ZN6Assimp7Blender5ImageC2Ev:
  786|      8|    Image() = default;

_ZNK6Assimp11COBImporter7CanReadERKNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEPNS_8IOSystemEb:
   95|     99|bool COBImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool /*checkSig*/) const {
   96|     99|    static const char *tokens[] = { "Caligary" };
   97|       |    return SearchFileHeaderForToken(pIOHandler, pFile, tokens, AI_COUNT_OF(tokens));
   98|     99|}
_ZNK6Assimp11COBImporter7GetInfoEv:
  102|    634|const aiImporterDesc *COBImporter::GetInfo() const {
  103|    634|    return &desc;
  104|    634|}

_ZN6Assimp11COBImporterC2Ev:
   77|    624|    COBImporter() = default;

_ZN6Assimp11CSMImporterC2Ev:
   76|    624|CSMImporter::CSMImporter() : noSkeletonMesh() {
   77|       |    // empty
   78|    624|}
_ZNK6Assimp11CSMImporter7CanReadERKNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEPNS_8IOSystemEb:
   82|    287|bool CSMImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool /*checkSig*/) const {
   83|    287|    static const char* tokens[] = {"$Filename"};
   84|       |    return SearchFileHeaderForToken(pIOHandler,pFile,tokens,AI_COUNT_OF(tokens));
   85|    287|}
_ZNK6Assimp11CSMImporter7GetInfoEv:
   89|    634|const aiImporterDesc* CSMImporter::GetInfo () const {
   90|    634|    return &desc;
   91|    634|}

_ZN6Assimp7Collada25MakeColladaAssimpMetaKeysEv:
   51|      1|const MetaKeyPairVector MakeColladaAssimpMetaKeys() {
   52|      1|    MetaKeyPairVector result;
   53|      1|    result.emplace_back("authoring_tool", AI_METADATA_SOURCE_GENERATOR);
   54|       |    result.emplace_back("copyright", AI_METADATA_SOURCE_COPYRIGHT);
   55|      1|    return result;
   56|      1|}
_ZN6Assimp7Collada34MakeColladaAssimpMetaKeysCamelCaseEv:
   63|      1|const MetaKeyPairVector MakeColladaAssimpMetaKeysCamelCase() {
   64|      1|    MetaKeyPairVector result = MakeColladaAssimpMetaKeys();
   65|      2|    for (auto &val : result) {
  ------------------
  |  Branch (65:20): [True: 2, False: 1]
  ------------------
   66|      2|        ToCamelCase(val.first);
   67|      2|    }
   68|      1|    return result;
   69|      1|}
_ZN6Assimp7Collada33GetColladaAssimpMetaKeysCamelCaseEv:
   71|    232|const MetaKeyPairVector &GetColladaAssimpMetaKeysCamelCase() {
   72|    232|    static const MetaKeyPairVector result = MakeColladaAssimpMetaKeysCamelCase();
   73|    232|    return result;
   74|    232|}
_ZN6Assimp7Collada11ToCamelCaseERNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEE:
   78|    234|void ToCamelCase(std::string &text) {
   79|    234|    if (text.empty())
  ------------------
  |  Branch (79:9): [True: 0, False: 234]
  ------------------
   80|      0|        return;
   81|       |    // Capitalise first character
   82|    234|    auto it = text.begin();
   83|    234|    (*it) = ai_toupper(*it);
   84|    234|    ++it;
   85|  1.92k|    for (/*started above*/; it != text.end(); /*iterated below*/) {
  ------------------
  |  Branch (85:29): [True: 1.69k, False: 234]
  ------------------
   86|  1.69k|        if ((*it) == '_') {
  ------------------
  |  Branch (86:13): [True: 36, False: 1.65k]
  ------------------
   87|     36|            it = text.erase(it);
   88|     36|            if (it != text.end())
  ------------------
  |  Branch (88:17): [True: 36, False: 0]
  ------------------
   89|     36|                (*it) = ai_toupper(*it);
   90|  1.65k|        } else {
   91|       |            // Make lower case
   92|  1.65k|            (*it) = ai_tolower(*it);
   93|  1.65k|            ++it;
   94|  1.65k|        }
   95|  1.69k|    }
   96|    234|}

_ZN6Assimp7Collada6CameraC2Ev:
  125|     10|            mOrtho(false),
  126|     10|            mHorFov(10e10f),
  127|     10|            mVerFov(10e10f),
  128|     10|            mAspect(10e10f),
  129|     10|            mZNear(0.1f),
  130|     10|            mZFar(1000.f) {}
_ZN6Assimp7Collada5LightC2Ev:
  156|     30|            mType(aiLightSource_UNDEFINED),
  157|     30|            mAttConstant(1.f),
  158|     30|            mAttLinear(0.f),
  159|     30|            mAttQuadratic(0.f),
  160|     30|            mFalloffAngle(180.f),
  161|     30|            mFalloffExponent(0.f),
  162|     30|            mPenumbraAngle(ASSIMP_COLLADA_LIGHT_ANGLE_NOT_SET),
  ------------------
  |  |  151|     30|#define ASSIMP_COLLADA_LIGHT_ANGLE_NOT_SET 1e9f
  ------------------
  163|     30|            mOuterAngle(ASSIMP_COLLADA_LIGHT_ANGLE_NOT_SET),
  ------------------
  |  |  151|     30|#define ASSIMP_COLLADA_LIGHT_ANGLE_NOT_SET 1e9f
  ------------------
  164|     30|            mIntensity(1.f) {}
_ZN6Assimp7Collada21InputSemanticMapEntryC2Ev:
  193|     28|            mSet(0),
  194|     28|            mType(IT_Invalid) {}
_ZN6Assimp7Collada4NodeC2Ev:
  274|    333|            mParent(nullptr) {
  275|       |        // empty
  276|    333|    }
_ZN6Assimp7Collada4NodeD2Ev:
  279|    196|    ~Node() {
  280|    376|        for (std::vector<Node *>::iterator it = mChildren.begin(); it != mChildren.end(); ++it) {
  ------------------
  |  Branch (280:68): [True: 180, False: 196]
  ------------------
  281|    180|            delete *it;
  282|    180|        }
  283|    196|    }
_ZN6Assimp7Collada8AccessorC2Ev:
  305|  3.35k|    Accessor() {
  306|  3.35k|        mCount = 0;
  307|  3.35k|        mSize = 0;
  308|  3.35k|        mOffset = 0;
  309|  3.35k|        mStride = 0;
  310|  3.35k|        mData = nullptr;
  311|  3.35k|        mSubOffset[0] = mSubOffset[1] = mSubOffset[2] = mSubOffset[3] = 0;
  312|  3.35k|    }
_ZN6Assimp7Collada12InputChannelC2Ev:
  328|    659|    InputChannel() {
  329|    659|        mType = IT_Invalid;
  330|    659|        mIndex = 0;
  331|    659|        mOffset = 0;
  332|    659|        mResolved = nullptr;
  333|    659|    }
_ZN6Assimp7Collada4MeshC2ERKNSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEE:
  345|    165|            mId(id) {
  346|  1.48k|        for (unsigned int i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++i) {
  ------------------
  |  Branch (346:34): [True: 1.32k, False: 165]
  ------------------
  347|  1.32k|            mNumUVComponents[i] = 2;
  348|  1.32k|        }
  349|    165|    }
_ZN6Assimp7Collada7SamplerC2Ev:
  460|    504|            mWrapU(true),
  461|    504|            mWrapV(true),
  462|       |            mMirrorU(),
  463|       |            mMirrorV(),
  464|    504|            mOp(aiTextureOp_Multiply),
  465|    504|            mUVId(UINT_MAX),
  466|    504|            mWeighting(1.f),
  467|    504|            mMixWithPrevious(1.f) {}
_ZN6Assimp7Collada6EffectC2Ev:
  537|     72|            mShadeType(Shade_Phong),
  538|     72|            mEmissive(0, 0, 0, 1),
  539|     72|            mAmbient(0.1f, 0.1f, 0.1f, 1),
  540|     72|            mDiffuse(0.6f, 0.6f, 0.6f, 1),
  541|     72|            mSpecular(0.4f, 0.4f, 0.4f, 1),
  542|     72|            mTransparent(0, 0, 0, 1),
  543|     72|            mShininess(10.0f),
  544|     72|            mRefractIndex(1.f),
  545|     72|            mReflectivity(0.f),
  546|     72|            mTransparency(1.f),
  547|     72|            mHasTransparency(false),
  548|     72|            mRGBTransparency(false),
  549|     72|            mInvertTransparency(false),
  550|     72|            mDoubleSided(false),
  551|     72|            mWireframe(false),
  552|     72|            mFaceted(false) {
  553|     72|    }
_ZN6Assimp7Collada9AnimationD2Ev:
  597|    428|    ~Animation() {
  598|    633|        for (std::vector<Animation *>::iterator it = mSubAnims.begin(); it != mSubAnims.end(); ++it) {
  ------------------
  |  Branch (598:73): [True: 205, False: 428]
  ------------------
  599|    205|            delete *it;
  600|    205|        }
  601|    428|    }
_ZN6Assimp7Collada9Animation30CombineSingleChannelAnimationsEv:
  614|     16|    void CombineSingleChannelAnimations() {
  615|     16|        CombineSingleChannelAnimationsRecursively(this);
  616|     16|    }
_ZN6Assimp7Collada9Animation41CombineSingleChannelAnimationsRecursivelyEPS1_:
  618|    220|    void CombineSingleChannelAnimationsRecursively(Animation *pParent) {
  619|    220|        std::set<std::string> childrenTargets;
  620|    220|        bool childrenAnimationsHaveDifferentChannels = true;
  621|       |
  622|    424|        for (std::vector<Animation *>::iterator it = pParent->mSubAnims.begin(); it != pParent->mSubAnims.end();) {
  ------------------
  |  Branch (622:82): [True: 204, False: 220]
  ------------------
  623|    204|            Animation *anim = *it;
  624|       |            // Assign the first animation name to the parent if empty.
  625|       |            // This prevents the animation name from being lost when animations are combined
  626|    204|            if (mName.empty()) {
  ------------------
  |  Branch (626:17): [True: 2, False: 202]
  ------------------
  627|      2|              mName = anim->mName;
  628|      2|            }
  629|    204|            CombineSingleChannelAnimationsRecursively(anim);
  630|       |
  631|    204|            if (childrenAnimationsHaveDifferentChannels && anim->mChannels.size() == 1 &&
  ------------------
  |  Branch (631:17): [True: 199, False: 5]
  |  Branch (631:17): [True: 198, False: 6]
  |  Branch (631:60): [True: 199, False: 0]
  ------------------
  632|    199|                    childrenTargets.find(anim->mChannels[0].mTarget) == childrenTargets.end()) {
  ------------------
  |  Branch (632:21): [True: 198, False: 1]
  ------------------
  633|    198|                childrenTargets.insert(anim->mChannels[0].mTarget);
  634|    198|            } else {
  635|      6|                childrenAnimationsHaveDifferentChannels = false;
  636|      6|            }
  637|       |
  638|    204|            ++it;
  639|    204|        }
  640|       |
  641|       |        // We only want to combine animations if they have different channels
  642|    220|        if (childrenAnimationsHaveDifferentChannels) {
  ------------------
  |  Branch (642:13): [True: 219, False: 1]
  ------------------
  643|    411|            for (std::vector<Animation *>::iterator it = pParent->mSubAnims.begin(); it != pParent->mSubAnims.end();) {
  ------------------
  |  Branch (643:86): [True: 192, False: 219]
  ------------------
  644|    192|                Animation *anim = *it;
  645|       |
  646|    192|                pParent->mChannels.push_back(anim->mChannels[0]);
  647|       |
  648|    192|                it = pParent->mSubAnims.erase(it);
  649|       |
  650|    192|                delete anim;
  651|    192|                continue;
  652|    192|            }
  653|    219|        }
  654|    220|    }
_ZN6Assimp7Collada12ChannelEntryC2Ev:
  678|  24.8k|            mValueData() {}

_ZN6Assimp13ColladaLoaderC2Ev:
  103|    624|        noSkeletonMesh(false),
  104|    624|        removeEmptyBones(false),
  105|    624|        ignoreUpDirection(false),
  106|    624|        ignoreUnitSize(false),
  107|    624|        useColladaName(false),
  108|    624|        mNodeNameCounter(0) {
  109|       |    // empty
  110|    624|}
_ZNK6Assimp13ColladaLoader7CanReadERKNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEPNS_8IOSystemEb:
  114|    320|bool ColladaLoader::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool /*checkSig*/) const {
  115|       |    // Look for a DAE file inside, but don't extract it
  116|    320|    ZipArchiveIOSystem zip_archive(pIOHandler, pFile);
  117|    320|    if (zip_archive.isOpen()) {
  ------------------
  |  Branch (117:9): [True: 10, False: 310]
  ------------------
  118|     10|        return !ColladaParser::ReadZaeManifest(zip_archive).empty();
  119|     10|    }
  120|       |
  121|    310|    static const char *tokens[] = { "<collada" };
  122|       |    return SearchFileHeaderForToken(pIOHandler, pFile, tokens, AI_COUNT_OF(tokens));
  123|    320|}
_ZN6Assimp13ColladaLoader15SetupPropertiesEPKNS_8ImporterE:
  126|     31|void ColladaLoader::SetupProperties(const Importer *pImp) {
  127|     31|    noSkeletonMesh = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_NO_SKELETON_MESHES, 0) != 0;
  128|     31|    removeEmptyBones = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_REMOVE_EMPTY_BONES, true) != 0;
  129|     31|    ignoreUpDirection = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_COLLADA_IGNORE_UP_DIRECTION, 0) != 0;
  130|     31|    ignoreUnitSize = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_COLLADA_IGNORE_UNIT_SIZE, 0) != 0;
  131|       |    useColladaName = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_COLLADA_USE_COLLADA_NAMES, 0) != 0;
  132|     31|}
_ZNK6Assimp13ColladaLoader7GetInfoEv:
  136|    665|const aiImporterDesc *ColladaLoader::GetInfo() const {
  137|    665|    return &desc;
  138|    665|}
_ZN6Assimp13ColladaLoader14InternReadFileERKNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEP7aiScenePNS_8IOSystemE:
  142|     31|void ColladaLoader::InternReadFile(const std::string &pFile, aiScene *pScene, IOSystem *pIOHandler) {
  143|     31|    mFileName = pFile;
  144|       |
  145|       |    // clean all member arrays - just for safety, it should work even if we did not
  146|     31|    mMeshIndexByID.clear();
  147|     31|    mMaterialIndexByName.clear();
  148|     31|    mMeshes.clear();
  149|     31|    mTargetMeshes.clear();
  150|     31|    newMats.clear();
  151|     31|    mLights.clear();
  152|     31|    mCameras.clear();
  153|     31|    mTextures.clear();
  154|     31|    mAnims.clear();
  155|       |
  156|       |    // parse the input file
  157|     31|    ColladaParser parser(pIOHandler, pFile);
  158|       |
  159|     31|    if (!parser.mRootNode) {
  ------------------
  |  Branch (159:9): [True: 0, False: 31]
  ------------------
  160|      0|        throw DeadlyImportError("Collada: File came out empty. Something is wrong here.");
  161|      0|    }
  162|       |
  163|       |    // reserve some storage to avoid unnecessary reallocates
  164|     31|    newMats.reserve(parser.mMaterialLibrary.size() * 2u);
  165|     31|    mMeshes.reserve(parser.mMeshLibrary.size() * 2u);
  166|       |
  167|     31|    mCameras.reserve(parser.mCameraLibrary.size());
  168|     31|    mLights.reserve(parser.mLightLibrary.size());
  169|       |
  170|       |    // create the materials first, for the meshes to find
  171|     31|    BuildMaterials(parser, pScene);
  172|       |
  173|       |    // build the node hierarchy from it
  174|     31|    pScene->mRootNode = BuildHierarchy(parser, parser.mRootNode);
  175|       |
  176|       |    // ... then fill the materials with the now adjusted settings
  177|     31|    FillMaterials(parser, pScene);
  178|       |
  179|     31|    if (!ignoreUnitSize) {
  ------------------
  |  Branch (179:9): [True: 16, False: 15]
  ------------------
  180|       |        // Apply unit-size scale calculation
  181|     16|        pScene->mRootNode->mTransformation *= aiMatrix4x4(
  182|     16|                parser.mUnitSize, 0, 0, 0,
  183|     16|                0, parser.mUnitSize, 0, 0,
  184|     16|                0, 0, parser.mUnitSize, 0,
  185|     16|                0, 0, 0, 1);
  186|     16|    }
  187|       |
  188|     31|    if (!ignoreUpDirection) {
  ------------------
  |  Branch (188:9): [True: 16, False: 15]
  ------------------
  189|       |        // Convert to Y_UP, if different orientation
  190|     16|        if (parser.mUpDirection == ColladaParser::UP_X) {
  ------------------
  |  Branch (190:13): [True: 0, False: 16]
  ------------------
  191|      0|            pScene->mRootNode->mTransformation *= aiMatrix4x4(
  192|      0|                    0, -1, 0, 0,
  193|      0|                    1, 0, 0, 0,
  194|      0|                    0, 0, 1, 0,
  195|      0|                    0, 0, 0, 1);
  196|     16|        } else if (parser.mUpDirection == ColladaParser::UP_Z) {
  ------------------
  |  Branch (196:20): [True: 6, False: 10]
  ------------------
  197|      6|            pScene->mRootNode->mTransformation *= aiMatrix4x4(
  198|      6|                    1, 0, 0, 0,
  199|      6|                    0, 0, 1, 0,
  200|      6|                    0, -1, 0, 0,
  201|      6|                    0, 0, 0, 1);
  202|      6|        }
  203|     16|    }
  204|       |
  205|       |    // Store scene metadata
  206|     31|    if (!parser.mAssetMetaData.empty()) {
  ------------------
  |  Branch (206:9): [True: 16, False: 15]
  ------------------
  207|     16|        const size_t numMeta(parser.mAssetMetaData.size());
  208|     16|        pScene->mMetaData = aiMetadata::Alloc(static_cast<unsigned int>(numMeta));
  209|     16|        size_t i = 0;
  210|    136|        for (auto it = parser.mAssetMetaData.cbegin(); it != parser.mAssetMetaData.cend(); ++it, ++i) {
  ------------------
  |  Branch (210:56): [True: 120, False: 16]
  ------------------
  211|    120|            pScene->mMetaData->Set(static_cast<unsigned int>(i), (*it).first, (*it).second);
  212|    120|        }
  213|     16|    }
  214|       |
  215|     31|    StoreSceneMeshes(pScene);
  216|     31|    StoreSceneMaterials(pScene);
  217|     31|    StoreSceneTextures(pScene);
  218|     31|    StoreSceneLights(pScene);
  219|     31|    StoreSceneCameras(pScene);
  220|     31|    StoreAnimations(pScene, parser);
  221|       |
  222|       |    // If no meshes have been loaded, it's probably just an animated skeleton.
  223|     31|    if (0u == pScene->mNumMeshes) {
  ------------------
  |  Branch (223:9): [True: 1, False: 30]
  ------------------
  224|      1|        if (!noSkeletonMesh) {
  ------------------
  |  Branch (224:13): [True: 1, False: 0]
  ------------------
  225|      1|            SkeletonMeshBuilder hero(pScene);
  226|      1|        }
  227|       |        pScene->mFlags |= AI_SCENE_FLAGS_INCOMPLETE;
  228|      1|    }
  229|     31|}
_ZN6Assimp13ColladaLoader14BuildHierarchyERKNS_13ColladaParserEPKNS_7Collada4NodeE:
  233|    196|aiNode *ColladaLoader::BuildHierarchy(const ColladaParser &pParser, const Collada::Node *pNode) {
  234|       |    // create a node for it
  235|    196|    auto *node = new aiNode();
  236|       |
  237|       |    // find a name for the new node. It's more complicated than you might think
  238|    196|    node->mName.Set(FindNameForNode(pNode));
  239|       |    // if we're not using the unique IDs, hold onto them for reference and export
  240|    196|    if (useColladaName) {
  ------------------
  |  Branch (240:9): [True: 0, False: 196]
  ------------------
  241|      0|        if (!pNode->mID.empty()) {
  ------------------
  |  Branch (241:13): [True: 0, False: 0]
  ------------------
  242|      0|            AddNodeMetaData(node, AI_METADATA_COLLADA_ID, aiString(pNode->mID));
  243|      0|        }
  244|      0|        if (!pNode->mSID.empty()) {
  ------------------
  |  Branch (244:13): [True: 0, False: 0]
  ------------------
  245|      0|            AddNodeMetaData(node, AI_METADATA_COLLADA_SID, aiString(pNode->mSID));
  246|      0|        }
  247|      0|    }
  248|       |
  249|       |    // calculate the transformation matrix for it
  250|    196|    node->mTransformation = pParser.CalculateResultTransform(pNode->mTransforms);
  251|       |
  252|       |    // now resolve node instances
  253|    196|    std::vector<const Node*> instances;
  254|    196|    ResolveNodeInstances(pParser, pNode, instances);
  255|       |
  256|       |    // add children. first the *real* ones
  257|    196|    node->mNumChildren = static_cast<unsigned int>(pNode->mChildren.size() + instances.size());
  258|    196|    if (node->mNumChildren != 0) {
  ------------------
  |  Branch (258:9): [True: 84, False: 112]
  ------------------
  259|     84|        node->mChildren = new aiNode * [node->mNumChildren];
  260|     84|    }
  261|       |
  262|    376|    for (size_t a = 0; a < pNode->mChildren.size(); ++a) {
  ------------------
  |  Branch (262:24): [True: 180, False: 196]
  ------------------
  263|    180|        node->mChildren[a] = BuildHierarchy(pParser, pNode->mChildren[a]);
  264|    180|        node->mChildren[a]->mParent = node;
  265|    180|    }
  266|       |
  267|       |    // ... and finally the resolved node instances
  268|    196|    for (size_t a = 0; a < instances.size(); ++a) {
  ------------------
  |  Branch (268:24): [True: 0, False: 196]
  ------------------
  269|      0|        node->mChildren[pNode->mChildren.size() + a] = BuildHierarchy(pParser, instances[a]);
  270|      0|        node->mChildren[pNode->mChildren.size() + a]->mParent = node;
  271|      0|    }
  272|       |
  273|    196|    BuildMeshesForNode(pParser, pNode, node);
  274|    196|    BuildCamerasForNode(pParser, pNode, node);
  275|    196|    BuildLightsForNode(pParser, pNode, node);
  276|       |
  277|    196|    return node;
  278|    196|}
_ZNK6Assimp13ColladaLoader20ResolveNodeInstancesERKNS_13ColladaParserEPKNS_7Collada4NodeERNSt3__16vectorIS7_NS8_9allocatorIS7_EEEE:
  283|    196|        std::vector<const Node*> &resolved) const {
  284|       |    // reserve enough storage
  285|    196|    resolved.reserve(pNode->mNodeInstances.size());
  286|       |
  287|       |    // ... and iterate through all nodes to be instanced as children of pNode
  288|    196|    for (const auto &[mNode] : pNode->mNodeInstances) {
  ------------------
  |  Branch (288:30): [True: 0, False: 196]
  ------------------
  289|       |        // find the corresponding node in the library
  290|      0|        const auto itt = pParser.mNodeLibrary.find(mNode);
  291|      0|        const Node *nd = itt == pParser.mNodeLibrary.end() ? nullptr : (*itt).second;
  ------------------
  |  Branch (291:26): [True: 0, False: 0]
  ------------------
  292|       |
  293|       |        // FIX for http://sourceforge.net/tracker/?func=detail&aid=3054873&group_id=226462&atid=1067632
  294|       |        // need to check for both name and ID to catch all. To avoid breaking valid files,
  295|       |        // the workaround is only enabled when the first attempt to resolve the node has failed.
  296|      0|        if (nullptr == nd) {
  ------------------
  |  Branch (296:13): [True: 0, False: 0]
  ------------------
  297|      0|            nd = FindNode(pParser.mRootNode, mNode);
  298|      0|        }
  299|      0|        if (nullptr == nd) {
  ------------------
  |  Branch (299:13): [True: 0, False: 0]
  ------------------
  300|      0|            ASSIMP_LOG_ERROR("Collada: Unable to resolve reference to instanced node ", mNode);
  301|      0|        } else {
  302|       |            //  attach this node to the list of children
  303|      0|            resolved.push_back(nd);
  304|      0|        }
  305|      0|    }
  306|    196|}
_ZN6Assimp13ColladaLoader18BuildLightsForNodeERKNS_13ColladaParserEPKNS_7Collada4NodeEP6aiNode:
  325|    196|void ColladaLoader::BuildLightsForNode(const ColladaParser &pParser, const Node *pNode, aiNode *pTarget) {
  326|    196|    for (const LightInstance &lid : pNode->mLights) {
  ------------------
  |  Branch (326:35): [True: 15, False: 196]
  ------------------
  327|       |        // find the referred light
  328|     15|        auto srcLightIt = pParser.mLightLibrary.find(lid.mLight);
  329|     15|        if (srcLightIt == pParser.mLightLibrary.end()) {
  ------------------
  |  Branch (329:13): [True: 0, False: 15]
  ------------------
  330|      0|            ASSIMP_LOG_WARN("Collada: Unable to find light for ID \"", lid.mLight, "\". Skipping.");
  331|      0|            continue;
  332|      0|        }
  333|     15|        const Collada::Light *srcLight = &srcLightIt->second;
  334|       |
  335|       |        // now fill our ai data structure
  336|     15|        auto out = new aiLight();
  337|     15|        out->mName = pTarget->mName;
  338|     15|        out->mType = (aiLightSourceType)srcLight->mType;
  339|       |
  340|       |        // collada lights point in -Z by default, rest is specified in node transform
  341|     15|        out->mDirection = aiVector3D(0.f, 0.f, -1.f);
  342|       |
  343|     15|        out->mAttenuationConstant = srcLight->mAttConstant;
  344|     15|        out->mAttenuationLinear = srcLight->mAttLinear;
  345|     15|        out->mAttenuationQuadratic = srcLight->mAttQuadratic;
  346|       |
  347|     15|        out->mColorDiffuse = out->mColorSpecular = out->mColorAmbient = srcLight->mColor * srcLight->mIntensity;
  348|     15|        if (out->mType == aiLightSource_AMBIENT) {
  ------------------
  |  Branch (348:13): [True: 1, False: 14]
  ------------------
  349|      1|            out->mColorDiffuse = out->mColorSpecular = aiColor3D(0, 0, 0);
  350|      1|            out->mColorAmbient = srcLight->mColor * srcLight->mIntensity;
  351|     14|        } else {
  352|       |            // collada doesn't differentiate between these color types
  353|     14|            out->mColorDiffuse = out->mColorSpecular = srcLight->mColor * srcLight->mIntensity;
  354|     14|            out->mColorAmbient = aiColor3D(0, 0, 0);
  355|     14|        }
  356|       |
  357|       |        // convert falloff angle and falloff exponent in our representation, if given
  358|     15|        if (out->mType == aiLightSource_SPOT) {
  ------------------
  |  Branch (358:13): [True: 1, False: 14]
  ------------------
  359|      1|            out->mAngleInnerCone = AI_DEG_TO_RAD(srcLight->mFalloffAngle);
  360|       |
  361|       |            // ... some extension magic.
  362|      1|            if (srcLight->mOuterAngle >= ASSIMP_COLLADA_LIGHT_ANGLE_NOT_SET * (1 - ai_epsilon)) {
  ------------------
  |  |  151|      1|#define ASSIMP_COLLADA_LIGHT_ANGLE_NOT_SET 1e9f
  ------------------
  |  Branch (362:17): [True: 1, False: 0]
  ------------------
  363|       |                // ... some deprecation magic.
  364|      1|                if (srcLight->mPenumbraAngle >= ASSIMP_COLLADA_LIGHT_ANGLE_NOT_SET * (1 - ai_epsilon)) {
  ------------------
  |  |  151|      1|#define ASSIMP_COLLADA_LIGHT_ANGLE_NOT_SET 1e9f
  ------------------
  |  Branch (364:21): [True: 1, False: 0]
  ------------------
  365|       |                    // Need to rely on falloff_exponent. I don't know how to interpret it, so I need to guess ....
  366|       |                    // epsilon chosen to be 0.1
  367|      1|                    float f = 1.0f;
  368|      1|                    if ( 0.0f != srcLight->mFalloffExponent ) {
  ------------------
  |  Branch (368:26): [True: 1, False: 0]
  ------------------
  369|      1|                        f = 1.f / srcLight->mFalloffExponent;
  370|      1|                    }
  371|      1|                    out->mAngleOuterCone = std::acos(std::pow(0.1f, f)) +
  372|      1|                                           out->mAngleInnerCone;
  373|      1|                } else {
  374|      0|                    out->mAngleOuterCone = out->mAngleInnerCone + AI_DEG_TO_RAD(srcLight->mPenumbraAngle);
  375|      0|                    if (out->mAngleOuterCone < out->mAngleInnerCone)
  ------------------
  |  Branch (375:25): [True: 0, False: 0]
  ------------------
  376|      0|                        std::swap(out->mAngleInnerCone, out->mAngleOuterCone);
  377|      0|                }
  378|      1|            } else {
  379|      0|                out->mAngleOuterCone = AI_DEG_TO_RAD(srcLight->mOuterAngle);
  380|      0|            }
  381|      1|        }
  382|       |
  383|       |        // add to light list
  384|     15|        mLights.push_back(out);
  385|     15|    }
  386|    196|}
_ZN6Assimp13ColladaLoader19BuildCamerasForNodeERKNS_13ColladaParserEPKNS_7Collada4NodeEP6aiNode:
  390|    196|void ColladaLoader::BuildCamerasForNode(const ColladaParser &pParser, const Node *pNode, aiNode *pTarget) {
  391|    196|    for (const CameraInstance &cid : pNode->mCameras) {
  ------------------
  |  Branch (391:36): [True: 10, False: 196]
  ------------------
  392|       |        // find the referred light
  393|     10|        auto srcCameraIt = pParser.mCameraLibrary.find(cid.mCamera);
  394|     10|        if (srcCameraIt == pParser.mCameraLibrary.end()) {
  ------------------
  |  Branch (394:13): [True: 0, False: 10]
  ------------------
  395|      0|            ASSIMP_LOG_WARN("Collada: Unable to find camera for ID \"", cid.mCamera, "\". Skipping.");
  396|      0|            continue;
  397|      0|        }
  398|     10|        const Collada::Camera *srcCamera = &srcCameraIt->second;
  399|       |
  400|       |        // orthographic cameras not yet supported in Assimp
  401|     10|        if (srcCamera->mOrtho) {
  ------------------
  |  Branch (401:13): [True: 0, False: 10]
  ------------------
  402|      0|            ASSIMP_LOG_WARN("Collada: Orthographic cameras are not supported.");
  403|      0|        }
  404|       |
  405|       |        // now fill our ai data structure
  406|     10|        auto *out = new aiCamera();
  407|     10|        out->mName = pTarget->mName;
  408|       |
  409|       |        // collada cameras point in -Z by default, rest is specified in node transform
  410|     10|        out->mLookAt = aiVector3D(0.f, 0.f, -1.f);
  411|       |
  412|       |        // near/far z is already ok
  413|     10|        out->mClipPlaneFar = srcCamera->mZFar;
  414|     10|        out->mClipPlaneNear = srcCamera->mZNear;
  415|       |
  416|       |        // ... but for the rest some values are optional
  417|       |        // and we need to compute the others in any combination.
  418|     10|        if (srcCamera->mAspect != 10e10f) {
  ------------------
  |  Branch (418:13): [True: 10, False: 0]
  ------------------
  419|     10|            out->mAspect = srcCamera->mAspect;
  420|     10|        }
  421|       |
  422|     10|        if (srcCamera->mHorFov != 10e10f) {
  ------------------
  |  Branch (422:13): [True: 0, False: 10]
  ------------------
  423|      0|            out->mHorizontalFOV = srcCamera->mHorFov;
  424|       |
  425|      0|            if (srcCamera->mVerFov != 10e10f && srcCamera->mAspect == 10e10f) {
  ------------------
  |  Branch (425:17): [True: 0, False: 0]
  |  Branch (425:49): [True: 0, False: 0]
  ------------------
  426|      0|                out->mAspect = std::tan(AI_DEG_TO_RAD(srcCamera->mHorFov)) /
  427|      0|                               std::tan(AI_DEG_TO_RAD(srcCamera->mVerFov));
  428|      0|            }
  429|       |
  430|     10|        } else if (srcCamera->mAspect != 10e10f && srcCamera->mVerFov != 10e10f) {
  ------------------
  |  Branch (430:20): [True: 10, False: 0]
  |  Branch (430:52): [True: 10, False: 0]
  ------------------
  431|     10|            out->mHorizontalFOV = 2.0f * AI_RAD_TO_DEG(std::atan(srcCamera->mAspect *
  432|     10|                                                                 std::tan(AI_DEG_TO_RAD(srcCamera->mVerFov) * 0.5f)));
  433|     10|        }
  434|       |
  435|       |        // Collada uses degrees, we use radians
  436|     10|        out->mHorizontalFOV = AI_DEG_TO_RAD(out->mHorizontalFOV);
  437|       |
  438|       |        // add to camera list
  439|     10|        mCameras.push_back(out);
  440|     10|    }
  441|    196|}
_ZN6Assimp13ColladaLoader18BuildMeshesForNodeERKNS_13ColladaParserEPKNS_7Collada4NodeEP6aiNode:
  445|    196|void ColladaLoader::BuildMeshesForNode(const ColladaParser &pParser, const Node *pNode, aiNode *pTarget) {
  446|       |    // accumulated mesh references by this node
  447|    196|    std::vector<size_t> newMeshRefs;
  448|    196|    newMeshRefs.reserve(pNode->mMeshes.size());
  449|       |
  450|       |    // add a mesh for each subgroup in each collada mesh
  451|    196|    for (const MeshInstance &mid : pNode->mMeshes) {
  ------------------
  |  Branch (451:34): [True: 85, False: 196]
  ------------------
  452|     85|        const Mesh *srcMesh = nullptr;
  453|     85|        const Controller *srcController = nullptr;
  454|       |
  455|       |        // find the referred mesh
  456|     85|        auto srcMeshIt = pParser.mMeshLibrary.find(mid.mMeshOrController);
  457|     85|        if (srcMeshIt == pParser.mMeshLibrary.end()) {
  ------------------
  |  Branch (457:13): [True: 1, False: 84]
  ------------------
  458|       |            // if not found in the mesh-library, it might also be a controller referring to a mesh
  459|      1|            auto srcContrIt = pParser.mControllerLibrary.find(mid.mMeshOrController);
  460|      1|            if (srcContrIt != pParser.mControllerLibrary.end()) {
  ------------------
  |  Branch (460:17): [True: 1, False: 0]
  ------------------
  461|      1|                srcController = &srcContrIt->second;
  462|      1|                srcMeshIt = pParser.mMeshLibrary.find(srcController->mMeshId);
  463|      1|                if (srcMeshIt != pParser.mMeshLibrary.end()) {
  ------------------
  |  Branch (463:21): [True: 1, False: 0]
  ------------------
  464|      1|                    srcMesh = srcMeshIt->second;
  465|      1|                }
  466|      1|            }
  467|       |
  468|      1|            if (nullptr == srcMesh) {
  ------------------
  |  Branch (468:17): [True: 0, False: 1]
  ------------------
  469|      0|                ASSIMP_LOG_WARN("Collada: Unable to find geometry for ID \"", mid.mMeshOrController, "\". Skipping.");
  470|      0|                continue;
  471|      0|            }
  472|     84|        } else {
  473|       |            // ID found in the mesh library -> direct reference to a not skinned mesh
  474|     84|            srcMesh = srcMeshIt->second;
  475|     84|        }
  476|       |
  477|       |        // build a mesh for each of its subgroups
  478|     85|        size_t vertexStart = 0, faceStart = 0;
  479|    175|        for (size_t sm = 0; sm < srcMesh->mSubMeshes.size(); ++sm) {
  ------------------
  |  Branch (479:29): [True: 90, False: 85]
  ------------------
  480|     90|            const Collada::SubMesh &submesh = srcMesh->mSubMeshes[sm];
  481|     90|            if (submesh.mNumFaces == 0) {
  ------------------
  |  Branch (481:17): [True: 0, False: 90]
  ------------------
  482|      0|                continue;
  483|      0|            }
  484|       |
  485|       |            // find material assigned to this submesh
  486|     90|            std::string meshMaterial;
  487|     90|            auto meshMatIt = mid.mMaterials.find(submesh.mMaterial);
  488|       |
  489|     90|            const Collada::SemanticMappingTable *table = nullptr;
  490|     90|            if (meshMatIt != mid.mMaterials.end()) {
  ------------------
  |  Branch (490:17): [True: 25, False: 65]
  ------------------
  491|     25|                table = &meshMatIt->second;
  492|     25|                meshMaterial = table->mMatName;
  493|     65|            } else {
  494|     65|                ASSIMP_LOG_WARN("Collada: No material specified for subgroup <", submesh.mMaterial, "> in geometry <",
  495|     65|                        mid.mMeshOrController, ">.");
  496|     65|                if (!mid.mMaterials.empty()) {
  ------------------
  |  Branch (496:21): [True: 0, False: 65]
  ------------------
  497|      0|                    meshMaterial = mid.mMaterials.begin()->second.mMatName;
  498|      0|                }
  499|     65|            }
  500|       |
  501|       |            // OK ... here the *real* fun starts ... we have the vertex-input-to-effect-semantic-table
  502|       |            // given. The only mapping stuff which we do actually support is the UV channel.
  503|     90|            auto matIt = mMaterialIndexByName.find(meshMaterial);
  504|     90|            unsigned int matIdx = 0;
  505|     90|            if (matIt != mMaterialIndexByName.end()) {
  ------------------
  |  Branch (505:17): [True: 25, False: 65]
  ------------------
  506|     25|                matIdx = static_cast<unsigned int>(matIt->second);
  507|     25|            }
  508|       |
  509|     90|            if (table && !table->mMap.empty()) {
  ------------------
  |  Branch (509:17): [True: 25, False: 65]
  |  Branch (509:26): [True: 13, False: 12]
  ------------------
  510|     13|                std::pair<Collada::Effect *, aiMaterial *> &mat = newMats[matIdx];
  511|       |
  512|       |                // Iterate through all texture channels assigned to the effect and
  513|       |                // check whether we have mapping information for it.
  514|     13|                ApplyVertexToEffectSemanticMapping(mat.first->mTexDiffuse, *table);
  515|     13|                ApplyVertexToEffectSemanticMapping(mat.first->mTexAmbient, *table);
  516|     13|                ApplyVertexToEffectSemanticMapping(mat.first->mTexSpecular, *table);
  517|     13|                ApplyVertexToEffectSemanticMapping(mat.first->mTexEmissive, *table);
  518|     13|                ApplyVertexToEffectSemanticMapping(mat.first->mTexTransparent, *table);
  519|     13|                ApplyVertexToEffectSemanticMapping(mat.first->mTexBump, *table);
  520|     13|            }
  521|       |
  522|       |            // built lookup index of the Mesh-Submesh-Material combination
  523|     90|            ColladaMeshIndex index(mid.mMeshOrController, sm, meshMaterial);
  524|       |
  525|       |            // if we already have the mesh at the library, just add its index to the node's array
  526|     90|            auto dstMeshIt = mMeshIndexByID.find(index);
  527|     90|            if (dstMeshIt != mMeshIndexByID.end()) {
  ------------------
  |  Branch (527:17): [True: 0, False: 90]
  ------------------
  528|      0|                newMeshRefs.push_back(dstMeshIt->second);
  529|     90|            } else {
  530|       |                // else we have to add the mesh to the collection and store its newly assigned index at the node
  531|     90|                aiMesh *dstMesh = CreateMesh(pParser, srcMesh, submesh, srcController, vertexStart, faceStart);
  532|       |
  533|       |                // store the mesh, and store its new index in the node
  534|     90|                newMeshRefs.push_back(mMeshes.size());
  535|     90|                mMeshIndexByID[index] = mMeshes.size();
  536|     90|                mMeshes.push_back(dstMesh);
  537|     90|                vertexStart += dstMesh->mNumVertices;
  538|     90|                faceStart += submesh.mNumFaces;
  539|       |
  540|       |                // assign the material index
  541|     90|                auto subMatIt = mMaterialIndexByName.find(submesh.mMaterial);
  542|     90|                if (subMatIt != mMaterialIndexByName.end()) {
  ------------------
  |  Branch (542:21): [True: 10, False: 80]
  ------------------
  543|     10|                    dstMesh->mMaterialIndex = static_cast<unsigned int>(subMatIt->second);
  544|     80|                } else {
  545|     80|                    dstMesh->mMaterialIndex = matIdx;
  546|     80|                }
  547|     90|                if (dstMesh->mName.length == 0) {
  ------------------
  |  Branch (547:21): [True: 0, False: 90]
  ------------------
  548|      0|                    dstMesh->mName = mid.mMeshOrController;
  549|      0|                }
  550|     90|            }
  551|     90|        }
  552|     85|    }
  553|       |
  554|       |    // now place all mesh references we gathered in the target node
  555|    196|    pTarget->mNumMeshes = static_cast<unsigned int>(newMeshRefs.size());
  556|    196|    if (!newMeshRefs.empty()) {
  ------------------
  |  Branch (556:9): [True: 85, False: 111]
  ------------------
  557|     85|        struct UIntTypeConverter {
  558|     85|            unsigned int operator()(const size_t &v) const {
  559|     85|                return static_cast<unsigned int>(v);
  560|     85|            }
  561|     85|        };
  562|       |
  563|     85|        pTarget->mMeshes = new unsigned int[pTarget->mNumMeshes];
  564|     85|        std::transform(newMeshRefs.begin(), newMeshRefs.end(), pTarget->mMeshes, UIntTypeConverter());
  565|     85|    }
  566|    196|}
_ZN6Assimp13ColladaLoader10CreateMeshERKNS_13ColladaParserEPKNS_7Collada4MeshERKNS4_7SubMeshEPKNS4_10ControllerEmm:
  593|     90|        const Controller *pSrcController, size_t pStartVertex, size_t pStartFace) {
  594|     90|    std::unique_ptr<aiMesh> dstMesh(new aiMesh);
  595|       |
  596|     90|    if (useColladaName) {
  ------------------
  |  Branch (596:9): [True: 0, False: 90]
  ------------------
  597|      0|        dstMesh->mName = pSrcMesh->mName;
  598|     90|    } else {
  599|     90|        dstMesh->mName = pSrcMesh->mId;
  600|     90|    }
  601|       |
  602|     90|    if (pSrcMesh->mPositions.empty()) {
  ------------------
  |  Branch (602:9): [True: 0, False: 90]
  ------------------
  603|      0|        return dstMesh.release();
  604|      0|    }
  605|       |
  606|       |    // count the vertices addressed by its faces
  607|     90|    const size_t numVertices = std::accumulate(pSrcMesh->mFaceSize.begin() + pStartFace,
  608|     90|            pSrcMesh->mFaceSize.begin() + pStartFace + pSubMesh.mNumFaces, size_t(0));
  609|       |
  610|       |    // copy positions
  611|     90|    dstMesh->mNumVertices = static_cast<unsigned int>(numVertices);
  612|     90|    dstMesh->mVertices = new aiVector3D[numVertices];
  613|     90|    std::copy(pSrcMesh->mPositions.begin() + pStartVertex, pSrcMesh->mPositions.begin() + pStartVertex + numVertices, dstMesh->mVertices);
  614|       |
  615|       |    // normals, if given. HACK: (thom) Due to the glorious Collada spec we never
  616|       |    // know if we have the same number of normals as there are positions. So we
  617|       |    // also ignore any vertex attribute if it has a different count
  618|     90|    if (pSrcMesh->mNormals.size() >= pStartVertex + numVertices) {
  ------------------
  |  Branch (618:9): [True: 90, False: 0]
  ------------------
  619|     90|        dstMesh->mNormals = new aiVector3D[numVertices];
  620|     90|        std::copy(pSrcMesh->mNormals.begin() + pStartVertex, pSrcMesh->mNormals.begin() + pStartVertex + numVertices, dstMesh->mNormals);
  621|     90|    }
  622|       |
  623|       |    // tangents, if given.
  624|     90|    if (pSrcMesh->mTangents.size() >= pStartVertex + numVertices) {
  ------------------
  |  Branch (624:9): [True: 0, False: 90]
  ------------------
  625|      0|        dstMesh->mTangents = new aiVector3D[numVertices];
  626|      0|        std::copy(pSrcMesh->mTangents.begin() + pStartVertex, pSrcMesh->mTangents.begin() + pStartVertex + numVertices, dstMesh->mTangents);
  627|      0|    }
  628|       |
  629|       |    // bi-tangents, if given.
  630|     90|    if (pSrcMesh->mBitangents.size() >= pStartVertex + numVertices) {
  ------------------
  |  Branch (630:9): [True: 0, False: 90]
  ------------------
  631|      0|        dstMesh->mBitangents = new aiVector3D[numVertices];
  632|      0|        std::copy(pSrcMesh->mBitangents.begin() + pStartVertex, pSrcMesh->mBitangents.begin() + pStartVertex + numVertices, dstMesh->mBitangents);
  633|      0|    }
  634|       |
  635|       |    // same for texture coords, as many as we have
  636|    810|    for (size_t a = 0; a < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++a) {
  ------------------
  |  Branch (636:24): [True: 720, False: 90]
  ------------------
  637|    720|        if (pSrcMesh->mTexCoords[a].size() >= pStartVertex + numVertices) {
  ------------------
  |  Branch (637:13): [True: 84, False: 636]
  ------------------
  638|     84|            dstMesh->mTextureCoords[a] = new aiVector3D[numVertices];
  639|  59.8k|            for (size_t b = 0; b < numVertices; ++b) {
  ------------------
  |  Branch (639:32): [True: 59.7k, False: 84]
  ------------------
  640|  59.7k|                dstMesh->mTextureCoords[a][b] = pSrcMesh->mTexCoords[a][pStartVertex + b];
  641|  59.7k|            }
  642|       |
  643|     84|            dstMesh->mNumUVComponents[a] = pSrcMesh->mNumUVComponents[a];
  644|     84|        }
  645|    720|    }
  646|       |
  647|       |    // same for vertex colors, as many as we have. again the same packing to avoid empty slots
  648|    810|    for (size_t a = 0, real = 0; a < AI_MAX_NUMBER_OF_COLOR_SETS; ++a) {
  ------------------
  |  Branch (648:34): [True: 720, False: 90]
  ------------------
  649|    720|        if (pSrcMesh->mColors[a].size() >= pStartVertex + numVertices) {
  ------------------
  |  Branch (649:13): [True: 1, False: 719]
  ------------------
  650|      1|            dstMesh->mColors[real] = new aiColor4D[numVertices];
  651|      1|            std::copy(pSrcMesh->mColors[a].begin() + pStartVertex, pSrcMesh->mColors[a].begin() + pStartVertex + numVertices, dstMesh->mColors[real]);
  652|      1|            ++real;
  653|      1|        }
  654|    720|    }
  655|       |
  656|       |    // create faces. Due to the fact that each face uses unique vertices, we can simply count up on each vertex
  657|     90|    size_t vertex = 0;
  658|     90|    dstMesh->mNumFaces = static_cast<unsigned int>(pSubMesh.mNumFaces);
  659|     90|    dstMesh->mFaces = new aiFace[dstMesh->mNumFaces];
  660|  32.1k|    for (size_t a = 0; a < dstMesh->mNumFaces; ++a) {
  ------------------
  |  Branch (660:24): [True: 32.0k, False: 90]
  ------------------
  661|  32.0k|        size_t s = pSrcMesh->mFaceSize[pStartFace + a];
  662|  32.0k|        aiFace &face = dstMesh->mFaces[a];
  663|  32.0k|        face.mNumIndices = static_cast<unsigned int>(s);
  664|  32.0k|        face.mIndices = new unsigned int[s];
  665|   135k|        for (size_t b = 0; b < s; ++b) {
  ------------------
  |  Branch (665:28): [True: 103k, False: 32.0k]
  ------------------
  666|   103k|            face.mIndices[b] = static_cast<unsigned int>(vertex++);
  667|   103k|        }
  668|  32.0k|    }
  669|       |
  670|       |    // create morph target meshes if any
  671|     90|    std::vector<aiMesh *> targetMeshes;
  672|     90|    std::vector<float> targetWeights;
  673|     90|    Collada::MorphMethod method = Normalized;
  674|       |
  675|     90|    for (auto it = pParser.mControllerLibrary.begin();
  676|     91|            it != pParser.mControllerLibrary.end(); ++it) {
  ------------------
  |  Branch (676:13): [True: 1, False: 90]
  ------------------
  677|      1|        const Controller &c = it->second;
  678|      1|        const Collada::Mesh *baseMesh = pParser.ResolveLibraryReference(pParser.mMeshLibrary, c.mMeshId);
  679|       |
  680|      1|        if (c.mType == Collada::Morph && baseMesh->mName == pSrcMesh->mName) {
  ------------------
  |  Branch (680:13): [True: 0, False: 1]
  |  Branch (680:42): [True: 0, False: 0]
  ------------------
  681|      0|            const Collada::Accessor &targetAccessor = pParser.ResolveLibraryReference(pParser.mAccessorLibrary, c.mMorphTarget);
  682|      0|            const Collada::Accessor &weightAccessor = pParser.ResolveLibraryReference(pParser.mAccessorLibrary, c.mMorphWeight);
  683|      0|            const Collada::Data &targetData = pParser.ResolveLibraryReference(pParser.mDataLibrary, targetAccessor.mSource);
  684|      0|            const Collada::Data &weightData = pParser.ResolveLibraryReference(pParser.mDataLibrary, weightAccessor.mSource);
  685|       |
  686|       |            // take method
  687|      0|            method = c.mMethod;
  688|       |
  689|      0|            if (!targetData.mIsStringArray) {
  ------------------
  |  Branch (689:17): [True: 0, False: 0]
  ------------------
  690|      0|                throw DeadlyImportError("target data must contain id. ");
  691|      0|            }
  692|      0|            if (weightData.mIsStringArray) {
  ------------------
  |  Branch (692:17): [True: 0, False: 0]
  ------------------
  693|      0|                throw DeadlyImportError("target weight data must not be textual ");
  694|      0|            }
  695|       |
  696|      0|            for (const auto & mString : targetData.mStrings) {
  ------------------
  |  Branch (696:39): [True: 0, False: 0]
  ------------------
  697|      0|                const Mesh *targetMesh = pParser.ResolveLibraryReference(pParser.mMeshLibrary, mString);
  698|       |
  699|      0|                aiMesh *aimesh = findMesh(useColladaName ? targetMesh->mName : targetMesh->mId);
  ------------------
  |  Branch (699:43): [True: 0, False: 0]
  ------------------
  700|      0|                if (!aimesh) {
  ------------------
  |  Branch (700:21): [True: 0, False: 0]
  ------------------
  701|      0|                    if (targetMesh->mSubMeshes.size() > 1) {
  ------------------
  |  Branch (701:25): [True: 0, False: 0]
  ------------------
  702|      0|                        throw DeadlyImportError("Morphing target mesh must be a single");
  703|      0|                    }
  704|      0|                    aimesh = CreateMesh(pParser, targetMesh, targetMesh->mSubMeshes.at(0), nullptr, 0, 0);
  705|      0|                    mTargetMeshes.push_back(aimesh);
  706|      0|                }
  707|      0|                targetMeshes.push_back(aimesh);
  708|      0|            }
  709|      0|            for (float mValue : weightData.mValues) {
  ------------------
  |  Branch (709:31): [True: 0, False: 0]
  ------------------
  710|      0|                targetWeights.push_back(mValue);
  711|      0|            }
  712|      0|        }
  713|      1|    }
  714|     90|    if (!targetMeshes.empty() && targetWeights.size() == targetMeshes.size()) {
  ------------------
  |  Branch (714:9): [True: 0, False: 90]
  |  Branch (714:34): [True: 0, False: 0]
  ------------------
  715|      0|        std::vector<aiAnimMesh *> animMeshes;
  716|      0|        for (unsigned int i = 0; i < targetMeshes.size(); ++i) {
  ------------------
  |  Branch (716:34): [True: 0, False: 0]
  ------------------
  717|      0|            aiMesh *targetMesh = targetMeshes.at(i);
  718|      0|            aiAnimMesh *animMesh = aiCreateAnimMesh(targetMesh);
  719|      0|            float weight = targetWeights[i];
  720|      0|            animMesh->mWeight = weight == 0 ? 1.0f : weight;
  ------------------
  |  Branch (720:33): [True: 0, False: 0]
  ------------------
  721|      0|            animMesh->mName = targetMesh->mName;
  722|      0|            animMeshes.push_back(animMesh);
  723|      0|        }
  724|      0|        dstMesh->mMethod = (method == Relative) ? aiMorphingMethod_MORPH_RELATIVE : aiMorphingMethod_MORPH_NORMALIZED;
  ------------------
  |  Branch (724:28): [True: 0, False: 0]
  ------------------
  725|      0|        dstMesh->mAnimMeshes = new aiAnimMesh *[animMeshes.size()];
  726|      0|        dstMesh->mNumAnimMeshes = static_cast<unsigned int>(animMeshes.size());
  727|      0|        for (unsigned int i = 0; i < animMeshes.size(); ++i) {
  ------------------
  |  Branch (727:34): [True: 0, False: 0]
  ------------------
  728|      0|            dstMesh->mAnimMeshes[i] = animMeshes.at(i);
  729|      0|        }
  730|      0|    }
  731|       |
  732|       |    // create bones if given
  733|     90|    if (pSrcController && pSrcController->mType == Collada::Skin) {
  ------------------
  |  Branch (733:9): [True: 1, False: 89]
  |  Branch (733:27): [True: 1, False: 0]
  ------------------
  734|       |        // resolve references - joint names
  735|      1|        const Collada::Accessor &jointNamesAcc = pParser.ResolveLibraryReference(pParser.mAccessorLibrary, pSrcController->mJointNameSource);
  736|      1|        const Collada::Data &jointNames = pParser.ResolveLibraryReference(pParser.mDataLibrary, jointNamesAcc.mSource);
  737|       |        // joint offset matrices
  738|      1|        const Collada::Accessor &jointMatrixAcc = pParser.ResolveLibraryReference(pParser.mAccessorLibrary, pSrcController->mJointOffsetMatrixSource);
  739|      1|        const Collada::Data &jointMatrices = pParser.ResolveLibraryReference(pParser.mDataLibrary, jointMatrixAcc.mSource);
  740|       |        // joint vertex_weight name list - should refer to the same list as the joint names above. If not, report and reconsider
  741|      1|        const Collada::Accessor &weightNamesAcc = pParser.ResolveLibraryReference(pParser.mAccessorLibrary, pSrcController->mWeightInputJoints.mAccessor);
  742|      1|        if (&weightNamesAcc != &jointNamesAcc)
  ------------------
  |  Branch (742:13): [True: 0, False: 1]
  ------------------
  743|      0|            throw DeadlyImportError("Temporary implementational laziness. If you read this, please report to the author.");
  744|       |        // vertex weights
  745|      1|        const Collada::Accessor &weightsAcc = pParser.ResolveLibraryReference(pParser.mAccessorLibrary, pSrcController->mWeightInputWeights.mAccessor);
  746|      1|        const Collada::Data &weights = pParser.ResolveLibraryReference(pParser.mDataLibrary, weightsAcc.mSource);
  747|       |
  748|      1|        if (!jointNames.mIsStringArray || jointMatrices.mIsStringArray || weights.mIsStringArray) {
  ------------------
  |  Branch (748:13): [True: 0, False: 1]
  |  Branch (748:43): [True: 0, False: 1]
  |  Branch (748:75): [True: 0, False: 1]
  ------------------
  749|      0|            throw DeadlyImportError("Data type mismatch while resolving mesh joints");
  750|      0|        }
  751|       |        // sanity check: we rely on the vertex weights always coming as pairs of BoneIndex-WeightIndex
  752|      1|        if (pSrcController->mWeightInputJoints.mOffset != 0 || pSrcController->mWeightInputWeights.mOffset != 1) {
  ------------------
  |  Branch (752:13): [True: 0, False: 1]
  |  Branch (752:64): [True: 0, False: 1]
  ------------------
  753|      0|            throw DeadlyImportError("Unsupported vertex_weight addressing scheme. ");
  754|      0|        }
  755|       |
  756|       |        // create containers to collect the weights for each bone
  757|      1|        size_t numBones = jointNames.mStrings.size();
  758|      1|        std::vector<std::vector<aiVertexWeight>> dstBones(numBones);
  759|       |
  760|       |        // build a temporary array of pointers to the start of each vertex's weights
  761|      1|        using IndexPairVector = std::vector<std::pair<size_t, size_t>>;
  762|      1|        std::vector<IndexPairVector::const_iterator> weightStartPerVertex;
  763|      1|        weightStartPerVertex.resize(pSrcController->mWeightCounts.size(), pSrcController->mWeights.end());
  764|       |
  765|      1|        auto pit = pSrcController->mWeights.begin();
  766|     73|        for (size_t a = 0; a < pSrcController->mWeightCounts.size(); ++a) {
  ------------------
  |  Branch (766:28): [True: 72, False: 1]
  ------------------
  767|     72|            weightStartPerVertex[a] = pit;
  768|     72|            pit += pSrcController->mWeightCounts[a];
  769|     72|        }
  770|       |
  771|       |        // now for each vertex put the corresponding vertex weights into each bone's weight collection
  772|    105|        for (size_t a = pStartVertex; a < pStartVertex + numVertices; ++a) {
  ------------------
  |  Branch (772:39): [True: 104, False: 1]
  ------------------
  773|       |            // which position index was responsible for this vertex? that's also the index by which
  774|       |            // the controller assigns the vertex weights
  775|    104|            size_t orgIndex = pSrcMesh->mFacePosIndices[a];
  776|       |            // find the vertex weights for this vertex
  777|    104|            auto iit = weightStartPerVertex[orgIndex];
  778|    104|            size_t pairCount = pSrcController->mWeightCounts[orgIndex];
  779|       |
  780|    265|            for (size_t b = 0; b < pairCount; ++b, ++iit) {
  ------------------
  |  Branch (780:32): [True: 161, False: 104]
  ------------------
  781|    161|                const size_t jointIndex = iit->first;
  782|    161|                const size_t vertexIndex = iit->second;
  783|    161|                ai_real weight = 1.0f;
  784|    161|                if (!weights.mValues.empty()) {
  ------------------
  |  Branch (784:21): [True: 161, False: 0]
  ------------------
  785|    161|                    weight = ReadFloat(weightsAcc, weights, vertexIndex, 0);
  786|    161|                }
  787|       |
  788|       |                // one day I gonna kill that XSI Collada exporter
  789|    161|                if (weight > 0.0f) {
  ------------------
  |  Branch (789:21): [True: 161, False: 0]
  ------------------
  790|    161|                    aiVertexWeight w;
  791|    161|                    w.mVertexId = static_cast<unsigned int>(a - pStartVertex);
  792|    161|                    w.mWeight = weight;
  793|    161|                    dstBones[jointIndex].push_back(w);
  794|    161|                }
  795|    161|            }
  796|    104|        }
  797|       |
  798|       |        // count the number of bones which influence vertices of the current submesh
  799|      1|        size_t numRemainingBones = 0;
  800|      5|        for (const auto & dstBone : dstBones) {
  ------------------
  |  Branch (800:35): [True: 5, False: 1]
  ------------------
  801|      5|            if (dstBone.empty() && removeEmptyBones) {
  ------------------
  |  Branch (801:17): [True: 1, False: 4]
  |  Branch (801:36): [True: 1, False: 0]
  ------------------
  802|      1|                continue;
  803|      1|            }
  804|      4|            ++numRemainingBones;
  805|      4|        }
  806|       |
  807|       |        // create bone array and copy bone weights one by one
  808|      1|        dstMesh->mNumBones = static_cast<unsigned int>(numRemainingBones);
  809|      1|        dstMesh->mBones = new aiBone *[numRemainingBones];
  810|      1|        size_t boneCount = 0;
  811|      6|        for (size_t a = 0; a < numBones; ++a) {
  ------------------
  |  Branch (811:28): [True: 5, False: 1]
  ------------------
  812|       |            // omit bones without weights
  813|      5|            if (dstBones[a].empty() && removeEmptyBones) {
  ------------------
  |  Branch (813:17): [True: 1, False: 4]
  |  Branch (813:40): [True: 1, False: 0]
  ------------------
  814|      1|                continue;
  815|      1|            }
  816|       |
  817|       |            // create bone with its weights
  818|      4|            auto bone = new aiBone;
  819|      4|            bone->mName = ReadString(jointNamesAcc, jointNames, a);
  820|      4|            bone->mOffsetMatrix.a1 = ReadFloat(jointMatrixAcc, jointMatrices, a, 0);
  821|      4|            bone->mOffsetMatrix.a2 = ReadFloat(jointMatrixAcc, jointMatrices, a, 1);
  822|      4|            bone->mOffsetMatrix.a3 = ReadFloat(jointMatrixAcc, jointMatrices, a, 2);
  823|      4|            bone->mOffsetMatrix.a4 = ReadFloat(jointMatrixAcc, jointMatrices, a, 3);
  824|      4|            bone->mOffsetMatrix.b1 = ReadFloat(jointMatrixAcc, jointMatrices, a, 4);
  825|      4|            bone->mOffsetMatrix.b2 = ReadFloat(jointMatrixAcc, jointMatrices, a, 5);
  826|      4|            bone->mOffsetMatrix.b3 = ReadFloat(jointMatrixAcc, jointMatrices, a, 6);
  827|      4|            bone->mOffsetMatrix.b4 = ReadFloat(jointMatrixAcc, jointMatrices, a, 7);
  828|      4|            bone->mOffsetMatrix.c1 = ReadFloat(jointMatrixAcc, jointMatrices, a, 8);
  829|      4|            bone->mOffsetMatrix.c2 = ReadFloat(jointMatrixAcc, jointMatrices, a, 9);
  830|      4|            bone->mOffsetMatrix.c3 = ReadFloat(jointMatrixAcc, jointMatrices, a, 10);
  831|      4|            bone->mOffsetMatrix.c4 = ReadFloat(jointMatrixAcc, jointMatrices, a, 11);
  832|      4|            bone->mNumWeights = static_cast<unsigned int>(dstBones[a].size());
  833|      4|            bone->mWeights = new aiVertexWeight[bone->mNumWeights];
  834|      4|            std::copy(dstBones[a].begin(), dstBones[a].end(), bone->mWeights);
  835|       |
  836|       |            // apply bind shape matrix to offset matrix
  837|      4|            aiMatrix4x4 bindShapeMatrix;
  838|      4|            bindShapeMatrix.a1 = pSrcController->mBindShapeMatrix[0];
  839|      4|            bindShapeMatrix.a2 = pSrcController->mBindShapeMatrix[1];
  840|      4|            bindShapeMatrix.a3 = pSrcController->mBindShapeMatrix[2];
  841|      4|            bindShapeMatrix.a4 = pSrcController->mBindShapeMatrix[3];
  842|      4|            bindShapeMatrix.b1 = pSrcController->mBindShapeMatrix[4];
  843|      4|            bindShapeMatrix.b2 = pSrcController->mBindShapeMatrix[5];
  844|      4|            bindShapeMatrix.b3 = pSrcController->mBindShapeMatrix[6];
  845|      4|            bindShapeMatrix.b4 = pSrcController->mBindShapeMatrix[7];
  846|      4|            bindShapeMatrix.c1 = pSrcController->mBindShapeMatrix[8];
  847|      4|            bindShapeMatrix.c2 = pSrcController->mBindShapeMatrix[9];
  848|      4|            bindShapeMatrix.c3 = pSrcController->mBindShapeMatrix[10];
  849|      4|            bindShapeMatrix.c4 = pSrcController->mBindShapeMatrix[11];
  850|      4|            bindShapeMatrix.d1 = pSrcController->mBindShapeMatrix[12];
  851|      4|            bindShapeMatrix.d2 = pSrcController->mBindShapeMatrix[13];
  852|      4|            bindShapeMatrix.d3 = pSrcController->mBindShapeMatrix[14];
  853|      4|            bindShapeMatrix.d4 = pSrcController->mBindShapeMatrix[15];
  854|      4|            bone->mOffsetMatrix *= bindShapeMatrix;
  855|       |
  856|       |            // HACK: (thom) Some exporters address the bone nodes by SID, others address them by ID or even name.
  857|       |            // Therefore I added a little name replacement here: I search for the bone's node by either name, ID or SID,
  858|       |            // and replace the bone's name by the node's name so that the user can use the standard
  859|       |            // find-by-name method to associate nodes with bones.
  860|      4|            const Collada::Node *bnode = FindNode(pParser.mRootNode, bone->mName.data);
  861|      4|            if (nullptr == bnode) {
  ------------------
  |  Branch (861:17): [True: 4, False: 0]
  ------------------
  862|      4|                bnode = FindNodeBySID(pParser.mRootNode, bone->mName.data);
  863|      4|            }
  864|       |
  865|       |            // assign the name that we would have assigned for the source node
  866|      4|            if (nullptr != bnode) {
  ------------------
  |  Branch (866:17): [True: 4, False: 0]
  ------------------
  867|      4|                bone->mName.Set(FindNameForNode(bnode));
  868|      4|            } else {
  869|      0|                ASSIMP_LOG_WARN("ColladaLoader::CreateMesh(): could not find corresponding node for joint \"", bone->mName.data, "\".");
  870|      0|            }
  871|       |
  872|       |            // and insert bone
  873|      4|            dstMesh->mBones[boneCount++] = bone;
  874|      4|        }
  875|      1|    }
  876|       |
  877|     90|    return dstMesh.release();
  878|     90|}
_ZN6Assimp13ColladaLoader16StoreSceneMeshesEP7aiScene:
  882|     16|void ColladaLoader::StoreSceneMeshes(aiScene *pScene) {
  883|     16|    pScene->mNumMeshes = static_cast<unsigned int>(mMeshes.size());
  884|     16|    if (mMeshes.empty()) {
  ------------------
  |  Branch (884:9): [True: 1, False: 15]
  ------------------
  885|      1|        return;
  886|      1|    }
  887|     15|    pScene->mMeshes = new aiMesh *[mMeshes.size()];
  888|     15|    std::copy(mMeshes.begin(), mMeshes.end(), pScene->mMeshes);
  889|     15|    mMeshes.clear();
  890|     15|}
_ZN6Assimp13ColladaLoader17StoreSceneCamerasEP7aiScene:
  894|     16|void ColladaLoader::StoreSceneCameras(aiScene *pScene) {
  895|     16|    pScene->mNumCameras = static_cast<unsigned int>(mCameras.size());
  896|     16|    if (mCameras.empty()) {
  ------------------
  |  Branch (896:9): [True: 9, False: 7]
  ------------------
  897|      9|        return;
  898|      9|    }
  899|      7|    pScene->mCameras = new aiCamera *[mCameras.size()];
  900|      7|    std::copy(mCameras.begin(), mCameras.end(), pScene->mCameras);
  901|      7|    mCameras.clear();
  902|      7|}
_ZN6Assimp13ColladaLoader16StoreSceneLightsEP7aiScene:
  906|     16|void ColladaLoader::StoreSceneLights(aiScene *pScene) {
  907|     16|    pScene->mNumLights = static_cast<unsigned int>(mLights.size());
  908|     16|    if (mLights.empty()) {
  ------------------
  |  Branch (908:9): [True: 8, False: 8]
  ------------------
  909|      8|        return;
  910|      8|    }
  911|      8|    pScene->mLights = new aiLight *[mLights.size()];
  912|      8|    std::copy(mLights.begin(), mLights.end(), pScene->mLights);
  913|      8|    mLights.clear();
  914|      8|}
_ZN6Assimp13ColladaLoader18StoreSceneTexturesEP7aiScene:
  918|     16|void ColladaLoader::StoreSceneTextures(aiScene *pScene) {
  919|     16|    pScene->mNumTextures = static_cast<unsigned int>(mTextures.size());
  920|     16|    if (mTextures.empty()) {
  ------------------
  |  Branch (920:9): [True: 14, False: 2]
  ------------------
  921|     14|        return;
  922|     14|    }
  923|      2|    pScene->mTextures = new aiTexture *[mTextures.size()];
  924|      2|    std::copy(mTextures.begin(), mTextures.end(), pScene->mTextures);
  925|      2|    mTextures.clear();
  926|      2|}
_ZN6Assimp13ColladaLoader19StoreSceneMaterialsEP7aiScene:
  930|     16|void ColladaLoader::StoreSceneMaterials(aiScene *pScene) {
  931|     16|    pScene->mNumMaterials = static_cast<unsigned int>(newMats.size());
  932|     16|    if (newMats.empty()) {
  ------------------
  |  Branch (932:9): [True: 2, False: 14]
  ------------------
  933|      2|        return;
  934|      2|    }
  935|     14|    pScene->mMaterials = new aiMaterial *[newMats.size()];
  936|     38|    for (unsigned int i = 0; i < newMats.size(); ++i) {
  ------------------
  |  Branch (936:30): [True: 24, False: 14]
  ------------------
  937|     24|        pScene->mMaterials[i] = newMats[i].second;
  938|     24|    }
  939|     14|    newMats.clear();
  940|     14|}
_ZN6Assimp13ColladaLoader15StoreAnimationsEP7aiSceneRKNS_13ColladaParserE:
  944|     16|void ColladaLoader::StoreAnimations(aiScene *pScene, const ColladaParser &pParser) {
  945|       |    // recursively collect all animations from the collada scene
  946|     16|    StoreAnimations(pScene, pParser, &pParser.mAnims, "");
  947|       |
  948|       |    // catch special case: many animations with the same length, each affecting only a single node.
  949|       |    // we need to unite all those single-node-anims to a proper combined animation
  950|     19|    for (size_t a = 0; a < mAnims.size(); ++a) {
  ------------------
  |  Branch (950:24): [True: 3, False: 16]
  ------------------
  951|      3|        aiAnimation *templateAnim = mAnims[a];
  952|       |
  953|      3|        if (templateAnim->mNumChannels == 1) {
  ------------------
  |  Branch (953:13): [True: 2, False: 1]
  ------------------
  954|       |            // search for other single-channel-anims with the same duration
  955|      2|            std::vector<size_t> collectedAnimIndices;
  956|     18|            for (size_t b = a + 1; b < mAnims.size(); ++b) {
  ------------------
  |  Branch (956:36): [True: 16, False: 2]
  ------------------
  957|     16|                aiAnimation *other = mAnims[b];
  958|     16|                if (other->mNumChannels == 1 && other->mDuration == templateAnim->mDuration &&
  ------------------
  |  Branch (958:21): [True: 16, False: 0]
  |  Branch (958:49): [True: 10, False: 6]
  ------------------
  959|     10|                        other->mTicksPerSecond == templateAnim->mTicksPerSecond)
  ------------------
  |  Branch (959:25): [True: 10, False: 0]
  ------------------
  960|     10|                    collectedAnimIndices.push_back(b);
  961|     16|            }
  962|       |
  963|       |            // We only want to combine the animations if they have different channels
  964|      2|            std::set<std::string> animTargets;
  965|      2|            animTargets.insert(templateAnim->mChannels[0]->mNodeName.C_Str());
  966|      2|            bool collectedAnimationsHaveDifferentChannels = true;
  967|     10|            for (unsigned long long collectedAnimIndice : collectedAnimIndices) {
  ------------------
  |  Branch (967:57): [True: 10, False: 2]
  ------------------
  968|     10|                aiAnimation *srcAnimation = mAnims[(int)collectedAnimIndice];
  969|     10|                std::string channelName = std::string(srcAnimation->mChannels[0]->mNodeName.C_Str());
  970|     10|                if (animTargets.find(channelName) == animTargets.end()) {
  ------------------
  |  Branch (970:21): [True: 10, False: 0]
  ------------------
  971|     10|                    animTargets.insert(channelName);
  972|     10|                } else {
  973|      0|                    collectedAnimationsHaveDifferentChannels = false;
  974|      0|                    break;
  975|      0|                }
  976|     10|            }
  977|       |
  978|      2|            if (!collectedAnimationsHaveDifferentChannels) {
  ------------------
  |  Branch (978:17): [True: 0, False: 2]
  ------------------
  979|      0|                continue;
  980|      0|            }
  981|       |
  982|       |            // if there are other animations which fit the template anim, combine all channels into a single anim
  983|      2|            if (!collectedAnimIndices.empty()) {
  ------------------
  |  Branch (983:17): [True: 2, False: 0]
  ------------------
  984|      2|                auto *combinedAnim = new aiAnimation();
  985|      2|                combinedAnim->mName = aiString(std::string("combinedAnim_") + char('0' + a));
  986|      2|                combinedAnim->mDuration = templateAnim->mDuration;
  987|      2|                combinedAnim->mTicksPerSecond = templateAnim->mTicksPerSecond;
  988|      2|                combinedAnim->mNumChannels = static_cast<unsigned int>(collectedAnimIndices.size() + 1);
  989|      2|                combinedAnim->mChannels = new aiNodeAnim *[combinedAnim->mNumChannels];
  990|       |                // add the template anim as first channel by moving its aiNodeAnim to the combined animation
  991|      2|                combinedAnim->mChannels[0] = templateAnim->mChannels[0];
  992|      2|                templateAnim->mChannels[0] = nullptr;
  993|      2|                delete templateAnim;
  994|       |                // combined animation replaces template animation in the anim array
  995|      2|                mAnims[a] = combinedAnim;
  996|       |
  997|       |                // move the memory of all other anims to the combined anim and erase them from the source anims
  998|     12|                for (size_t b = 0; b < collectedAnimIndices.size(); ++b) {
  ------------------
  |  Branch (998:36): [True: 10, False: 2]
  ------------------
  999|     10|                    aiAnimation *srcAnimation = mAnims[collectedAnimIndices[b]];
 1000|     10|                    combinedAnim->mChannels[1 + b] = srcAnimation->mChannels[0];
 1001|     10|                    srcAnimation->mChannels[0] = nullptr;
 1002|     10|                    delete srcAnimation;
 1003|     10|                }
 1004|       |
 1005|       |                // in a second go, delete all the single-channel-anims that we've stripped from their channels
 1006|       |                // back to front to preserve indices - you know, removing an element from a vector moves all elements behind the removed one
 1007|     12|                while (!collectedAnimIndices.empty()) {
  ------------------
  |  Branch (1007:24): [True: 10, False: 2]
  ------------------
 1008|     10|                    mAnims.erase(mAnims.begin() + collectedAnimIndices.back());
 1009|     10|                    collectedAnimIndices.pop_back();
 1010|     10|                }
 1011|      2|            }
 1012|      2|        }
 1013|      3|    }
 1014|       |
 1015|       |    // now store all anims in the scene
 1016|     16|    if (!mAnims.empty()) {
  ------------------
  |  Branch (1016:9): [True: 2, False: 14]
  ------------------
 1017|      2|        pScene->mNumAnimations = static_cast<unsigned int>(mAnims.size());
 1018|      2|        pScene->mAnimations = new aiAnimation *[mAnims.size()];
 1019|      2|        std::copy(mAnims.begin(), mAnims.end(), pScene->mAnimations);
 1020|      2|    }
 1021|       |
 1022|     16|    mAnims.clear();
 1023|     16|}
_ZN6Assimp13ColladaLoader15StoreAnimationsEP7aiSceneRKNS_13ColladaParserEPKNS_7Collada9AnimationERKNSt3__112basic_stringIcNSA_11char_traitsIcEENSA_9allocatorIcEEEE:
 1027|     28|void ColladaLoader::StoreAnimations(aiScene *pScene, const ColladaParser &pParser, const Animation *pSrcAnim, const std::string &pPrefix) {
 1028|     28|    std::string animName = pPrefix.empty() ? pSrcAnim->mName : pPrefix + "_" + pSrcAnim->mName;
  ------------------
  |  Branch (1028:28): [True: 16, False: 12]
  ------------------
 1029|       |
 1030|       |    // create nested animations, if given
 1031|     28|    for (auto mSubAnim : pSrcAnim->mSubAnims) {
  ------------------
  |  Branch (1031:24): [True: 12, False: 28]
  ------------------
 1032|     12|        StoreAnimations(pScene, pParser, mSubAnim, animName);
 1033|     12|    }
 1034|       |
 1035|       |    // create animation channels, if any
 1036|     28|    if (!pSrcAnim->mChannels.empty()) {
  ------------------
  |  Branch (1036:9): [True: 13, False: 15]
  ------------------
 1037|     13|        CreateAnimation(pScene, pParser, pSrcAnim, animName);
 1038|     13|    }
 1039|     28|}
_ZN6Assimp13ColladaLoader15CreateAnimationEP7aiSceneRKNS_13ColladaParserEPKNS_7Collada9AnimationERKNSt3__112basic_stringIcNSA_11char_traitsIcEENSA_9allocatorIcEEEE:
 1096|     13|void ColladaLoader::CreateAnimation(aiScene *pScene, const ColladaParser &pParser, const Animation *pSrcAnim, const std::string &pName) {
 1097|       |    // collect a list of animatable nodes
 1098|     13|    std::vector<const aiNode *> nodes;
 1099|     13|    CollectNodes(pScene->mRootNode, nodes);
 1100|       |
 1101|     13|    std::vector<aiNodeAnim *> anims;
 1102|     13|    std::vector<aiMeshMorphAnim *> morphAnims;
 1103|       |
 1104|    225|    for (auto node : nodes) {
  ------------------
  |  Branch (1104:20): [True: 225, False: 13]
  ------------------
 1105|       |        // find all the collada anim channels which refer to the current node
 1106|    225|        std::vector<ChannelEntry> entries;
 1107|    225|        std::string nodeName = node->mName.data;
 1108|       |
 1109|       |        // find the collada node corresponding to the aiNode
 1110|    225|        const Node *srcNode = FindNode(pParser.mRootNode, nodeName);
 1111|    225|        if (!srcNode) {
  ------------------
  |  Branch (1111:13): [True: 0, False: 225]
  ------------------
 1112|      0|            continue;
 1113|      0|        }
 1114|       |
 1115|       |        // now check all channels if they affect the current node
 1116|    225|        std::string targetID, subElement;
 1117|    225|        for (auto cit = pSrcAnim->mChannels.begin();
 1118|  25.0k|                cit != pSrcAnim->mChannels.end(); ++cit) {
  ------------------
  |  Branch (1118:17): [True: 24.8k, False: 225]
  ------------------
 1119|  24.8k|            const AnimationChannel &srcChannel = *cit;
 1120|  24.8k|            ChannelEntry entry;
 1121|       |
 1122|       |            // we expect the animation target to be of type "nodeName/transformID.subElement". Ignore all others
 1123|       |            // find the slash that separates the node name - there should be only one
 1124|  24.8k|            std::string::size_type slashPos = srcChannel.mTarget.find('/');
 1125|  24.8k|            if (slashPos == std::string::npos) {
  ------------------
  |  Branch (1125:17): [True: 0, False: 24.8k]
  ------------------
 1126|      0|                std::string::size_type targetPos = srcChannel.mTarget.find(srcNode->mID);
 1127|      0|                if (targetPos == std::string::npos) {
  ------------------
  |  Branch (1127:21): [True: 0, False: 0]
  ------------------
 1128|      0|                    continue;
 1129|      0|                }
 1130|       |
 1131|       |                // not node transform, but something else. store as unknown animation channel for now
 1132|      0|                entry.mChannel = &(*cit);
 1133|      0|                entry.mTargetId = srcChannel.mTarget.substr(targetPos + pSrcAnim->mName.length(),
 1134|      0|                        srcChannel.mTarget.length() - targetPos - pSrcAnim->mName.length());
 1135|      0|                if (entry.mTargetId.front() == '-') {
  ------------------
  |  Branch (1135:21): [True: 0, False: 0]
  ------------------
 1136|      0|                    entry.mTargetId = entry.mTargetId.substr(1);
 1137|      0|                }
 1138|      0|                entries.push_back(entry);
 1139|      0|                continue;
 1140|      0|            }
 1141|  24.8k|            if (srcChannel.mTarget.find('/', slashPos + 1) != std::string::npos) {
  ------------------
  |  Branch (1141:17): [True: 0, False: 24.8k]
  ------------------
 1142|      0|                continue;
 1143|      0|            }
 1144|       |
 1145|  24.8k|            targetID.clear();
 1146|  24.8k|            targetID = srcChannel.mTarget.substr(0, slashPos);
 1147|  24.8k|            if (targetID != srcNode->mID) {
  ------------------
  |  Branch (1147:17): [True: 24.6k, False: 204]
  ------------------
 1148|  24.6k|                continue;
 1149|  24.6k|            }
 1150|       |
 1151|       |            // find the dot that separates the transformID - there should be only one or zero
 1152|    204|            std::string::size_type dotPos = srcChannel.mTarget.find('.');
 1153|    204|            if (dotPos != std::string::npos) {
  ------------------
  |  Branch (1153:17): [True: 192, False: 12]
  ------------------
 1154|    192|                if (srcChannel.mTarget.find('.', dotPos + 1) != std::string::npos) {
  ------------------
  |  Branch (1154:21): [True: 0, False: 192]
  ------------------
 1155|      0|                    continue;
 1156|      0|                }
 1157|       |
 1158|    192|                entry.mTransformId = srcChannel.mTarget.substr(slashPos + 1, dotPos - slashPos - 1);
 1159|       |
 1160|    192|                subElement.clear();
 1161|    192|                subElement = srcChannel.mTarget.substr(dotPos + 1);
 1162|    192|                if (subElement == "ANGLE")
  ------------------
  |  Branch (1162:21): [True: 192, False: 0]
  ------------------
 1163|    192|                    entry.mSubElement = 3; // last number in an Axis-Angle-Transform is the angle
 1164|      0|                else if (subElement == "X")
  ------------------
  |  Branch (1164:26): [True: 0, False: 0]
  ------------------
 1165|      0|                    entry.mSubElement = 0;
 1166|      0|                else if (subElement == "Y")
  ------------------
  |  Branch (1166:26): [True: 0, False: 0]
  ------------------
 1167|      0|                    entry.mSubElement = 1;
 1168|      0|                else if (subElement == "Z")
  ------------------
  |  Branch (1168:26): [True: 0, False: 0]
  ------------------
 1169|      0|                    entry.mSubElement = 2;
 1170|      0|                else
 1171|      0|                    ASSIMP_LOG_WARN("Unknown anim subelement <", subElement, ">. Ignoring");
 1172|    192|            } else {
 1173|       |                // no sub-element following, transformId is remaining string
 1174|     12|                entry.mTransformId = srcChannel.mTarget.substr(slashPos + 1);
 1175|     12|            }
 1176|       |
 1177|    204|            std::string::size_type bracketPos = srcChannel.mTarget.find('(');
 1178|    204|            if (bracketPos != std::string::npos) {
  ------------------
  |  Branch (1178:17): [True: 0, False: 204]
  ------------------
 1179|      0|                entry.mTransformId = srcChannel.mTarget.substr(slashPos + 1, bracketPos - slashPos - 1);
 1180|      0|                subElement.clear();
 1181|      0|                subElement = srcChannel.mTarget.substr(bracketPos);
 1182|       |
 1183|      0|                if (subElement == "(0)(0)")
  ------------------
  |  Branch (1183:21): [True: 0, False: 0]
  ------------------
 1184|      0|                    entry.mSubElement = 0;
 1185|      0|                else if (subElement == "(1)(0)")
  ------------------
  |  Branch (1185:26): [True: 0, False: 0]
  ------------------
 1186|      0|                    entry.mSubElement = 1;
 1187|      0|                else if (subElement == "(2)(0)")
  ------------------
  |  Branch (1187:26): [True: 0, False: 0]
  ------------------
 1188|      0|                    entry.mSubElement = 2;
 1189|      0|                else if (subElement == "(3)(0)")
  ------------------
  |  Branch (1189:26): [True: 0, False: 0]
  ------------------
 1190|      0|                    entry.mSubElement = 3;
 1191|      0|                else if (subElement == "(0)(1)")
  ------------------
  |  Branch (1191:26): [True: 0, False: 0]
  ------------------
 1192|      0|                    entry.mSubElement = 4;
 1193|      0|                else if (subElement == "(1)(1)")
  ------------------
  |  Branch (1193:26): [True: 0, False: 0]
  ------------------
 1194|      0|                    entry.mSubElement = 5;
 1195|      0|                else if (subElement == "(2)(1)")
  ------------------
  |  Branch (1195:26): [True: 0, False: 0]
  ------------------
 1196|      0|                    entry.mSubElement = 6;
 1197|      0|                else if (subElement == "(3)(1)")
  ------------------
  |  Branch (1197:26): [True: 0, False: 0]
  ------------------
 1198|      0|                    entry.mSubElement = 7;
 1199|      0|                else if (subElement == "(0)(2)")
  ------------------
  |  Branch (1199:26): [True: 0, False: 0]
  ------------------
 1200|      0|                    entry.mSubElement = 8;
 1201|      0|                else if (subElement == "(1)(2)")
  ------------------
  |  Branch (1201:26): [True: 0, False: 0]
  ------------------
 1202|      0|                    entry.mSubElement = 9;
 1203|      0|                else if (subElement == "(2)(2)")
  ------------------
  |  Branch (1203:26): [True: 0, False: 0]
  ------------------
 1204|      0|                    entry.mSubElement = 10;
 1205|      0|                else if (subElement == "(3)(2)")
  ------------------
  |  Branch (1205:26): [True: 0, False: 0]
  ------------------
 1206|      0|                    entry.mSubElement = 11;
 1207|      0|                else if (subElement == "(0)(3)")
  ------------------
  |  Branch (1207:26): [True: 0, False: 0]
  ------------------
 1208|      0|                    entry.mSubElement = 12;
 1209|      0|                else if (subElement == "(1)(3)")
  ------------------
  |  Branch (1209:26): [True: 0, False: 0]
  ------------------
 1210|      0|                    entry.mSubElement = 13;
 1211|      0|                else if (subElement == "(2)(3)")
  ------------------
  |  Branch (1211:26): [True: 0, False: 0]
  ------------------
 1212|      0|                    entry.mSubElement = 14;
 1213|      0|                else if (subElement == "(3)(3)")
  ------------------
  |  Branch (1213:26): [True: 0, False: 0]
  ------------------
 1214|      0|                    entry.mSubElement = 15;
 1215|      0|            }
 1216|       |
 1217|       |            // determine which transform step is affected by this channel
 1218|    204|            entry.mTransformIndex = SIZE_MAX;
 1219|    792|            for (size_t a = 0; a < srcNode->mTransforms.size(); ++a)
  ------------------
  |  Branch (1219:32): [True: 588, False: 204]
  ------------------
 1220|    588|                if (srcNode->mTransforms[a].mID == entry.mTransformId)
  ------------------
  |  Branch (1220:21): [True: 204, False: 384]
  ------------------
 1221|    204|                    entry.mTransformIndex = a;
 1222|       |
 1223|    204|            if (entry.mTransformIndex == SIZE_MAX) {
  ------------------
  |  Branch (1223:17): [True: 0, False: 204]
  ------------------
 1224|      0|                if (entry.mTransformId.find("morph-weights") == std::string::npos) {
  ------------------
  |  Branch (1224:21): [True: 0, False: 0]
  ------------------
 1225|      0|                    continue;
 1226|      0|                }
 1227|      0|                entry.mTargetId = entry.mTransformId;
 1228|      0|                entry.mTransformId = std::string();
 1229|      0|            }
 1230|       |
 1231|    204|            entry.mChannel = &(*cit);
 1232|    204|            entries.push_back(entry);
 1233|    204|        }
 1234|       |
 1235|       |        // if there's no channel affecting the current node, we skip it
 1236|    225|        if (entries.empty()) {
  ------------------
  |  Branch (1236:13): [True: 149, False: 76]
  ------------------
 1237|    149|            continue;
 1238|    149|        }
 1239|       |
 1240|       |        // resolve the data pointers for all anim channels. Find the minimum time while we're at it
 1241|     76|        ai_real startTime = ai_real(1e20), endTime = ai_real(-1e20);
 1242|    204|        for (ChannelEntry & e : entries) {
  ------------------
  |  Branch (1242:31): [True: 204, False: 76]
  ------------------
 1243|    204|            e.mTimeAccessor = &pParser.ResolveLibraryReference(pParser.mAccessorLibrary, e.mChannel->mSourceTimes);
 1244|    204|            e.mTimeData = &pParser.ResolveLibraryReference(pParser.mDataLibrary, e.mTimeAccessor->mSource);
 1245|    204|            e.mValueAccessor = &pParser.ResolveLibraryReference(pParser.mAccessorLibrary, e.mChannel->mSourceValues);
 1246|    204|            e.mValueData = &pParser.ResolveLibraryReference(pParser.mDataLibrary, e.mValueAccessor->mSource);
 1247|       |
 1248|       |            // time count and value count must match
 1249|    204|            if (e.mTimeAccessor->mCount != e.mValueAccessor->mCount) {
  ------------------
  |  Branch (1249:17): [True: 0, False: 204]
  ------------------
 1250|      0|                throw DeadlyImportError("Time count / value count mismatch in animation channel \"", e.mChannel->mTarget, "\".");
 1251|      0|            }
 1252|       |
 1253|    204|            if (e.mTimeAccessor->mCount > 0) {
  ------------------
  |  Branch (1253:17): [True: 204, False: 0]
  ------------------
 1254|       |                // find bounding times
 1255|    204|                startTime = std::min(startTime, ReadFloat(*e.mTimeAccessor, *e.mTimeData, 0, 0));
 1256|    204|                endTime = std::max(endTime, ReadFloat(*e.mTimeAccessor, *e.mTimeData, e.mTimeAccessor->mCount - 1, 0));
 1257|    204|            }
 1258|    204|        }
 1259|       |
 1260|     76|        std::vector<aiMatrix4x4> resultTrafos;
 1261|     76|        if (!entries.empty() && entries.front().mTimeAccessor->mCount > 0) {
  ------------------
  |  Branch (1261:13): [True: 76, False: 0]
  |  Branch (1261:33): [True: 76, False: 0]
  ------------------
 1262|       |            // create a local transformation chain of the node's transforms
 1263|     76|            std::vector<Collada::Transform> transforms = srcNode->mTransforms;
 1264|       |
 1265|       |            // now for every unique point in time, find or interpolate the key values for that time
 1266|       |            // and apply them to the transform chain. Then the node's present transformation can be calculated.
 1267|     76|            ai_real time = startTime;
 1268|    536|            while (true) {
  ------------------
  |  Branch (1268:20): [True: 536, Folded]
  ------------------
 1269|  1.17k|                for (ChannelEntry & e : entries) {
  ------------------
  |  Branch (1269:39): [True: 1.17k, False: 536]
  ------------------
 1270|       |                    // find the keyframe behind the current point in time
 1271|  1.17k|                    size_t pos = 0;
 1272|  1.17k|                    ai_real postTime = 0.0;
 1273|  3.83k|                    while (true) {
  ------------------
  |  Branch (1273:28): [True: 3.83k, Folded]
  ------------------
 1274|  3.83k|                        if (pos >= e.mTimeAccessor->mCount) {
  ------------------
  |  Branch (1274:29): [True: 0, False: 3.83k]
  ------------------
 1275|      0|                            break;
 1276|      0|                        }
 1277|  3.83k|                        postTime = ReadFloat(*e.mTimeAccessor, *e.mTimeData, pos, 0);
 1278|  3.83k|                        if (postTime >= time) {
  ------------------
  |  Branch (1278:29): [True: 1.17k, False: 2.65k]
  ------------------
 1279|  1.17k|                            break;
 1280|  1.17k|                        }
 1281|  2.65k|                        ++pos;
 1282|  2.65k|                    }
 1283|       |
 1284|  1.17k|                    pos = std::min(pos, e.mTimeAccessor->mCount - 1);
 1285|       |
 1286|       |                    // read values from there
 1287|  1.17k|                    ai_real temp[16];
 1288|  5.59k|                    for (size_t c = 0; c < e.mValueAccessor->mSize; ++c) {
  ------------------
  |  Branch (1288:40): [True: 4.41k, False: 1.17k]
  ------------------
 1289|  4.41k|                        temp[c] = ReadFloat(*e.mValueAccessor, *e.mValueData, pos, c);
 1290|  4.41k|                    }
 1291|       |
 1292|       |                    // if not exactly at the key time, interpolate with previous value set
 1293|  1.17k|                    if (postTime > time && pos > 0) {
  ------------------
  |  Branch (1293:25): [True: 576, False: 600]
  |  Branch (1293:44): [True: 576, False: 0]
  ------------------
 1294|    576|                        ai_real preTime = ReadFloat(*e.mTimeAccessor, *e.mTimeData, pos - 1, 0);
 1295|    576|                        ai_real factor = (time - postTime) / (preTime - postTime);
 1296|       |
 1297|  1.15k|                        for (size_t c = 0; c < e.mValueAccessor->mSize; ++c) {
  ------------------
  |  Branch (1297:44): [True: 576, False: 576]
  ------------------
 1298|    576|                            ai_real v = ReadFloat(*e.mValueAccessor, *e.mValueData, pos - 1, c);
 1299|    576|                            temp[c] += (v - temp[c]) * factor;
 1300|    576|                        }
 1301|    576|                    }
 1302|       |
 1303|       |                    // Apply values to current transformation
 1304|  1.17k|                    std::copy(temp, temp + e.mValueAccessor->mSize, transforms[e.mTransformIndex].f + e.mSubElement);
 1305|  1.17k|                }
 1306|       |
 1307|       |                // Calculate resulting transformation
 1308|    536|                aiMatrix4x4 mat = pParser.CalculateResultTransform(transforms);
 1309|       |
 1310|       |                // out of laziness: we store the time in matrix.d4
 1311|    536|                mat.d4 = time;
 1312|    536|                resultTrafos.push_back(mat);
 1313|       |
 1314|       |                // find next point in time to evaluate. That's the closest frame larger than the current in any channel
 1315|    536|                ai_real nextTime = ai_real(1e20);
 1316|  1.17k|                for (ChannelEntry & channelElement : entries) {
  ------------------
  |  Branch (1316:52): [True: 1.17k, False: 536]
  ------------------
 1317|       |                    // find the next time value larger than the current
 1318|  1.17k|                    size_t pos = 0;
 1319|  4.43k|                    while (pos < channelElement.mTimeAccessor->mCount) {
  ------------------
  |  Branch (1319:28): [True: 4.23k, False: 204]
  ------------------
 1320|  4.23k|                        const ai_real t = ReadFloat(*channelElement.mTimeAccessor, *channelElement.mTimeData, pos, 0);
 1321|  4.23k|                        if (t > time) {
  ------------------
  |  Branch (1321:29): [True: 972, False: 3.25k]
  ------------------
 1322|    972|                            nextTime = std::min(nextTime, t);
 1323|    972|                            break;
 1324|    972|                        }
 1325|  3.25k|                        ++pos;
 1326|  3.25k|                    }
 1327|       |
 1328|       |                    // https://github.com/assimp/assimp/issues/458
 1329|       |                    // Sub-sample axis-angle channels if the delta between two consecutive
 1330|       |                    // key-frame angles is >= 180 degrees.
 1331|  1.17k|                    if (transforms[channelElement.mTransformIndex].mType == TF_ROTATE && channelElement.mSubElement == 3 && pos > 0 && pos < channelElement.mTimeAccessor->mCount) {
  ------------------
  |  Branch (1331:25): [True: 960, False: 216]
  |  Branch (1331:90): [True: 960, False: 0]
  |  Branch (1331:125): [True: 960, False: 0]
  |  Branch (1331:136): [True: 768, False: 192]
  ------------------
 1332|    768|                        const ai_real cur_key_angle = ReadFloat(*channelElement.mValueAccessor, *channelElement.mValueData, pos, 0);
 1333|    768|                        const ai_real last_key_angle = ReadFloat(*channelElement.mValueAccessor, *channelElement.mValueData, pos - 1, 0);
 1334|    768|                        const ai_real cur_key_time = ReadFloat(*channelElement.mTimeAccessor, *channelElement.mTimeData, pos, 0);
 1335|    768|                        const ai_real last_key_time = ReadFloat(*channelElement.mTimeAccessor, *channelElement.mTimeData, pos - 1, 0);
 1336|    768|                        const ai_real last_eval_angle = last_key_angle + (cur_key_angle - last_key_angle) * (time - last_key_time) / (cur_key_time - last_key_time);
 1337|    768|                        const ai_real delta = std::abs(cur_key_angle - last_eval_angle);
 1338|    768|                        if (delta >= 180.0) {
  ------------------
  |  Branch (1338:29): [True: 192, False: 576]
  ------------------
 1339|    192|                            const int subSampleCount = static_cast<int>(std::floor(delta / 90.0));
 1340|    192|                            if (cur_key_time != time) {
  ------------------
  |  Branch (1340:33): [True: 192, False: 0]
  ------------------
 1341|    192|                                const ai_real nextSampleTime = time + (cur_key_time - time) / subSampleCount;
 1342|    192|                                nextTime = std::min(nextTime, nextSampleTime);
 1343|    192|                            }
 1344|    192|                        }
 1345|    768|                    }
 1346|  1.17k|                }
 1347|       |
 1348|       |                // no more keys on any channel after the current time -> we're done
 1349|    536|                if (nextTime > 1e19) {
  ------------------
  |  Branch (1349:21): [True: 76, False: 460]
  ------------------
 1350|     76|                    break;
 1351|     76|                }
 1352|       |
 1353|       |                // else construct next key-frame at this following time point
 1354|    460|                time = nextTime;
 1355|    460|            }
 1356|     76|        }
 1357|       |
 1358|       |        // build an animation channel for the given node out of these trafo keys
 1359|     76|        if (!resultTrafos.empty()) {
  ------------------
  |  Branch (1359:13): [True: 76, False: 0]
  ------------------
 1360|     76|            auto *dstAnim = new aiNodeAnim;
 1361|     76|            dstAnim->mNodeName = nodeName;
 1362|     76|            dstAnim->mNumPositionKeys = static_cast<unsigned int>(resultTrafos.size());
 1363|     76|            dstAnim->mNumRotationKeys = static_cast<unsigned int>(resultTrafos.size());
 1364|     76|            dstAnim->mNumScalingKeys = static_cast<unsigned int>(resultTrafos.size());
 1365|     76|            dstAnim->mPositionKeys = new aiVectorKey[resultTrafos.size()];
 1366|     76|            dstAnim->mRotationKeys = new aiQuatKey[resultTrafos.size()];
 1367|     76|            dstAnim->mScalingKeys = new aiVectorKey[resultTrafos.size()];
 1368|       |
 1369|    612|            for (size_t a = 0; a < resultTrafos.size(); ++a) {
  ------------------
  |  Branch (1369:32): [True: 536, False: 76]
  ------------------
 1370|    536|                aiMatrix4x4 mat = resultTrafos[a];
 1371|    536|                double time = double(mat.d4); // remember? time is stored in mat.d4
 1372|    536|                mat.d4 = 1.0f;
 1373|       |
 1374|    536|                dstAnim->mPositionKeys[a].mTime = time * kMillisecondsFromSeconds;
 1375|    536|                dstAnim->mRotationKeys[a].mTime = time * kMillisecondsFromSeconds;
 1376|    536|                dstAnim->mScalingKeys[a].mTime = time * kMillisecondsFromSeconds;
 1377|    536|                mat.Decompose(dstAnim->mScalingKeys[a].mValue, dstAnim->mRotationKeys[a].mValue, dstAnim->mPositionKeys[a].mValue);
 1378|    536|            }
 1379|       |
 1380|     76|            anims.push_back(dstAnim);
 1381|     76|        } else {
 1382|      0|            ASSIMP_LOG_WARN("Collada loader: found empty animation channel, ignored. Please check your exporter.");
 1383|      0|        }
 1384|       |
 1385|     76|        if (!entries.empty() && entries.front().mTimeAccessor->mCount > 0) {
  ------------------
  |  Branch (1385:13): [True: 76, False: 0]
  |  Branch (1385:33): [True: 76, False: 0]
  ------------------
 1386|     76|            std::vector<ChannelEntry> morphChannels;
 1387|    204|            for (ChannelEntry & e : entries) {
  ------------------
  |  Branch (1387:35): [True: 204, False: 76]
  ------------------
 1388|       |                // skip non-transform types
 1389|    204|                if (e.mTargetId.empty()) {
  ------------------
  |  Branch (1389:21): [True: 204, False: 0]
  ------------------
 1390|    204|                    continue;
 1391|    204|                }
 1392|       |
 1393|      0|                if (e.mTargetId.find("morph-weights") != std::string::npos) {
  ------------------
  |  Branch (1393:21): [True: 0, False: 0]
  ------------------
 1394|      0|                    morphChannels.push_back(e);
 1395|      0|                }
 1396|      0|            }
 1397|     76|            if (!morphChannels.empty()) {
  ------------------
  |  Branch (1397:17): [True: 0, False: 76]
  ------------------
 1398|       |                // either 1) morph weight animation count should contain morph target count channels
 1399|       |                // or     2) one channel with morph target count arrays
 1400|       |                // assume first
 1401|       |
 1402|      0|                auto *morphAnim = new aiMeshMorphAnim;
 1403|      0|                morphAnim->mName.Set(nodeName);
 1404|       |
 1405|      0|                std::vector<MorphTimeValues> morphTimeValues;
 1406|      0|                int morphAnimChannelIndex = 0;
 1407|      0|                for (ChannelEntry & e : morphChannels) {
  ------------------
  |  Branch (1407:39): [True: 0, False: 0]
  ------------------
 1408|      0|                    std::string::size_type apos = e.mTargetId.find('(');
 1409|      0|                    std::string::size_type bpos = e.mTargetId.find(')');
 1410|       |
 1411|       |                    // If unknown way to specify weight -> ignore this animation
 1412|      0|                    if (apos == std::string::npos || bpos == std::string::npos) {
  ------------------
  |  Branch (1412:25): [True: 0, False: 0]
  |  Branch (1412:54): [True: 0, False: 0]
  ------------------
 1413|      0|                        continue;
 1414|      0|                    }
 1415|       |
 1416|       |                    // weight target can be in format Weight_M_N, Weight_N, WeightN, or some other way
 1417|       |                    // we ignore the name and just assume the channels are in the right order
 1418|      0|                    for (unsigned int i = 0; i < e.mTimeData->mValues.size(); i++) {
  ------------------
  |  Branch (1418:46): [True: 0, False: 0]
  ------------------
 1419|      0|                        insertMorphTimeValue(morphTimeValues, e.mTimeData->mValues[i], e.mValueData->mValues[i], morphAnimChannelIndex);
 1420|      0|                    }
 1421|       |
 1422|      0|                    ++morphAnimChannelIndex;
 1423|      0|                }
 1424|       |
 1425|      0|                morphAnim->mNumKeys = static_cast<unsigned int>(morphTimeValues.size());
 1426|      0|                morphAnim->mKeys = new aiMeshMorphKey[morphAnim->mNumKeys];
 1427|      0|                for (unsigned int key = 0; key < morphAnim->mNumKeys; key++) {
  ------------------
  |  Branch (1427:44): [True: 0, False: 0]
  ------------------
 1428|      0|                    morphAnim->mKeys[key].mNumValuesAndWeights = static_cast<unsigned int>(morphChannels.size());
 1429|      0|                    morphAnim->mKeys[key].mValues = new unsigned int[morphChannels.size()];
 1430|      0|                    morphAnim->mKeys[key].mWeights = new double[morphChannels.size()];
 1431|       |
 1432|      0|                    morphAnim->mKeys[key].mTime = morphTimeValues[key].mTime * kMillisecondsFromSeconds;
 1433|      0|                    for (unsigned int valueIndex = 0; valueIndex < morphChannels.size(); ++valueIndex) {
  ------------------
  |  Branch (1433:55): [True: 0, False: 0]
  ------------------
 1434|      0|                        morphAnim->mKeys[key].mValues[valueIndex] = valueIndex;
 1435|      0|                        morphAnim->mKeys[key].mWeights[valueIndex] = getWeightAtKey(morphTimeValues, key, valueIndex);
 1436|      0|                    }
 1437|      0|                }
 1438|       |
 1439|      0|                morphAnims.push_back(morphAnim);
 1440|      0|            }
 1441|     76|        }
 1442|     76|    }
 1443|       |
 1444|     13|    if (!anims.empty() || !morphAnims.empty()) {
  ------------------
  |  Branch (1444:9): [True: 13, False: 0]
  |  Branch (1444:27): [True: 0, False: 0]
  ------------------
 1445|     13|        auto anim = new aiAnimation;
 1446|     13|        anim->mName.Set(pName);
 1447|     13|        anim->mNumChannels = static_cast<unsigned int>(anims.size());
 1448|     13|        if (anim->mNumChannels > 0) {
  ------------------
  |  Branch (1448:13): [True: 13, False: 0]
  ------------------
 1449|     13|            anim->mChannels = new aiNodeAnim *[anims.size()];
 1450|     13|            std::copy(anims.begin(), anims.end(), anim->mChannels);
 1451|     13|        }
 1452|     13|        anim->mNumMorphMeshChannels = static_cast<unsigned int>(morphAnims.size());
 1453|     13|        if (anim->mNumMorphMeshChannels > 0) {
  ------------------
  |  Branch (1453:13): [True: 0, False: 13]
  ------------------
 1454|      0|            anim->mMorphMeshChannels = new aiMeshMorphAnim *[anim->mNumMorphMeshChannels];
 1455|      0|            std::copy(morphAnims.begin(), morphAnims.end(), anim->mMorphMeshChannels);
 1456|      0|        }
 1457|     13|        anim->mDuration = 0.0f;
 1458|     76|        for (auto & a : anims) {
  ------------------
  |  Branch (1458:23): [True: 76, False: 13]
  ------------------
 1459|     76|            anim->mDuration = std::max(anim->mDuration, a->mPositionKeys[a->mNumPositionKeys - 1].mTime);
 1460|     76|            anim->mDuration = std::max(anim->mDuration, a->mRotationKeys[a->mNumRotationKeys - 1].mTime);
 1461|     76|            anim->mDuration = std::max(anim->mDuration, a->mScalingKeys[a->mNumScalingKeys - 1].mTime);
 1462|     76|        }
 1463|     13|        for (auto & morphAnim : morphAnims) {
  ------------------
  |  Branch (1463:31): [True: 0, False: 13]
  ------------------
 1464|      0|            anim->mDuration = std::max(anim->mDuration, morphAnim->mKeys[morphAnim->mNumKeys - 1].mTime);
 1465|      0|        }
 1466|     13|        anim->mTicksPerSecond = 1000.0;
 1467|     13|        mAnims.push_back(anim);
 1468|     13|    }
 1469|     13|}
_ZN6Assimp13ColladaLoader10AddTextureER10aiMaterialRKNS_13ColladaParserERKNS_7Collada6EffectERKNS6_7SamplerE13aiTextureTypej:
 1478|     12|        unsigned int idx) {
 1479|       |    // first of all, basic file name
 1480|     12|    const aiString name = FindFilenameForEffectTexture(pParser, effect, sampler.mName);
 1481|     12|    mat.AddProperty(&name, _AI_MATKEY_TEXTURE_BASE, type, idx);
 1482|       |
 1483|       |    // mapping mode
 1484|     12|    int map = aiTextureMapMode_Clamp;
 1485|     12|    if (sampler.mWrapU) {
  ------------------
  |  Branch (1485:9): [True: 12, False: 0]
  ------------------
 1486|     12|        map = aiTextureMapMode_Wrap;
 1487|     12|    }
 1488|     12|    if (sampler.mWrapU && sampler.mMirrorU) {
  ------------------
  |  Branch (1488:9): [True: 12, False: 0]
  |  Branch (1488:27): [True: 0, False: 12]
  ------------------
 1489|      0|        map = aiTextureMapMode_Mirror;
 1490|      0|    }
 1491|       |
 1492|     12|    mat.AddProperty(&map, 1, _AI_MATKEY_MAPPINGMODE_U_BASE, type, idx);
 1493|       |
 1494|     12|    map = aiTextureMapMode_Clamp;
 1495|     12|    if (sampler.mWrapV) {
  ------------------
  |  Branch (1495:9): [True: 12, False: 0]
  ------------------
 1496|     12|        map = aiTextureMapMode_Wrap;
 1497|     12|    }
 1498|     12|    if (sampler.mWrapV && sampler.mMirrorV) {
  ------------------
  |  Branch (1498:9): [True: 12, False: 0]
  |  Branch (1498:27): [True: 0, False: 12]
  ------------------
 1499|      0|        map = aiTextureMapMode_Mirror;
 1500|      0|    }
 1501|       |
 1502|     12|    mat.AddProperty(&map, 1, _AI_MATKEY_MAPPINGMODE_V_BASE, type, idx);
 1503|       |
 1504|       |    // UV transformation
 1505|     12|    mat.AddProperty(&sampler.mTransform, 1,
 1506|     12|            _AI_MATKEY_UVTRANSFORM_BASE, type, idx);
 1507|       |
 1508|       |    // Blend mode
 1509|     12|    mat.AddProperty((int *)&sampler.mOp, 1,
 1510|     12|            _AI_MATKEY_TEXBLEND_BASE, type, idx);
 1511|       |
 1512|       |    // Blend factor
 1513|     12|    mat.AddProperty((ai_real *)&sampler.mWeighting, 1,
 1514|     12|            _AI_MATKEY_TEXBLEND_BASE, type, idx);
 1515|       |
 1516|       |    // UV source index ... if we didn't resolve the mapping, it is actually just
 1517|       |    // a guess but it works in most cases. We search for the frst occurrence of a
 1518|       |    // number in the channel name. We assume it is the zero-based index into the
 1519|       |    // UV channel array of all corresponding meshes. It could also be one-based
 1520|       |    // for some exporters, but we won't care of it unless someone complains about.
 1521|     12|    if (sampler.mUVId != UINT_MAX) {
  ------------------
  |  Branch (1521:9): [True: 10, False: 2]
  ------------------
 1522|     10|        map = sampler.mUVId;
 1523|     10|    } else {
 1524|      2|        map = -1;
 1525|     16|        for (auto it = sampler.mUVChannel.begin(); it != sampler.mUVChannel.end(); ++it) {
  ------------------
  |  Branch (1525:52): [True: 16, False: 0]
  ------------------
 1526|     16|            if (IsNumeric(*it)) {
  ------------------
  |  Branch (1526:17): [True: 2, False: 14]
  ------------------
 1527|      2|                map = strtoul10(&(*it));
 1528|      2|                break;
 1529|      2|            }
 1530|     16|        }
 1531|      2|        if (-1 == map) {
  ------------------
  |  Branch (1531:13): [True: 0, False: 2]
  ------------------
 1532|      0|            ASSIMP_LOG_WARN("Collada: unable to determine UV channel for texture");
 1533|      0|            map = 0;
 1534|      0|        }
 1535|      2|    }
 1536|       |    mat.AddProperty(&map, 1, _AI_MATKEY_UVWSRC_BASE, type, idx);
 1537|     12|}
_ZN6Assimp13ColladaLoader13FillMaterialsERKNS_13ColladaParserEP7aiScene:
 1541|     16|void ColladaLoader::FillMaterials(const ColladaParser &pParser, aiScene * /*pScene*/) {
 1542|     24|    for (auto &elem : newMats) {
  ------------------
  |  Branch (1542:21): [True: 24, False: 16]
  ------------------
 1543|     24|        auto &mat = (aiMaterial &)*elem.second;
 1544|     24|        Collada::Effect &effect = *elem.first;
 1545|       |
 1546|       |        // resolve shading mode
 1547|     24|        int shadeMode;
 1548|     24|        if (effect.mFaceted) {
  ------------------
  |  Branch (1548:13): [True: 0, False: 24]
  ------------------
 1549|      0|            shadeMode = aiShadingMode_Flat;
 1550|     24|        } else {
 1551|     24|            switch (effect.mShadeType) {
 1552|      0|            case Collada::Shade_Constant:
  ------------------
  |  Branch (1552:13): [True: 0, False: 24]
  ------------------
 1553|      0|                shadeMode = aiShadingMode_NoShading;
 1554|      0|                break;
 1555|      2|            case Collada::Shade_Lambert:
  ------------------
  |  Branch (1555:13): [True: 2, False: 22]
  ------------------
 1556|      2|                shadeMode = aiShadingMode_Gouraud;
 1557|      2|                break;
 1558|      6|            case Collada::Shade_Blinn:
  ------------------
  |  Branch (1558:13): [True: 6, False: 18]
  ------------------
 1559|      6|                shadeMode = aiShadingMode_Blinn;
 1560|      6|                break;
 1561|     16|            case Collada::Shade_Phong:
  ------------------
  |  Branch (1561:13): [True: 16, False: 8]
  ------------------
 1562|     16|                shadeMode = aiShadingMode_Phong;
 1563|     16|                break;
 1564|       |
 1565|      0|            default:
  ------------------
  |  Branch (1565:13): [True: 0, False: 24]
  ------------------
 1566|      0|                ASSIMP_LOG_WARN("Collada: Unrecognized shading mode, using gouraud shading");
 1567|      0|                shadeMode = aiShadingMode_Gouraud;
 1568|      0|                break;
 1569|     24|            }
 1570|     24|        }
 1571|     24|        mat.AddProperty<int>(&shadeMode, 1, AI_MATKEY_SHADING_MODEL);
 1572|       |
 1573|       |        // double-sided?
 1574|     24|        shadeMode = effect.mDoubleSided;
 1575|     24|        mat.AddProperty<int>(&shadeMode, 1, AI_MATKEY_TWOSIDED);
 1576|       |
 1577|       |        // wire-frame?
 1578|     24|        shadeMode = effect.mWireframe;
 1579|     24|        mat.AddProperty<int>(&shadeMode, 1, AI_MATKEY_ENABLE_WIREFRAME);
 1580|       |
 1581|       |        // add material colors
 1582|     24|        mat.AddProperty(&effect.mAmbient, 1, AI_MATKEY_COLOR_AMBIENT);
 1583|     24|        mat.AddProperty(&effect.mDiffuse, 1, AI_MATKEY_COLOR_DIFFUSE);
 1584|     24|        mat.AddProperty(&effect.mSpecular, 1, AI_MATKEY_COLOR_SPECULAR);
 1585|     24|        mat.AddProperty(&effect.mEmissive, 1, AI_MATKEY_COLOR_EMISSIVE);
 1586|     24|        mat.AddProperty(&effect.mReflective, 1, AI_MATKEY_COLOR_REFLECTIVE);
 1587|       |
 1588|       |        // scalar properties
 1589|     24|        mat.AddProperty(&effect.mShininess, 1, AI_MATKEY_SHININESS);
 1590|     24|        mat.AddProperty(&effect.mReflectivity, 1, AI_MATKEY_REFLECTIVITY);
 1591|     24|        mat.AddProperty(&effect.mRefractIndex, 1, AI_MATKEY_REFRACTI);
 1592|       |
 1593|       |        // transparency, a very hard one. seemingly not all files are following the
 1594|       |        // specification here (1.0 transparency => completely opaque)...
 1595|       |        // therefore, we let the opportunity for the user to manually invert
 1596|       |        // the transparency if necessary and we add preliminary support for RGB_ZERO mode
 1597|     24|        if (effect.mTransparency >= 0.f && effect.mTransparency <= 1.f) {
  ------------------
  |  Branch (1597:13): [True: 24, False: 0]
  |  Branch (1597:44): [True: 24, False: 0]
  ------------------
 1598|       |            // handle RGB transparency completely, cf Collada specs 1.5.0 pages 249 and 304
 1599|     24|            if (effect.mRGBTransparency) {
  ------------------
  |  Branch (1599:17): [True: 0, False: 24]
  ------------------
 1600|       |                // use luminance as defined by ISO/CIE color standards (see ITU-R Recommendation BT.709-4)
 1601|      0|                effect.mTransparency *= (0.212671f * effect.mTransparent.r +
 1602|      0|                                         0.715160f * effect.mTransparent.g +
 1603|      0|                                         0.072169f * effect.mTransparent.b);
 1604|       |
 1605|      0|                effect.mTransparent.a = 1.f;
 1606|       |
 1607|      0|                mat.AddProperty(&effect.mTransparent, 1, AI_MATKEY_COLOR_TRANSPARENT);
 1608|     24|            } else {
 1609|     24|                effect.mTransparency *= effect.mTransparent.a;
 1610|     24|            }
 1611|       |
 1612|     24|            if (effect.mInvertTransparency) {
  ------------------
  |  Branch (1612:17): [True: 0, False: 24]
  ------------------
 1613|      0|                effect.mTransparency = 1.f - effect.mTransparency;
 1614|      0|            }
 1615|       |
 1616|       |            // Is the material finally transparent ?
 1617|     24|            if (effect.mHasTransparency || effect.mTransparency < 1.f) {
  ------------------
  |  Branch (1617:17): [True: 22, False: 2]
  |  Branch (1617:44): [True: 0, False: 2]
  ------------------
 1618|     22|                mat.AddProperty(&effect.mTransparency, 1, AI_MATKEY_OPACITY);
 1619|     22|            }
 1620|     24|        }
 1621|       |
 1622|       |        // add textures, if given
 1623|     24|        if (!effect.mTexAmbient.mName.empty()) {
  ------------------
  |  Branch (1623:13): [True: 0, False: 24]
  ------------------
 1624|       |            // It is merely a light-map
 1625|      0|            AddTexture(mat, pParser, effect, effect.mTexAmbient, aiTextureType_LIGHTMAP);
 1626|      0|        }
 1627|       |
 1628|     24|        if (!effect.mTexEmissive.mName.empty())
  ------------------
  |  Branch (1628:13): [True: 0, False: 24]
  ------------------
 1629|      0|            AddTexture(mat, pParser, effect, effect.mTexEmissive, aiTextureType_EMISSIVE);
 1630|       |
 1631|     24|        if (!effect.mTexSpecular.mName.empty())
  ------------------
  |  Branch (1631:13): [True: 0, False: 24]
  ------------------
 1632|      0|            AddTexture(mat, pParser, effect, effect.mTexSpecular, aiTextureType_SPECULAR);
 1633|       |
 1634|     24|        if (!effect.mTexDiffuse.mName.empty())
  ------------------
  |  Branch (1634:13): [True: 12, False: 12]
  ------------------
 1635|     12|            AddTexture(mat, pParser, effect, effect.mTexDiffuse, aiTextureType_DIFFUSE);
 1636|       |
 1637|     24|        if (!effect.mTexBump.mName.empty())
  ------------------
  |  Branch (1637:13): [True: 0, False: 24]
  ------------------
 1638|      0|            AddTexture(mat, pParser, effect, effect.mTexBump, aiTextureType_NORMALS);
 1639|       |
 1640|     24|        if (!effect.mTexTransparent.mName.empty())
  ------------------
  |  Branch (1640:13): [True: 0, False: 24]
  ------------------
 1641|      0|            AddTexture(mat, pParser, effect, effect.mTexTransparent, aiTextureType_OPACITY);
 1642|       |
 1643|     24|        if (!effect.mTexReflective.mName.empty())
  ------------------
  |  Branch (1643:13): [True: 0, False: 24]
  ------------------
 1644|      0|            AddTexture(mat, pParser, effect, effect.mTexReflective, aiTextureType_REFLECTION);
 1645|     24|    }
 1646|     16|}
_ZN6Assimp13ColladaLoader14BuildMaterialsERNS_13ColladaParserEP7aiScene:
 1650|     16|void ColladaLoader::BuildMaterials(ColladaParser &pParser, aiScene * /*pScene*/) {
 1651|     16|    newMats.reserve(pParser.mMaterialLibrary.size());
 1652|       |
 1653|     16|    for (auto matIt = pParser.mMaterialLibrary.begin();
 1654|     40|            matIt != pParser.mMaterialLibrary.end(); ++matIt) {
  ------------------
  |  Branch (1654:13): [True: 24, False: 16]
  ------------------
 1655|     24|        const Material &material = matIt->second;
 1656|       |        // a material is only a reference to an effect
 1657|     24|        auto effIt = pParser.mEffectLibrary.find(material.mEffect);
 1658|     24|        if (effIt == pParser.mEffectLibrary.end())
  ------------------
  |  Branch (1658:13): [True: 0, False: 24]
  ------------------
 1659|      0|            continue;
 1660|     24|        Effect &effect = effIt->second;
 1661|       |
 1662|       |        // create material
 1663|     24|        auto *mat = new aiMaterial;
 1664|     24|        aiString name(material.mName.empty() ? matIt->first : material.mName);
  ------------------
  |  Branch (1664:23): [True: 0, False: 24]
  ------------------
 1665|     24|        mat->AddProperty(&name, AI_MATKEY_NAME);
 1666|       |
 1667|       |        // store the material
 1668|     24|        mMaterialIndexByName[matIt->first] = newMats.size();
 1669|     24|        newMats.emplace_back(&effect, mat);
 1670|     24|    }
 1671|       |    // ScenePreprocessor generates a default material automatically if none is there.
 1672|       |    // All further code here in this loader works well without a valid material so
 1673|       |    // we can safely let it to ScenePreprocessor.
 1674|     16|}
_ZN6Assimp13ColladaLoader28FindFilenameForEffectTextureERKNS_13ColladaParserERKNS_7Collada6EffectERKNSt3__112basic_stringIcNS8_11char_traitsIcEENS8_9allocatorIcEEEE:
 1679|     12|        const Effect &pEffect, const std::string &pName) {
 1680|     12|    aiString result;
 1681|       |
 1682|       |    // recurse through the param references until we end up at an image
 1683|     12|    std::string name = pName;
 1684|     32|    while (true) {
  ------------------
  |  Branch (1684:12): [True: 32, Folded]
  ------------------
 1685|       |        // the given string is a param entry. Find it
 1686|     32|        auto it = pEffect.mParams.find(name);
 1687|       |        // if not found, we're at the end of the recursion. The resulting string should be the image ID
 1688|     32|        if (it == pEffect.mParams.end())
  ------------------
  |  Branch (1688:13): [True: 12, False: 20]
  ------------------
 1689|     12|            break;
 1690|       |
 1691|       |        // else recurse on
 1692|     20|        name = it->second.mReference;
 1693|     20|    }
 1694|       |
 1695|       |    // find the image referred by this name in the image library of the scene
 1696|     12|    auto imIt = pParser.mImageLibrary.find(name);
 1697|     12|    if (imIt == pParser.mImageLibrary.end()) {
  ------------------
  |  Branch (1697:9): [True: 0, False: 12]
  ------------------
 1698|      0|        ASSIMP_LOG_WARN("Collada: Unable to resolve effect texture entry \"", pName, "\", ended up at ID \"", name, "\".");
 1699|       |
 1700|       |        //set default texture file name
 1701|      0|        result.Set(name + ".jpg");
 1702|      0|        ColladaParser::UriDecodePath(result);
 1703|      0|        return result;
 1704|      0|    }
 1705|       |
 1706|       |    // if this is an embedded texture image setup an aiTexture for it
 1707|     12|    if (!imIt->second.mImageData.empty()) {
  ------------------
  |  Branch (1707:9): [True: 2, False: 10]
  ------------------
 1708|      2|        auto *tex = new aiTexture();
 1709|       |
 1710|       |        // Store embedded texture name reference
 1711|      2|        tex->mFilename.Set(imIt->second.mFileName.c_str());
 1712|      2|        result.Set(imIt->second.mFileName);
 1713|       |
 1714|       |        // setup format hint
 1715|      2|        if (imIt->second.mEmbeddedFormat.length() >= HINTMAXTEXTURELEN) {
  ------------------
  |  Branch (1715:13): [True: 0, False: 2]
  ------------------
 1716|      0|            ASSIMP_LOG_WARN("Collada: texture format hint is too long, truncating to 3 characters");
 1717|      0|        }
 1718|      2|        strncpy(tex->achFormatHint, imIt->second.mEmbeddedFormat.c_str(), 3);
 1719|       |
 1720|       |        // and copy texture data
 1721|      2|        tex->mHeight = 0;
 1722|      2|        tex->mWidth = static_cast<unsigned int>(imIt->second.mImageData.size());
 1723|      2|        tex->pcData = (aiTexel *)new char[tex->mWidth];
 1724|      2|        memcpy(tex->pcData, &imIt->second.mImageData[0], tex->mWidth);
 1725|       |
 1726|       |        // and add this texture to the list
 1727|      2|        mTextures.push_back(tex);
 1728|      2|        return result;
 1729|      2|    }
 1730|       |
 1731|     10|    if (imIt->second.mFileName.empty()) {
  ------------------
  |  Branch (1731:9): [True: 0, False: 10]
  ------------------
 1732|      0|        throw DeadlyImportError("Collada: Invalid texture, no data or file reference given");
 1733|      0|    }
 1734|       |
 1735|     10|    result.Set(imIt->second.mFileName);
 1736|       |
 1737|     10|    return result;
 1738|     10|}
_ZNK6Assimp13ColladaLoader10ReadStringERKNS_7Collada8AccessorERKNS1_4DataEm:
 1742|      4|const std::string &ColladaLoader::ReadString(const Accessor &pAccessor, const Data &pData, size_t pIndex) const {
 1743|      4|    size_t pos = pAccessor.mStride * pIndex + pAccessor.mOffset;
 1744|      4|    ai_assert(pos < pData.mStrings.size());
  ------------------
  |  |   67|      4|#   define ai_assert(expression) (void)((!!(expression)) || (Assimp::aiAssertViolation(#expression, __FILE__, __LINE__), 0))
  |  |  ------------------
  |  |  |  Branch (67:41): [True: 4, False: 0]
  |  |  |  Branch (67:61): [True: 0, False: 0]
  |  |  ------------------
  ------------------
 1745|      4|    return pData.mStrings[pos];
 1746|      4|}
_ZNK6Assimp13ColladaLoader12CollectNodesEPK6aiNodeRNSt3__16vectorIS3_NS4_9allocatorIS3_EEEE:
 1750|    225|void ColladaLoader::CollectNodes(const aiNode *pNode, std::vector<const aiNode *> &poNodes) const {
 1751|    225|    poNodes.push_back(pNode);
 1752|    437|    for (size_t a = 0; a < pNode->mNumChildren; ++a) {
  ------------------
  |  Branch (1752:24): [True: 212, False: 225]
  ------------------
 1753|    212|        CollectNodes(pNode->mChildren[a], poNodes);
 1754|    212|    }
 1755|    225|}
_ZNK6Assimp13ColladaLoader8FindNodeEPKNS_7Collada4NodeERKNSt3__112basic_stringIcNS5_11char_traitsIcEENS5_9allocatorIcEEEE:
 1759|  8.84k|const Node *ColladaLoader::FindNode(const Node *pNode, const std::string &pName) const {
 1760|  8.84k|    if (pNode->mName == pName || pNode->mID == pName)
  ------------------
  |  Branch (1760:9): [True: 153, False: 8.69k]
  |  Branch (1760:34): [True: 72, False: 8.62k]
  ------------------
 1761|    225|        return pNode;
 1762|       |
 1763|  8.62k|    for (auto a : pNode->mChildren) {
  ------------------
  |  Branch (1763:17): [True: 8.62k, False: 4.13k]
  ------------------
 1764|  8.62k|        const Collada::Node *node = FindNode(a, pName);
 1765|  8.62k|        if (node) {
  ------------------
  |  Branch (1765:13): [True: 4.48k, False: 4.13k]
  ------------------
 1766|  4.48k|            return node;
 1767|  4.48k|        }
 1768|  8.62k|    }
 1769|       |
 1770|  4.13k|    return nullptr;
 1771|  8.62k|}
_ZNK6Assimp13ColladaLoader13FindNodeBySIDEPKNS_7Collada4NodeERKNSt3__112basic_stringIcNS5_11char_traitsIcEENS5_9allocatorIcEEEE:
 1775|     18|const Node *ColladaLoader::FindNodeBySID(const Node *pNode, const std::string &pSID) const {
 1776|     18|    if (nullptr == pNode) {
  ------------------
  |  Branch (1776:9): [True: 0, False: 18]
  ------------------
 1777|      0|        return nullptr;
 1778|      0|    }
 1779|       |
 1780|     18|    if (pNode->mSID == pSID) {
  ------------------
  |  Branch (1780:9): [True: 4, False: 14]
  ------------------
 1781|      4|        return pNode;
 1782|      4|    }
 1783|       |
 1784|     14|    for (auto a : pNode->mChildren) {
  ------------------
  |  Branch (1784:17): [True: 14, False: 0]
  ------------------
 1785|     14|        const Collada::Node *node = FindNodeBySID(a, pSID);
 1786|     14|        if (node) {
  ------------------
  |  Branch (1786:13): [True: 14, False: 0]
  ------------------
 1787|     14|            return node;
 1788|     14|        }
 1789|     14|    }
 1790|       |
 1791|      0|    return nullptr;
 1792|     14|}
_ZN6Assimp13ColladaLoader15FindNameForNodeEPKNS_7Collada4NodeE:
 1797|    200|std::string ColladaLoader::FindNameForNode(const Node *pNode) {
 1798|       |    // If explicitly requested, just use the collada name.
 1799|    200|    if (useColladaName) {
  ------------------
  |  Branch (1799:9): [True: 0, False: 200]
  ------------------
 1800|      0|        if (!pNode->mName.empty()) {
  ------------------
  |  Branch (1800:13): [True: 0, False: 0]
  ------------------
 1801|      0|            return pNode->mName;
 1802|      0|        } else {
 1803|      0|            return format() << "$ColladaAutoName$_" << mNodeNameCounter++;
 1804|      0|        }
 1805|    200|    } else {
 1806|       |        // Now setup the name of the assimp node. The collada name might not be
 1807|       |        // unique, so we use the collada ID.
 1808|    200|        if (!pNode->mID.empty())
  ------------------
  |  Branch (1808:13): [True: 200, False: 0]
  ------------------
 1809|    200|            return pNode->mID;
 1810|      0|        else if (!pNode->mSID.empty())
  ------------------
  |  Branch (1810:18): [True: 0, False: 0]
  ------------------
 1811|      0|            return pNode->mSID;
 1812|      0|        else {
 1813|       |            // No need to worry. Unnamed nodes are no problem at all, except
 1814|       |            // if cameras or lights need to be assigned to them.
 1815|      0|            return format() << "$ColladaAutoName$_" << mNodeNameCounter++;
 1816|      0|        }
 1817|    200|    }
 1818|    200|}
ColladaLoader.cpp:_ZN6AssimpL34ApplyVertexToEffectSemanticMappingERNS_7Collada7SamplerERKNS0_20SemanticMappingTableE:
  310|     78|static void ApplyVertexToEffectSemanticMapping(Sampler &sampler, const SemanticMappingTable &table) {
  311|     78|    const auto it = table.mMap.find(sampler.mUVChannel);
  312|     78|    if (it == table.mMap.end()) {
  ------------------
  |  Branch (312:9): [True: 68, False: 10]
  ------------------
  313|     68|        return;
  314|     68|    }
  315|       |
  316|     10|    if (it->second.mType != IT_Texcoord) {
  ------------------
  |  Branch (316:9): [True: 10, False: 0]
  ------------------
  317|     10|        ASSIMP_LOG_ERROR("Collada: Unexpected effect input mapping");
  318|     10|    }
  319|       |
  320|     10|    sampler.mUVId = it->second.mSet;
  321|     10|}
ColladaLoader.cpp:_ZN6AssimpL9ReadFloatERKNS_7Collada8AccessorERKNS0_4DataEmm:
   94|  17.3k|static ai_real ReadFloat(const Accessor &pAccessor, const Data &pData, size_t pIndex, size_t pOffset) {
   95|  17.3k|    const size_t pos = pAccessor.mStride * pIndex + pAccessor.mOffset + pOffset;
   96|  17.3k|    ai_assert(pos < pData.mValues.size());
  ------------------
  |  |   67|  17.3k|#   define ai_assert(expression) (void)((!!(expression)) || (Assimp::aiAssertViolation(#expression, __FILE__, __LINE__), 0))
  |  |  ------------------
  |  |  |  Branch (67:41): [True: 17.3k, False: 0]
  |  |  |  Branch (67:61): [True: 0, False: 0]
  |  |  ------------------
  ------------------
   97|  17.3k|    return pData.mValues[pos];
   98|  17.3k|}
ColladaLoader.cpp:_ZZN6Assimp13ColladaLoader18BuildMeshesForNodeERKNS_13ColladaParserEPKNS_7Collada4NodeEP6aiNodeENK17UIntTypeConverterclERKm:
  558|     90|            unsigned int operator()(const size_t &v) const {
  559|     90|                return static_cast<unsigned int>(v);
  560|     90|            }

_ZN6Assimp16ColladaMeshIndexC2ERKNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEmS9_:
   63|     90|            mMeshID(pMeshID), mSubMesh(pSubMesh), mMaterial(pMaterial) {
   64|     90|        ai_assert(!pMeshID.empty());
  ------------------
  |  |   67|     90|#   define ai_assert(expression) (void)((!!(expression)) || (Assimp::aiAssertViolation(#expression, __FILE__, __LINE__), 0))
  |  |  ------------------
  |  |  |  Branch (67:41): [True: 90, False: 0]
  |  |  |  Branch (67:61): [True: 0, False: 0]
  |  |  ------------------
  ------------------
   65|     90|    }
_ZNK6Assimp16ColladaMeshIndexltERKS0_:
   67|  1.38k|    bool operator<(const ColladaMeshIndex &p) const {
   68|  1.38k|        if (mMeshID == p.mMeshID) {
  ------------------
  |  Branch (68:13): [True: 33, False: 1.35k]
  ------------------
   69|     33|            if (mSubMesh == p.mSubMesh)
  ------------------
  |  Branch (69:17): [True: 0, False: 33]
  ------------------
   70|      0|                return mMaterial < p.mMaterial;
   71|     33|            else
   72|     33|                return mSubMesh < p.mSubMesh;
   73|  1.35k|        } else {
   74|  1.35k|            return mMeshID < p.mMeshID;
   75|  1.35k|        }
   76|  1.38k|    }
_ZN6Assimp13ColladaLoaderD2Ev:
   91|    624|    ~ColladaLoader() override = default;

_ZN6Assimp13ColladaParserC2EPNS_8IOSystemERKNSt3__112basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEE:
  415|     31|        mFileName(pFile),
  416|     31|        mRootNode(nullptr),
  417|     31|        mUnitSize(1.0f),
  418|     31|        mUpDirection(UP_Y),
  419|     31|        mFormat(FV_1_5_n) {
  420|     31|    if (nullptr == pIOHandler) {
  ------------------
  |  Branch (420:9): [True: 0, False: 31]
  ------------------
  421|      0|        throw DeadlyImportError("IOSystem is nullptr.");
  422|      0|    }
  423|       |
  424|     31|    std::unique_ptr<IOStream> daeFile;
  425|     31|    std::unique_ptr<ZipArchiveIOSystem> zip_archive;
  426|       |
  427|       |    // Determine type
  428|     31|    const std::string extension = BaseImporter::GetExtension(pFile);
  429|     31|    if (extension != "dae") {
  ------------------
  |  Branch (429:9): [True: 31, False: 0]
  ------------------
  430|     31|        zip_archive = std::make_unique<ZipArchiveIOSystem>(pIOHandler, pFile);
  431|     31|    }
  432|       |
  433|     31|    if (zip_archive && zip_archive->isOpen()) {
  ------------------
  |  Branch (433:9): [True: 31, False: 0]
  |  Branch (433:24): [True: 3, False: 28]
  ------------------
  434|      3|        std::string dae_filename = ReadZaeManifest(*zip_archive);
  435|       |
  436|      3|        if (dae_filename.empty()) {
  ------------------
  |  Branch (436:13): [True: 0, False: 3]
  ------------------
  437|      0|            throw DeadlyImportError("Invalid ZAE");
  438|      0|        }
  439|       |
  440|      3|        daeFile.reset(zip_archive->Open(dae_filename.c_str()));
  441|      3|        if (daeFile == nullptr) {
  ------------------
  |  Branch (441:13): [True: 1, False: 2]
  ------------------
  442|      1|            throw DeadlyImportError("Invalid ZAE manifest: '", dae_filename, "' is missing");
  443|      1|        }
  444|     28|    } else {
  445|       |        // attempt to open the file directly
  446|     28|        daeFile.reset(pIOHandler->Open(pFile));
  447|     28|        if (daeFile == nullptr) {
  ------------------
  |  Branch (447:13): [True: 0, False: 28]
  ------------------
  448|      0|            throw DeadlyImportError("Failed to open file '", pFile, "'.");
  449|      0|        }
  450|     28|    }
  451|       |
  452|       |    // generate a XML reader for it
  453|     30|    if (!mXmlParser.parse(daeFile.get())) {
  ------------------
  |  Branch (453:9): [True: 0, False: 30]
  ------------------
  454|      0|        throw DeadlyImportError("Unable to read file, malformed XML");
  455|      0|    }
  456|       |    // start reading
  457|     30|    const XmlNode node = mXmlParser.getRootNode();
  458|     30|    XmlNode colladaNode = node.child("COLLADA");
  459|     30|    if (colladaNode.empty()) {
  ------------------
  |  Branch (459:9): [True: 0, False: 30]
  ------------------
  460|      0|        return;
  461|      0|    }
  462|       |
  463|       |    // Read content and embedded textures
  464|     30|    ReadContents(colladaNode);
  465|     30|    if (zip_archive && zip_archive->isOpen()) {
  ------------------
  |  Branch (465:9): [True: 16, False: 14]
  |  Branch (465:24): [True: 2, False: 14]
  ------------------
  466|      2|        ReadEmbeddedTextures(*zip_archive);
  467|      2|    }
  468|     30|}
_ZN6Assimp13ColladaParserD2Ev:
  472|     16|ColladaParser::~ColladaParser() {
  473|     16|    for (auto &it : mNodeLibrary) {
  ------------------
  |  Branch (473:19): [True: 16, False: 16]
  ------------------
  474|     16|        delete it.second;
  475|     16|    }
  476|     85|    for (auto &it : mMeshLibrary) {
  ------------------
  |  Branch (476:19): [True: 85, False: 16]
  ------------------
  477|     85|        delete it.second;
  478|     85|    }
  479|     16|}
_ZN6Assimp13ColladaParser15ReadZaeManifestERNS_18ZipArchiveIOSystemE:
  483|     13|std::string ColladaParser::ReadZaeManifest(ZipArchiveIOSystem &zip_archive) {
  484|       |    // Open the manifest
  485|     13|    std::unique_ptr<IOStream> manifestfile(zip_archive.Open("manifest.xml"));
  486|     13|    if (manifestfile == nullptr) {
  ------------------
  |  Branch (486:9): [True: 9, False: 4]
  ------------------
  487|       |        // No manifest, hope there is only one .DAE inside
  488|      9|        std::vector<std::string> file_list;
  489|      9|        zip_archive.getFileListExtension(file_list, "dae");
  490|       |
  491|      9|        if (file_list.empty()) {
  ------------------
  |  Branch (491:13): [True: 7, False: 2]
  ------------------
  492|      7|            return {};
  493|      7|        }
  494|       |
  495|      2|        return file_list.front();
  496|      9|    }
  497|      4|    XmlParser manifestParser;
  498|      4|    if (!manifestParser.parse(manifestfile.get())) {
  ------------------
  |  Branch (498:9): [True: 0, False: 4]
  ------------------
  499|      0|        return {};
  500|      0|    }
  501|       |
  502|      4|    XmlNode root = manifestParser.getRootNode();
  503|      4|    const std::string &name = root.name();
  504|      4|    if (name != "dae_root") {
  ------------------
  |  Branch (504:9): [True: 4, False: 0]
  ------------------
  505|      4|        root = *manifestParser.findNode("dae_root");
  506|      4|        if (nullptr == root) {
  ------------------
  |  Branch (506:13): [True: 0, False: 4]
  ------------------
  507|      0|            return {};
  508|      0|        }
  509|      4|        std::string v;
  510|      4|        XmlParser::getValueAsString(root, v);
  511|      4|        aiString ai_str(v);
  512|      4|        UriDecodePath(ai_str);
  513|      4|        return std::string(ai_str.C_Str());
  514|      4|    }
  515|       |
  516|      0|    return {};
  517|      4|}
_ZN6Assimp13ColladaParser13UriDecodePathER8aiString:
  521|     22|void ColladaParser::UriDecodePath(aiString &ss) {
  522|       |    // TODO: collada spec, p 22. Handle URI correctly.
  523|       |    // For the moment we're just stripping the file:// away to make it work.
  524|       |    // Windows doesn't seem to be able to find stuff like
  525|       |    // 'file://..\LWO\LWO2\MappingModes\earthSpherical.jpg'
  526|     22|    if (0 == strncmp(ss.data, "file://", 7)) {
  ------------------
  |  Branch (526:9): [True: 1, False: 21]
  ------------------
  527|      1|        ss.length -= 7;
  528|      1|        memmove(ss.data, ss.data + 7, ss.length);
  529|      1|        ss.data[ss.length] = '\0';
  530|      1|    }
  531|       |
  532|       |    // Maxon Cinema Collada Export writes "file:///C:\andsoon" with three slashes...
  533|       |    // I need to filter it without destroying linux paths starting with "/somewhere"
  534|     22|    if (ss.data[0] == '/' && isalpha((unsigned char)ss.data[1]) && ss.data[2] == ':') {
  ------------------
  |  Branch (534:9): [True: 0, False: 22]
  |  Branch (534:30): [True: 0, False: 0]
  |  Branch (534:68): [True: 0, False: 0]
  ------------------
  535|      0|        --ss.length;
  536|      0|        ::memmove(ss.data, ss.data + 1, ss.length);
  537|      0|        ss.data[ss.length] = 0;
  538|      0|    }
  539|       |
  540|       |    // find and convert all %xy special chars
  541|     22|    char *out = ss.data;
  542|    549|    for (const char *it = ss.data; it != ss.data + ss.length; /**/) {
  ------------------
  |  Branch (542:36): [True: 527, False: 22]
  ------------------
  543|    527|        if (*it == '%' && (it + 3) < ss.data + ss.length) {
  ------------------
  |  Branch (543:13): [True: 5, False: 522]
  |  Branch (543:27): [True: 5, False: 0]
  ------------------
  544|       |            // separate the number to avoid dragging in chars from behind into the parsing
  545|      5|            char mychar[3] = { it[1], it[2], 0 };
  546|      5|            size_t nbr = strtoul16(mychar);
  547|      5|            it += 3;
  548|      5|            *out++ = static_cast<char>(nbr & 0xFF);
  549|    522|        } else {
  550|    522|            *out++ = *it++;
  551|    522|        }
  552|    527|    }
  553|       |
  554|       |    // adjust length and terminator of the shortened string
  555|     22|    *out = 0;
  556|     22|    ai_assert(out > ss.data);
  ------------------
  |  |   67|     22|#   define ai_assert(expression) (void)((!!(expression)) || (Assimp::aiAssertViolation(#expression, __FILE__, __LINE__), 0))
  |  |  ------------------
  |  |  |  Branch (67:41): [True: 22, False: 0]
  |  |  |  Branch (67:61): [True: 0, False: 0]
  |  |  ------------------
  ------------------
  557|     22|    ss.length = static_cast<ai_uint32>(out - ss.data);
  558|     22|}
_ZN6Assimp13ColladaParser12ReadContentsERN4pugi8xml_nodeE:
  562|     30|void ColladaParser::ReadContents(XmlNode &node) {
  563|     30|    if (const std::string name = node.name(); name == "COLLADA") {
  ------------------
  |  Branch (563:47): [True: 30, False: 0]
  ------------------
  564|     30|        std::string version;
  565|     30|        if (XmlParser::getStdStrAttribute(node, "version", version)) {
  ------------------
  |  Branch (565:13): [True: 30, False: 0]
  ------------------
  566|     30|            aiString v;
  567|     30|            v.Set(version);
  568|     30|            mAssetMetaData.emplace(AI_METADATA_SOURCE_FORMAT_VERSION, v);
  569|     30|            if (!::strncmp(version.c_str(), "1.5", 3)) {
  ------------------
  |  Branch (569:17): [True: 0, False: 30]
  ------------------
  570|      0|                mFormat = FV_1_5_n;
  571|      0|                ASSIMP_LOG_DEBUG("Collada schema version is 1.5.n");
  572|     30|            } else if (!::strncmp(version.c_str(), "1.4", 3)) {
  ------------------
  |  Branch (572:24): [True: 30, False: 0]
  ------------------
  573|     30|                mFormat = FV_1_4_n;
  574|     30|                ASSIMP_LOG_DEBUG("Collada schema version is 1.4.n");
  575|     30|            } else if (!::strncmp(version.c_str(), "1.3", 3)) {
  ------------------
  |  Branch (575:24): [True: 0, False: 0]
  ------------------
  576|      0|                mFormat = FV_1_3_n;
  577|       |                ASSIMP_LOG_DEBUG("Collada schema version is 1.3.n");
  578|      0|            }
  579|     30|        }
  580|     30|        ReadStructure(node);
  581|     30|    }
  582|     30|}
_ZN6Assimp13ColladaParser13ReadStructureERN4pugi8xml_nodeE:
  586|     30|void ColladaParser::ReadStructure(XmlNode &node) {
  587|    194|    for (XmlNode &currentNode : node.children()) {
  ------------------
  |  Branch (587:31): [True: 194, False: 30]
  ------------------
  588|    194|        if (const std::string &currentName = currentNode.name(); currentName == "asset") {
  ------------------
  |  Branch (588:66): [True: 30, False: 164]
  ------------------
  589|     30|            ReadAssetInfo(currentNode);
  590|    164|        } else if (currentName == "library_animations") {
  ------------------
  |  Branch (590:20): [True: 4, False: 160]
  ------------------
  591|      4|            ReadAnimationLibrary(currentNode);
  592|    160|        } else if (currentName == "library_animation_clips") {
  ------------------
  |  Branch (592:20): [True: 2, False: 158]
  ------------------
  593|      2|            ReadAnimationClipLibrary(currentNode);
  594|    158|        } else if (currentName == "library_controllers") {
  ------------------
  |  Branch (594:20): [True: 3, False: 155]
  ------------------
  595|      3|            ReadControllerLibrary(currentNode);
  596|    155|        } else if (currentName == "library_images") {
  ------------------
  |  Branch (596:20): [True: 20, False: 135]
  ------------------
  597|     20|            ReadImageLibrary(currentNode);
  598|    135|        } else if (currentName == "library_materials") {
  ------------------
  |  Branch (598:20): [True: 26, False: 109]
  ------------------
  599|     26|            ReadMaterialLibrary(currentNode);
  600|    109|        } else if (currentName == "library_effects") {
  ------------------
  |  Branch (600:20): [True: 26, False: 83]
  ------------------
  601|     26|            ReadEffectLibrary(currentNode);
  602|     83|        } else if (currentName == "library_geometries") {
  ------------------
  |  Branch (602:20): [True: 29, False: 54]
  ------------------
  603|     29|            ReadGeometryLibrary(currentNode);
  604|     54|        } else if (currentName == "library_visual_scenes") {
  ------------------
  |  Branch (604:20): [True: 18, False: 36]
  ------------------
  605|     18|            ReadSceneLibrary(currentNode);
  606|     36|        } else if (currentName == "library_lights") {
  ------------------
  |  Branch (606:20): [True: 10, False: 26]
  ------------------
  607|     10|            ReadLightLibrary(currentNode);
  608|     26|        } else if (currentName == "library_cameras") {
  ------------------
  |  Branch (608:20): [True: 9, False: 17]
  ------------------
  609|      9|            ReadCameraLibrary(currentNode);
  610|     17|        } else if (currentName == "library_nodes") {
  ------------------
  |  Branch (610:20): [True: 0, False: 17]
  ------------------
  611|      0|            ReadSceneNode(currentNode, nullptr); /* some hacking to reuse this piece of code */
  612|     17|        } else if (currentName == "scene") {
  ------------------
  |  Branch (612:20): [True: 17, False: 0]
  ------------------
  613|     17|            ReadScene(currentNode);
  614|     17|        }
  615|    194|    }
  616|       |
  617|     30|    PostProcessRootAnimations();
  618|     30|    PostProcessControllers();
  619|     30|}
_ZN6Assimp13ColladaParser13ReadAssetInfoERN4pugi8xml_nodeE:
  623|     30|void ColladaParser::ReadAssetInfo(XmlNode &node) {
  624|     30|    if (node.empty()) {
  ------------------
  |  Branch (624:9): [True: 0, False: 30]
  ------------------
  625|      0|        return;
  626|      0|    }
  627|       |
  628|    224|    for (XmlNode &currentNode : node.children()) {
  ------------------
  |  Branch (628:31): [True: 224, False: 30]
  ------------------
  629|    224|        if (const std::string &currentName = currentNode.name(); currentName == "unit") {
  ------------------
  |  Branch (629:66): [True: 30, False: 194]
  ------------------
  630|     30|            mUnitSize = 1.f;
  631|     30|            std::string tUnitSizeString;
  632|     30|            if (XmlParser::getStdStrAttribute(currentNode, "meter", tUnitSizeString)) {
  ------------------
  |  Branch (632:17): [True: 28, False: 2]
  ------------------
  633|     28|                try {
  634|     28|                    fast_atoreal_move(tUnitSizeString.data(), mUnitSize);
  635|     28|                } catch (const DeadlyImportError& die) {
  636|      0|                    std::string warning("Collada: Failed to parse meter parameter to real number. Exception:\n");
  637|      0|                    warning.append(die.what());
  638|      0|                    ASSIMP_LOG_WARN(warning.data());
  639|      0|                }
  640|     28|            }
  641|    194|        } else if (currentName == "up_axis") {
  ------------------
  |  Branch (641:20): [True: 30, False: 164]
  ------------------
  642|     30|            std::string v;
  643|     30|            if (!XmlParser::getValueAsString(currentNode, v)) {
  ------------------
  |  Branch (643:17): [True: 0, False: 30]
  ------------------
  644|      0|                continue;
  645|      0|            }
  646|     30|            if (v == "X_UP") {
  ------------------
  |  Branch (646:17): [True: 0, False: 30]
  ------------------
  647|      0|                mUpDirection = UP_X;
  648|     30|            } else if (v == "Z_UP") {
  ------------------
  |  Branch (648:24): [True: 19, False: 11]
  ------------------
  649|     19|                mUpDirection = UP_Z;
  650|     19|            } else {
  651|     11|                mUpDirection = UP_Y;
  652|     11|            }
  653|    164|        } else if (currentName == "contributor") {
  ------------------
  |  Branch (653:20): [True: 30, False: 134]
  ------------------
  654|     98|            for (XmlNode currentChildNode : currentNode.children()) {
  ------------------
  |  Branch (654:43): [True: 98, False: 30]
  ------------------
  655|     98|                ReadMetaDataItem(currentChildNode, mAssetMetaData);
  656|     98|            }
  657|    134|        } else {
  658|    134|            ReadMetaDataItem(currentNode, mAssetMetaData);
  659|    134|        }
  660|    224|    }
  661|     30|}
_ZN6Assimp13ColladaParser24ReadAnimationClipLibraryERN4pugi8xml_nodeE:
  665|      2|void ColladaParser::ReadAnimationClipLibrary(XmlNode &node) {
  666|      2|    if (node.empty()) {
  ------------------
  |  Branch (666:9): [True: 0, False: 2]
  ------------------
  667|      0|        return;
  668|      0|    }
  669|       |
  670|      2|    std::string animName;
  671|      2|    if (!XmlParser::getStdStrAttribute(node, "name", animName)) {
  ------------------
  |  Branch (671:9): [True: 2, False: 0]
  ------------------
  672|      2|        if (!XmlParser::getStdStrAttribute(node, "id", animName)) {
  ------------------
  |  Branch (672:13): [True: 2, False: 0]
  ------------------
  673|      2|            animName = std::string("animation_") + ai_to_string(mAnimationClipLibrary.size());
  674|      2|        }
  675|      2|    }
  676|       |
  677|      2|    std::pair<std::string, std::vector<std::string>> clip;
  678|      2|    clip.first = animName;
  679|       |
  680|      4|    for (XmlNode &currentNode : node.children()) {
  ------------------
  |  Branch (680:31): [True: 4, False: 2]
  ------------------
  681|      4|        const std::string &currentName = currentNode.name();
  682|      4|        if (currentName == "instance_animation") {
  ------------------
  |  Branch (682:13): [True: 0, False: 4]
  ------------------
  683|      0|            std::string url;
  684|      0|            readUrlAttribute(currentNode, url);
  685|      0|            clip.second.push_back(url);
  686|      0|        }
  687|       |
  688|      4|        if (clip.second.size() > 0) {
  ------------------
  |  Branch (688:13): [True: 0, False: 4]
  ------------------
  689|      0|            mAnimationClipLibrary.push_back(clip);
  690|      0|        }
  691|      4|    }
  692|      2|}
_ZN6Assimp13ColladaParser22PostProcessControllersEv:
  696|     16|void ColladaParser::PostProcessControllers() {
  697|     16|    for (auto &it : mControllerLibrary) {
  ------------------
  |  Branch (697:19): [True: 1, False: 16]
  ------------------
  698|      1|        std::string meshId = it.second.mMeshId;
  699|      1|        if (meshId.empty()) {
  ------------------
  |  Branch (699:13): [True: 0, False: 1]
  ------------------
  700|      0|            continue;
  701|      0|        }
  702|       |
  703|      1|        auto findItr = mControllerLibrary.find(meshId);
  704|      1|        while (findItr != mControllerLibrary.end()) {
  ------------------
  |  Branch (704:16): [True: 0, False: 1]
  ------------------
  705|      0|            meshId = findItr->second.mMeshId;
  706|      0|            findItr = mControllerLibrary.find(meshId);
  707|      0|        }
  708|       |
  709|      1|        it.second.mMeshId = meshId;
  710|      1|    }
  711|     16|}
_ZN6Assimp13ColladaParser25PostProcessRootAnimationsEv:
  715|     16|void ColladaParser::PostProcessRootAnimations() {
  716|     16|    if (mAnimationClipLibrary.empty()) {
  ------------------
  |  Branch (716:9): [True: 16, False: 0]
  ------------------
  717|     16|        mAnims.CombineSingleChannelAnimations();
  718|     16|        return;
  719|     16|    }
  720|       |
  721|      0|    Animation temp;
  722|      0|    for (auto &it : mAnimationClipLibrary) {
  ------------------
  |  Branch (722:19): [True: 0, False: 0]
  ------------------
  723|      0|        std::string clipName = it.first;
  724|       |
  725|      0|        auto *clip = new Animation();
  726|      0|        clip->mName = clipName;
  727|       |
  728|      0|        temp.mSubAnims.push_back(clip);
  729|       |
  730|      0|        for (const std::string &animationID : it.second) {
  ------------------
  |  Branch (730:45): [True: 0, False: 0]
  ------------------
  731|      0|            auto animation = mAnimationLibrary.find(animationID);
  732|       |
  733|      0|            if (animation != mAnimationLibrary.end()) {
  ------------------
  |  Branch (733:17): [True: 0, False: 0]
  ------------------
  734|      0|                Animation *pSourceAnimation = animation->second;
  735|      0|                pSourceAnimation->CollectChannelsRecursively(clip->mChannels);
  736|      0|            }
  737|      0|        }
  738|      0|    }
  739|       |
  740|      0|    mAnims = temp;
  741|       |
  742|       |    // Ensure no double deletes.
  743|      0|    temp.mSubAnims.clear();
  744|      0|}
_ZN6Assimp13ColladaParser20ReadAnimationLibraryERN4pugi8xml_nodeE:
  748|      4|void ColladaParser::ReadAnimationLibrary(XmlNode &node) {
  749|      4|    if (node.empty()) {
  ------------------
  |  Branch (749:9): [True: 0, False: 4]
  ------------------
  750|      0|        return;
  751|      0|    }
  752|       |
  753|    526|    for (XmlNode &currentNode : node.children()) {
  ------------------
  |  Branch (753:31): [True: 526, False: 4]
  ------------------
  754|    526|        const std::string &currentName = currentNode.name();
  755|    526|        if (currentName == "animation") {
  ------------------
  |  Branch (755:13): [True: 526, False: 0]
  ------------------
  756|    526|            ReadAnimation(currentNode, &mAnims);
  757|    526|        }
  758|    526|    }
  759|      4|}
_ZN6Assimp13ColladaParser13ReadAnimationERN4pugi8xml_nodeEPNS_7Collada9AnimationE:
  763|    526|void ColladaParser::ReadAnimation(XmlNode &node, Collada::Animation *pParent) {
  764|    526|    if (node.empty()) {
  ------------------
  |  Branch (764:9): [True: 0, False: 526]
  ------------------
  765|      0|        return;
  766|      0|    }
  767|       |
  768|       |    // an <animation> element may be a container for grouping sub-elements or an animation channel
  769|       |    // this is the channel collection by ID, in case it has channels
  770|    526|    using ChannelMap = std::map<std::string, AnimationChannel>;
  771|    526|    ChannelMap channels;
  772|       |    // this is the anim container in case we're a container
  773|    526|    Animation *anim = nullptr;
  774|       |
  775|       |    // optional name given as an attribute
  776|    526|    std::string animName;
  777|    526|    if (!XmlParser::getStdStrAttribute(node, "name", animName)) {
  ------------------
  |  Branch (777:9): [True: 398, False: 128]
  ------------------
  778|    398|        animName = "animation";
  779|    398|    }
  780|       |
  781|    526|    std::string animID;
  782|    526|    pugi::xml_attribute idAttr = node.attribute("id");
  783|    526|    if (idAttr) {
  ------------------
  |  Branch (783:9): [True: 142, False: 384]
  ------------------
  784|    142|        animID = idAttr.as_string();
  785|    142|    }
  786|       |
  787|  1.98k|    for (XmlNode &currentNode : node.children()) {
  ------------------
  |  Branch (787:31): [True: 1.98k, False: 526]
  ------------------
  788|  1.98k|        const std::string &currentName = currentNode.name();
  789|  1.98k|        if (currentName == "animation") {
  ------------------
  |  Branch (789:13): [True: 0, False: 1.98k]
  ------------------
  790|      0|            if (!anim) {
  ------------------
  |  Branch (790:17): [True: 0, False: 0]
  ------------------
  791|      0|                anim = new Animation;
  792|      0|                anim->mName = animName;
  793|      0|                pParent->mSubAnims.push_back(anim);
  794|      0|            }
  795|       |
  796|       |            // recurse into the sub-element
  797|      0|            ReadAnimation(currentNode, anim);
  798|  1.98k|        } else if (currentName == "source") {
  ------------------
  |  Branch (798:20): [True: 1.19k, False: 794]
  ------------------
  799|  1.19k|            ReadSource(currentNode);
  800|  1.19k|        } else if (currentName == "sampler") {
  ------------------
  |  Branch (800:20): [True: 397, False: 397]
  ------------------
  801|    397|            std::string id;
  802|    397|            if (XmlParser::getStdStrAttribute(currentNode, "id", id)) {
  ------------------
  |  Branch (802:17): [True: 397, False: 0]
  ------------------
  803|       |                // have it read into a channel
  804|    397|                auto newChannel = channels.insert(std::make_pair(id, AnimationChannel())).first;
  805|    397|                ReadAnimationSampler(currentNode, newChannel->second);
  806|    397|            }
  807|    397|        } else if (currentName == "channel") {
  ------------------
  |  Branch (807:20): [True: 397, False: 0]
  ------------------
  808|    397|            std::string source_name, target;
  809|    397|            XmlParser::getStdStrAttribute(currentNode, "source", source_name);
  810|    397|            XmlParser::getStdStrAttribute(currentNode, "target", target);
  811|    397|            if (source_name[0] == '#') {
  ------------------
  |  Branch (811:17): [True: 397, False: 0]
  ------------------
  812|    397|                source_name = source_name.substr(1, source_name.size() - 1);
  813|    397|            }
  814|    397|            auto cit = channels.find(source_name);
  815|    397|            if (cit != channels.end()) {
  ------------------
  |  Branch (815:17): [True: 397, False: 0]
  ------------------
  816|    397|                cit->second.mTarget = target;
  817|    397|            }
  818|    397|        }
  819|  1.98k|    }
  820|       |
  821|       |    // it turned out to have channels - add them
  822|    526|    if (!channels.empty()) {
  ------------------
  |  Branch (822:9): [True: 397, False: 129]
  ------------------
  823|    397|        if (nullptr == anim) {
  ------------------
  |  Branch (823:13): [True: 397, False: 0]
  ------------------
  824|    397|            anim = new Animation;
  825|    397|            anim->mName = animName;
  826|    397|            pParent->mSubAnims.push_back(anim);
  827|    397|        }
  828|       |
  829|    397|        for (const auto &channel : channels) {
  ------------------
  |  Branch (829:34): [True: 397, False: 397]
  ------------------
  830|    397|            anim->mChannels.push_back(channel.second);
  831|    397|        }
  832|       |
  833|    397|        if (idAttr) {
  ------------------
  |  Branch (833:13): [True: 13, False: 384]
  ------------------
  834|     13|            mAnimationLibrary[animID] = anim;
  835|     13|        }
  836|    397|    }
  837|    526|}
_ZN6Assimp13ColladaParser21ReadControllerLibraryERN4pugi8xml_nodeE:
  841|      3|void ColladaParser::ReadControllerLibrary(XmlNode &node) {
  842|      3|    if (node.empty()) {
  ------------------
  |  Branch (842:9): [True: 0, False: 3]
  ------------------
  843|      0|        return;
  844|      0|    }
  845|       |
  846|      3|    for (XmlNode &currentNode : node.children()) {
  ------------------
  |  Branch (846:31): [True: 2, False: 3]
  ------------------
  847|      2|        const std::string &currentName = currentNode.name();
  848|      2|        if (currentName != "controller") {
  ------------------
  |  Branch (848:13): [True: 0, False: 2]
  ------------------
  849|      0|            continue;
  850|      0|        }
  851|      2|        if (std::string id; XmlParser::getStdStrAttribute(currentNode, "id", id)) {
  ------------------
  |  Branch (851:29): [True: 2, False: 0]
  ------------------
  852|      2|            mControllerLibrary[id] = Controller();
  853|      2|            ReadController(currentNode, mControllerLibrary[id]);
  854|      2|        }
  855|      2|    }
  856|      3|}
_ZN6Assimp13ColladaParser14ReadControllerERN4pugi8xml_nodeERNS_7Collada10ControllerE:
  860|      2|void ColladaParser::ReadController(XmlNode &node, Collada::Controller &controller) {
  861|       |    // initial values
  862|      2|    controller.mType = Skin;
  863|      2|    controller.mMethod = Normalized;
  864|       |
  865|      2|    XmlNodeIterator xmlIt(node, XmlNodeIterator::PreOrderMode);
  866|      2|    XmlNode currentNode;
  867|     52|    while (xmlIt.getNext(currentNode)) {
  ------------------
  |  Branch (867:12): [True: 50, False: 2]
  ------------------
  868|     50|        if (const std::string &currentName = currentNode.name(); currentName == "morph") {
  ------------------
  |  Branch (868:66): [True: 0, False: 50]
  ------------------
  869|      0|            controller.mType = Morph;
  870|      0|            std::string id = currentNode.attribute("source").as_string();
  871|      0|            controller.mMeshId = id.substr(1, id.size() - 1);
  872|      0|            if (const int methodIndex = currentNode.attribute("method").as_int(); methodIndex > 0) {
  ------------------
  |  Branch (872:83): [True: 0, False: 0]
  ------------------
  873|      0|                std::string method;
  874|      0|                XmlParser::getValueAsString(currentNode, method);
  875|       |
  876|      0|                if (method == "RELATIVE") {
  ------------------
  |  Branch (876:21): [True: 0, False: 0]
  ------------------
  877|      0|                    controller.mMethod = Relative;
  878|      0|                }
  879|      0|            }
  880|     50|        } else if (currentName == "skin") {
  ------------------
  |  Branch (880:20): [True: 2, False: 48]
  ------------------
  881|      2|            if (std::string id; XmlParser::getStdStrAttribute(currentNode, "source", id)) {
  ------------------
  |  Branch (881:33): [True: 2, False: 0]
  ------------------
  882|      2|                controller.mMeshId = id.substr(1, id.size() - 1);
  883|      2|            }
  884|     48|        } else if (currentName == "bind_shape_matrix") {
  ------------------
  |  Branch (884:20): [True: 2, False: 46]
  ------------------
  885|      2|            std::string v;
  886|      2|            XmlParser::getValueAsString(currentNode, v);
  887|      2|            const char *content = v.c_str();
  888|      2|            const char *end = content + v.size();
  889|     32|            for (auto & a : controller.mBindShapeMatrix) {
  ------------------
  |  Branch (889:27): [True: 32, False: 2]
  ------------------
  890|     32|                SkipSpacesAndLineEnd(&content, end);
  891|       |                // read a number
  892|     32|                content = fast_atoreal_move(content, a);
  893|       |                // skip whitespace after it
  894|     32|                SkipSpacesAndLineEnd(&content, end);
  895|     32|            }
  896|     46|        } else if (currentName == "source") {
  ------------------
  |  Branch (896:20): [True: 6, False: 40]
  ------------------
  897|      6|            ReadSource(currentNode);
  898|     40|        } else if (currentName == "joints") {
  ------------------
  |  Branch (898:20): [True: 2, False: 38]
  ------------------
  899|      2|            ReadControllerJoints(currentNode, controller);
  900|     38|        } else if (currentName == "vertex_weights") {
  ------------------
  |  Branch (900:20): [True: 2, False: 36]
  ------------------
  901|      2|            ReadControllerWeights(currentNode, controller);
  902|     36|        } else if (currentName == "targets") {
  ------------------
  |  Branch (902:20): [True: 0, False: 36]
  ------------------
  903|      0|            for (XmlNode currentChildNode = node.first_child(); currentNode; currentNode = currentNode.next_sibling()) {
  ------------------
  |  Branch (903:65): [True: 0, False: 0]
  ------------------
  904|      0|                const std::string &currentChildName = currentChildNode.name();
  905|      0|                if (currentChildName == "input") {
  ------------------
  |  Branch (905:21): [True: 0, False: 0]
  ------------------
  906|      0|                    const char *semantics = currentChildNode.attribute("semantic").as_string();
  907|      0|                    const char *source = currentChildNode.attribute("source").as_string();
  908|      0|                    if (strcmp(semantics, "MORPH_TARGET") == 0) {
  ------------------
  |  Branch (908:25): [True: 0, False: 0]
  ------------------
  909|      0|                        controller.mMorphTarget = source + 1;
  910|      0|                    } else if (strcmp(semantics, "MORPH_WEIGHT") == 0) {
  ------------------
  |  Branch (910:32): [True: 0, False: 0]
  ------------------
  911|      0|                        controller.mMorphWeight = source + 1;
  912|      0|                    }
  913|      0|                }
  914|      0|            }
  915|      0|        }
  916|     50|    }
  917|      2|}
_ZN6Assimp13ColladaParser16ReadImageLibraryERKN4pugi8xml_nodeE:
  921|     20|void ColladaParser::ReadImageLibrary(const XmlNode &node) {
  922|     20|    for (XmlNode &currentNode : node.children()) {
  ------------------
  |  Branch (922:31): [True: 18, False: 20]
  ------------------
  923|     18|        const std::string &currentName = currentNode.name();
  924|     18|        if (currentName == "image") {
  ------------------
  |  Branch (924:13): [True: 18, False: 0]
  ------------------
  925|     18|            if (std::basic_string<char> id; XmlParser::getStdStrAttribute(currentNode, "id", id)) {
  ------------------
  |  Branch (925:45): [True: 18, False: 0]
  ------------------
  926|     18|                mImageLibrary[id] = Image();
  927|       |                // read on from there
  928|     18|                ReadImage(currentNode, mImageLibrary[id]);
  929|     18|            }
  930|     18|        }
  931|     18|    }
  932|     20|}
_ZNK6Assimp13ColladaParser9ReadImageERKN4pugi8xml_nodeERNS_7Collada5ImageE:
  936|     18|void ColladaParser::ReadImage(const XmlNode &node, Collada::Image &pImage) const {
  937|     18|    for (XmlNode &currentNode : node.children()) {
  ------------------
  |  Branch (937:31): [True: 18, False: 18]
  ------------------
  938|     18|        const std::string currentName = currentNode.name();
  939|     18|        if (currentName == "image") {
  ------------------
  |  Branch (939:13): [True: 0, False: 18]
  ------------------
  940|       |            // Ignore
  941|      0|            continue;
  942|     18|        } else if (currentName == "init_from") {
  ------------------
  |  Branch (942:20): [True: 18, False: 0]
  ------------------
  943|     18|            if (mFormat == FV_1_4_n) {
  ------------------
  |  Branch (943:17): [True: 18, False: 0]
  ------------------
  944|       |                // FIX: C4D exporter writes empty <init_from/> tags
  945|     18|                if (!currentNode.empty()) {
  ------------------
  |  Branch (945:21): [True: 18, False: 0]
  ------------------
  946|       |                    // element content is filename - hopefully
  947|     18|                    const char *sz = currentNode.text().as_string();
  948|     18|                    if (nullptr != sz) {
  ------------------
  |  Branch (948:25): [True: 18, False: 0]
  ------------------
  949|     18|                        aiString filepath(sz);
  950|     18|                        UriDecodePath(filepath);
  951|     18|                        pImage.mFileName = filepath.C_Str();
  952|     18|                    }
  953|     18|                }
  954|     18|                if (!pImage.mFileName.length()) {
  ------------------
  |  Branch (954:21): [True: 0, False: 18]
  ------------------
  955|      0|                    pImage.mFileName = "unknown_texture";
  956|      0|                }
  957|     18|            } else if (mFormat == FV_1_5_n) {
  ------------------
  |  Branch (957:24): [True: 0, False: 0]
  ------------------
  958|      0|                std::string value;
  959|      0|                XmlNode refChild = currentNode.child("ref");
  960|      0|                XmlNode hexChild = currentNode.child("hex");
  961|      0|                if (refChild) {
  ------------------
  |  Branch (961:21): [True: 0, False: 0]
  ------------------
  962|       |                    // element content is filename - hopefully
  963|      0|                    if (XmlParser::getValueAsString(refChild, value)) {
  ------------------
  |  Branch (963:25): [True: 0, False: 0]
  ------------------
  964|      0|                        aiString filepath(value);
  965|      0|                        UriDecodePath(filepath);
  966|      0|                        pImage.mFileName = filepath.C_Str();
  967|      0|                    }
  968|      0|                } else if (hexChild && !pImage.mFileName.length()) {
  ------------------
  |  Branch (968:28): [True: 0, False: 0]
  |  Branch (968:40): [True: 0, False: 0]
  ------------------
  969|       |                    // embedded image. get format
  970|      0|                    pImage.mEmbeddedFormat = hexChild.attribute("format").as_string();
  971|      0|                    if (pImage.mEmbeddedFormat.empty()) {
  ------------------
  |  Branch (971:25): [True: 0, False: 0]
  ------------------
  972|      0|                        ASSIMP_LOG_WARN("Collada: Unknown image file format");
  973|      0|                    }
  974|       |
  975|      0|                    XmlParser::getValueAsString(hexChild, value);
  976|      0|                    const char *data = value.c_str();
  977|       |                    // hexadecimal-encoded binary octets. First of all, find the
  978|       |                    // required buffer size to reserve enough storage.
  979|      0|                    const char *cur = data;
  980|      0|                    while (!IsSpaceOrNewLine(*cur)) {
  ------------------
  |  Branch (980:28): [True: 0, False: 0]
  ------------------
  981|      0|                        ++cur;
  982|      0|                    }
  983|       |
  984|      0|                    const unsigned int size = (unsigned int)(cur - data) * 2;
  985|      0|                    pImage.mImageData.resize(size);
  986|      0|                    for (unsigned int i = 0; i < size; ++i) {
  ------------------
  |  Branch (986:46): [True: 0, False: 0]
  ------------------
  987|      0|                        pImage.mImageData[i] = HexOctetToDecimal(data + (i << 1));
  988|      0|                    }
  989|      0|                }
  990|      0|            }
  991|     18|        }
  992|     18|    }
  993|     18|}
_ZN6Assimp13ColladaParser19ReadMaterialLibraryERN4pugi8xml_nodeE:
  997|     26|void ColladaParser::ReadMaterialLibrary(XmlNode &node) {
  998|     26|    std::map<std::string, int> names;
  999|     36|    for (const XmlNode &currentNode : node.children()) {
  ------------------
  |  Branch (999:37): [True: 36, False: 26]
  ------------------
 1000|     36|        std::string id = currentNode.attribute("id").as_string();
 1001|     36|        std::string name = currentNode.attribute("name").as_string();
 1002|     36|        mMaterialLibrary[id] = Material();
 1003|       |
 1004|     36|        if (!name.empty()) {
  ------------------
  |  Branch (1004:13): [True: 36, False: 0]
  ------------------
 1005|     36|            auto it = names.find(name);
 1006|     36|            if (it != names.end()) {
  ------------------
  |  Branch (1006:17): [True: 0, False: 36]
  ------------------
 1007|      0|                std::ostringstream strStream;
 1008|      0|                strStream << ++it->second;
 1009|      0|                name.append(" " + strStream.str());
 1010|     36|            } else {
 1011|     36|                names[name] = 0;
 1012|     36|            }
 1013|       |
 1014|     36|            mMaterialLibrary[id].mName = name;
 1015|     36|        }
 1016|       |
 1017|     36|        ReadMaterial(currentNode, mMaterialLibrary[id]);
 1018|     36|    }
 1019|     26|}
_ZN6Assimp13ColladaParser16ReadLightLibraryERN4pugi8xml_nodeE:
 1023|     10|void ColladaParser::ReadLightLibrary(XmlNode &node) {
 1024|     15|    for (XmlNode &currentNode : node.children()) {
  ------------------
  |  Branch (1024:31): [True: 15, False: 10]
  ------------------
 1025|     15|        const std::string &currentName = currentNode.name();
 1026|     15|        if (currentName == "light") {
  ------------------
  |  Branch (1026:13): [True: 15, False: 0]
  ------------------
 1027|     15|            std::string id;
 1028|     15|            if (XmlParser::getStdStrAttribute(currentNode, "id", id)) {
  ------------------
  |  Branch (1028:17): [True: 15, False: 0]
  ------------------
 1029|     15|                ReadLight(currentNode, mLightLibrary[id] = Light());
 1030|     15|            }
 1031|     15|        }
 1032|     15|    }
 1033|     10|}
_ZN6Assimp13ColladaParser17ReadCameraLibraryERN4pugi8xml_nodeE:
 1037|      9|void ColladaParser::ReadCameraLibrary(XmlNode &node) {
 1038|     10|    for (XmlNode &currentNode : node.children()) {
  ------------------
  |  Branch (1038:31): [True: 10, False: 9]
  ------------------
 1039|     10|        const std::string &currentName = currentNode.name();
 1040|     10|        if (currentName == "camera") {
  ------------------
  |  Branch (1040:13): [True: 10, False: 0]
  ------------------
 1041|     10|            std::string id;
 1042|     10|            if (!XmlParser::getStdStrAttribute(currentNode, "id", id)) {
  ------------------
  |  Branch (1042:17): [True: 0, False: 10]
  ------------------
 1043|      0|                continue;
 1044|      0|            }
 1045|       |
 1046|       |            // create an entry and store it in the library under its ID
 1047|     10|            Camera &cam = mCameraLibrary[id];
 1048|     10|            std::string name;
 1049|     10|            if (!XmlParser::getStdStrAttribute(currentNode, "name", name)) {
  ------------------
  |  Branch (1049:17): [True: 0, False: 10]
  ------------------
 1050|      0|                continue;
 1051|      0|            }
 1052|     10|            if (!name.empty()) {
  ------------------
  |  Branch (1052:17): [True: 10, False: 0]
  ------------------
 1053|     10|                cam.mName = name;
 1054|     10|            }
 1055|     10|            ReadCamera(currentNode, cam);
 1056|     10|        }
 1057|     10|    }
 1058|      9|}
_ZN6Assimp13ColladaParser17ReadEffectLibraryERN4pugi8xml_nodeE:
 1062|     26|void ColladaParser::ReadEffectLibrary(XmlNode &node) {
 1063|     26|    if (node.empty()) {
  ------------------
  |  Branch (1063:9): [True: 0, False: 26]
  ------------------
 1064|      0|        return;
 1065|      0|    }
 1066|       |
 1067|     36|    for (XmlNode &currentNode : node.children()) {
  ------------------
  |  Branch (1067:31): [True: 36, False: 26]
  ------------------
 1068|     36|        const std::string &currentName = currentNode.name();
 1069|     36|        if (currentName == "effect") {
  ------------------
  |  Branch (1069:13): [True: 36, False: 0]
  ------------------
 1070|       |            // read ID. Do I have to repeat my ranting about "optional" attributes?
 1071|     36|            std::string id;
 1072|     36|            XmlParser::getStdStrAttribute(currentNode, "id", id);
 1073|       |
 1074|       |            // create an entry and store it in the library under its ID
 1075|     36|            mEffectLibrary[id] = Effect();
 1076|       |
 1077|       |            // read on from there
 1078|     36|            ReadEffect(currentNode, mEffectLibrary[id]);
 1079|     36|        }
 1080|     36|    }
 1081|     26|}
_ZN6Assimp13ColladaParser10ReadEffectERN4pugi8xml_nodeERNS_7Collada6EffectE:
 1085|     36|void ColladaParser::ReadEffect(XmlNode &node, Collada::Effect &pEffect) {
 1086|     36|    for (XmlNode &currentNode : node.children()) {
  ------------------
  |  Branch (1086:31): [True: 36, False: 36]
  ------------------
 1087|     36|        const std::string &currentName = currentNode.name();
 1088|     36|        if (currentName == "profile_COMMON") {
  ------------------
  |  Branch (1088:13): [True: 36, False: 0]
  ------------------
 1089|     36|            ReadEffectProfileCommon(currentNode, pEffect);
 1090|     36|        }
 1091|     36|    }
 1092|     36|}
_ZN6Assimp13ColladaParser23ReadEffectProfileCommonERN4pugi8xml_nodeERNS_7Collada6EffectE:
 1096|     36|void ColladaParser::ReadEffectProfileCommon(XmlNode &node, Collada::Effect &pEffect) {
 1097|     36|    XmlNodeIterator xmlIt(node, XmlNodeIterator::PreOrderMode);
 1098|     36|    XmlNode currentNode;
 1099|    841|    while (xmlIt.getNext(currentNode)) {
  ------------------
  |  Branch (1099:12): [True: 805, False: 36]
  ------------------
 1100|    805|        const std::string currentName = currentNode.name();
 1101|    805|        if (currentName == "newparam") {
  ------------------
  |  Branch (1101:13): [True: 20, False: 785]
  ------------------
 1102|       |            // save ID
 1103|     20|            std::string sid = currentNode.attribute("sid").as_string();
 1104|     20|            pEffect.mParams[sid] = EffectParam();
 1105|     20|            ReadEffectParam(currentNode, pEffect.mParams[sid]);
 1106|    785|        } else if (currentName == "technique" || currentName == "extra") {
  ------------------
  |  Branch (1106:20): [True: 48, False: 737]
  |  Branch (1106:50): [True: 10, False: 727]
  ------------------
 1107|       |            // just syntactic sugar
 1108|    727|        } else if (mFormat == FV_1_4_n && currentName == "image") {
  ------------------
  |  Branch (1108:20): [True: 727, False: 0]
  |  Branch (1108:43): [True: 0, False: 727]
  ------------------
 1109|       |            // read ID. Another entry which is "optional" by design but obligatory in reality
 1110|      0|            std::string id = currentNode.attribute("id").as_string();
 1111|       |
 1112|       |            // create an entry and store it in the library under its ID
 1113|      0|            mImageLibrary[id] = Image();
 1114|       |
 1115|       |            // read on from there
 1116|      0|            ReadImage(currentNode, mImageLibrary[id]);
 1117|    727|        } else if (currentName == "phong")
  ------------------
  |  Branch (1117:20): [True: 22, False: 705]
  ------------------
 1118|     22|            pEffect.mShadeType = Shade_Phong;
 1119|    705|        else if (currentName == "constant")
  ------------------
  |  Branch (1119:18): [True: 0, False: 705]
  ------------------
 1120|      0|            pEffect.mShadeType = Shade_Constant;
 1121|    705|        else if (currentName == "lambert")
  ------------------
  |  Branch (1121:18): [True: 6, False: 699]
  ------------------
 1122|      6|            pEffect.mShadeType = Shade_Lambert;
 1123|    699|        else if (currentName == "blinn")
  ------------------
  |  Branch (1123:18): [True: 8, False: 691]
  ------------------
 1124|      8|            pEffect.mShadeType = Shade_Blinn;
 1125|       |
 1126|       |        /* Color + texture properties */
 1127|    691|        else if (currentName == "emission")
  ------------------
  |  Branch (1127:18): [True: 47, False: 644]
  ------------------
 1128|     47|            ReadEffectColor(currentNode, pEffect.mEmissive, pEffect.mTexEmissive);
 1129|    644|        else if (currentName == "ambient")
  ------------------
  |  Branch (1129:18): [True: 30, False: 614]
  ------------------
 1130|     30|            ReadEffectColor(currentNode, pEffect.mAmbient, pEffect.mTexAmbient);
 1131|    614|        else if (currentName == "diffuse")
  ------------------
  |  Branch (1131:18): [True: 36, False: 578]
  ------------------
 1132|     36|            ReadEffectColor(currentNode, pEffect.mDiffuse, pEffect.mTexDiffuse);
 1133|    578|        else if (currentName == "specular")
  ------------------
  |  Branch (1133:18): [True: 34, False: 544]
  ------------------
 1134|     34|            ReadEffectColor(currentNode, pEffect.mSpecular, pEffect.mTexSpecular);
 1135|    544|        else if (currentName == "reflective") {
  ------------------
  |  Branch (1135:18): [True: 30, False: 514]
  ------------------
 1136|     30|            ReadEffectColor(currentNode, pEffect.mReflective, pEffect.mTexReflective);
 1137|    514|        } else if (currentName == "transparent") {
  ------------------
  |  Branch (1137:20): [True: 28, False: 486]
  ------------------
 1138|     28|            pEffect.mHasTransparency = true;
 1139|     28|            const char *opaque = currentNode.attribute("opaque").as_string();
 1140|       |            //const char *opaque = mReader->getAttributeValueSafe("opaque");
 1141|       |
 1142|     28|            if (::strcmp(opaque, "RGB_ZERO") == 0 || ::strcmp(opaque, "RGB_ONE") == 0) {
  ------------------
  |  Branch (1142:17): [True: 0, False: 28]
  |  Branch (1142:54): [True: 0, False: 28]
  ------------------
 1143|      0|                pEffect.mRGBTransparency = true;
 1144|      0|            }
 1145|       |
 1146|       |            // In RGB_ZERO mode, the transparency is interpreted in reverse, go figure...
 1147|     28|            if (::strcmp(opaque, "RGB_ZERO") == 0 || ::strcmp(opaque, "A_ZERO") == 0) {
  ------------------
  |  Branch (1147:17): [True: 0, False: 28]
  |  Branch (1147:54): [True: 0, False: 28]
  ------------------
 1148|      0|                pEffect.mInvertTransparency = true;
 1149|      0|            }
 1150|       |
 1151|     28|            ReadEffectColor(currentNode, pEffect.mTransparent, pEffect.mTexTransparent);
 1152|    486|        } else if (currentName == "shininess")
  ------------------
  |  Branch (1152:20): [True: 30, False: 456]
  ------------------
 1153|     30|            ReadEffectFloat(currentNode, pEffect.mShininess);
 1154|    456|        else if (currentName == "reflectivity")
  ------------------
  |  Branch (1154:18): [True: 28, False: 428]
  ------------------
 1155|     28|            ReadEffectFloat(currentNode, pEffect.mReflectivity);
 1156|       |
 1157|       |        /* Single scalar properties */
 1158|    428|        else if (currentName == "transparency")
  ------------------
  |  Branch (1158:18): [True: 28, False: 400]
  ------------------
 1159|     28|            ReadEffectFloat(currentNode, pEffect.mTransparency);
 1160|    400|        else if (currentName == "index_of_refraction")
  ------------------
  |  Branch (1160:18): [True: 13, False: 387]
  ------------------
 1161|     13|            ReadEffectFloat(currentNode, pEffect.mRefractIndex);
 1162|       |
 1163|       |        // GOOGLEEARTH/OKINO extensions
 1164|       |        // -------------------------------------------------------
 1165|    387|        else if (currentName == "double_sided")
  ------------------
  |  Branch (1165:18): [True: 2, False: 385]
  ------------------
 1166|      2|            XmlParser::getValueAsBool(currentNode, pEffect.mDoubleSided);
 1167|       |
 1168|       |        // FCOLLADA extensions
 1169|       |        // -------------------------------------------------------
 1170|    385|        else if (currentName == "bump") {
  ------------------
  |  Branch (1170:18): [True: 0, False: 385]
  ------------------
 1171|      0|            aiColor4D dummy;
 1172|      0|            ReadEffectColor(currentNode, dummy, pEffect.mTexBump);
 1173|      0|        }
 1174|       |
 1175|       |        // MAX3D extensions
 1176|       |        // -------------------------------------------------------
 1177|    385|        else if (currentName == "wireframe") {
  ------------------
  |  Branch (1177:18): [True: 0, False: 385]
  ------------------
 1178|      0|            XmlParser::getValueAsBool(currentNode, pEffect.mWireframe);
 1179|    385|        } else if (currentName == "faceted") {
  ------------------
  |  Branch (1179:20): [True: 0, False: 385]
  ------------------
 1180|      0|            XmlParser::getValueAsBool(currentNode, pEffect.mFaceted);
 1181|      0|        }
 1182|    805|    }
 1183|     36|}
_ZN6Assimp13ColladaParser21ReadSamplerPropertiesERN4pugi8xml_nodeERNS_7Collada7SamplerE:
 1187|      8|void ColladaParser::ReadSamplerProperties(XmlNode &node, Sampler &out) {
 1188|      8|    if (node.empty()) {
  ------------------
  |  Branch (1188:9): [True: 0, False: 8]
  ------------------
 1189|      0|        return;
 1190|      0|    }
 1191|       |
 1192|      8|    XmlNodeIterator xmlIt(node, XmlNodeIterator::PreOrderMode);
 1193|      8|    XmlNode currentNode;
 1194|     32|    while (xmlIt.getNext(currentNode)) {
  ------------------
  |  Branch (1194:12): [True: 24, False: 8]
  ------------------
 1195|     24|        const std::string &currentName = currentNode.name();
 1196|       |        // MAYA extensions
 1197|       |        // -------------------------------------------------------
 1198|     24|        if (currentName == "wrapU") {
  ------------------
  |  Branch (1198:13): [True: 8, False: 16]
  ------------------
 1199|      8|            XmlParser::getValueAsBool(currentNode, out.mWrapU);
 1200|     16|        } else if (currentName == "wrapV") {
  ------------------
  |  Branch (1200:20): [True: 8, False: 8]
  ------------------
 1201|      8|            XmlParser::getValueAsBool(currentNode, out.mWrapV);
 1202|      8|        } else if (currentName == "mirrorU") {
  ------------------
  |  Branch (1202:20): [True: 0, False: 8]
  ------------------
 1203|      0|            XmlParser::getValueAsBool(currentNode, out.mMirrorU);
 1204|      8|        } else if (currentName == "mirrorV") {
  ------------------
  |  Branch (1204:20): [True: 0, False: 8]
  ------------------
 1205|      0|            XmlParser::getValueAsBool(currentNode, out.mMirrorV);
 1206|      8|        } else if (currentName == "repeatU") {
  ------------------
  |  Branch (1206:20): [True: 0, False: 8]
  ------------------
 1207|      0|            XmlParser::getValueAsReal(currentNode, out.mTransform.mScaling.x);
 1208|      8|        } else if (currentName == "repeatV") {
  ------------------
  |  Branch (1208:20): [True: 0, False: 8]
  ------------------
 1209|      0|            XmlParser::getValueAsReal(currentNode, out.mTransform.mScaling.y);
 1210|      8|        } else if (currentName == "offsetU") {
  ------------------
  |  Branch (1210:20): [True: 0, False: 8]
  ------------------
 1211|      0|            XmlParser::getValueAsReal(currentNode, out.mTransform.mTranslation.x);
 1212|      8|        } else if (currentName == "offsetV") {
  ------------------
  |  Branch (1212:20): [True: 0, False: 8]
  ------------------
 1213|      0|            XmlParser::getValueAsReal(currentNode, out.mTransform.mTranslation.y);
 1214|      8|        } else if (currentName == "rotateUV") {
  ------------------
  |  Branch (1214:20): [True: 0, False: 8]
  ------------------
 1215|      0|            XmlParser::getValueAsReal(currentNode, out.mTransform.mRotation);
 1216|      8|        } else if (currentName == "blend_mode") {
  ------------------
  |  Branch (1216:20): [True: 8, False: 0]
  ------------------
 1217|      8|            std::string v;
 1218|      8|            XmlParser::getValueAsString(currentNode, v);
 1219|      8|            const char *sz = v.c_str();
 1220|       |            // http://www.feelingsoftware.com/content/view/55/72/lang,en/
 1221|       |            // NONE, OVER, IN, OUT, ADD, SUBTRACT, MULTIPLY, DIFFERENCE, LIGHTEN, DARKEN, SATURATE, DESATURATE and ILLUMINATE
 1222|      8|            if (0 == ASSIMP_strincmp(sz, "ADD", 3))
  ------------------
  |  Branch (1222:17): [True: 8, False: 0]
  ------------------
 1223|      8|                out.mOp = aiTextureOp_Add;
 1224|      0|            else if (0 == ASSIMP_strincmp(sz, "SUBTRACT", 8))
  ------------------
  |  Branch (1224:22): [True: 0, False: 0]
  ------------------
 1225|      0|                out.mOp = aiTextureOp_Subtract;
 1226|      0|            else if (0 == ASSIMP_strincmp(sz, "MULTIPLY", 8))
  ------------------
  |  Branch (1226:22): [True: 0, False: 0]
  ------------------
 1227|      0|                out.mOp = aiTextureOp_Multiply;
 1228|      0|            else {
 1229|      0|                ASSIMP_LOG_WARN("Collada: Unsupported MAYA texture blend mode");
 1230|      0|            }
 1231|      8|        }
 1232|       |        // OKINO extensions
 1233|       |        // -------------------------------------------------------
 1234|      0|        else if (currentName == "weighting") {
  ------------------
  |  Branch (1234:18): [True: 0, False: 0]
  ------------------
 1235|      0|            XmlParser::getValueAsReal(currentNode, out.mWeighting);
 1236|      0|        } else if (currentName == "mix_with_previous_layer") {
  ------------------
  |  Branch (1236:20): [True: 0, False: 0]
  ------------------
 1237|      0|            XmlParser::getValueAsReal(currentNode, out.mMixWithPrevious);
 1238|      0|        }
 1239|       |        // MAX3D extensions
 1240|       |        // -------------------------------------------------------
 1241|      0|        else if (currentName == "amount") {
  ------------------
  |  Branch (1241:18): [True: 0, False: 0]
  ------------------
 1242|      0|            XmlParser::getValueAsReal(currentNode, out.mWeighting);
 1243|      0|        }
 1244|     24|    }
 1245|      8|}
_ZN6Assimp13ColladaParser15ReadEffectColorERN4pugi8xml_nodeER9aiColor4tIfERNS_7Collada7SamplerE:
 1249|    205|void ColladaParser::ReadEffectColor(XmlNode &node, aiColor4D &pColor, Sampler &pSampler) {
 1250|    205|    if (node.empty()) {
  ------------------
  |  Branch (1250:9): [True: 0, False: 205]
  ------------------
 1251|      0|        return;
 1252|      0|    }
 1253|       |
 1254|    205|    XmlNodeIterator xmlIt(node, XmlNodeIterator::PreOrderMode);
 1255|    205|    XmlNode currentNode;
 1256|    517|    while (xmlIt.getNext(currentNode)) {
  ------------------
  |  Branch (1256:12): [True: 312, False: 205]
  ------------------
 1257|    312|        const std::string &currentName = currentNode.name();
 1258|    312|        if (currentName == "color") {
  ------------------
  |  Branch (1258:13): [True: 197, False: 115]
  ------------------
 1259|       |            // text content contains 4 floats
 1260|    197|            std::string v;
 1261|    197|            XmlParser::getValueAsString(currentNode, v);
 1262|    197|            const char *content = v.c_str();
 1263|    197|            const char *end = v.c_str() + v.size() + 1;
 1264|       |
 1265|    197|            content = fast_atoreal_move(content, pColor.r);
 1266|    197|            SkipSpacesAndLineEnd(&content, end);
 1267|       |
 1268|    197|            content = fast_atoreal_move(content, pColor.g);
 1269|    197|            SkipSpacesAndLineEnd(&content, end);
 1270|       |
 1271|    197|            content = fast_atoreal_move(content, pColor.b);
 1272|    197|            SkipSpacesAndLineEnd(&content, end);
 1273|       |
 1274|    197|            content = fast_atoreal_move(content, pColor.a);
 1275|    197|            SkipSpacesAndLineEnd(&content, end);
 1276|    197|        } else if (currentName == "texture") {
  ------------------
  |  Branch (1276:20): [True: 18, False: 97]
  ------------------
 1277|       |            // get name of source texture/sampler
 1278|     18|            XmlParser::getStdStrAttribute(currentNode, "texture", pSampler.mName);
 1279|       |
 1280|       |            // get name of UV source channel. Specification demands it to be there, but some exporters
 1281|       |            // don't write it. It will be the default UV channel in case it's missing.
 1282|     18|            XmlParser::getStdStrAttribute(currentNode, "texcoord", pSampler.mUVChannel);
 1283|       |
 1284|       |            // as we've read texture, the color needs to be 1,1,1,1
 1285|     18|            pColor = aiColor4D(1.f, 1.f, 1.f, 1.f);
 1286|     97|        } else if (currentName == "technique") {
  ------------------
  |  Branch (1286:20): [True: 8, False: 89]
  ------------------
 1287|      8|            std::string profile;
 1288|      8|            XmlParser::getStdStrAttribute(currentNode, "profile", profile);
 1289|       |
 1290|       |            // Some extensions are quite useful ... ReadSamplerProperties processes
 1291|       |            // several extensions in MAYA, OKINO and MAX3D profiles.
 1292|      8|            if (!::strcmp(profile.c_str(), "MAYA") || !::strcmp(profile.c_str(), "MAX3D") || !::strcmp(profile.c_str(), "OKINO")) {
  ------------------
  |  Branch (1292:17): [True: 8, False: 0]
  |  Branch (1292:55): [True: 0, False: 0]
  |  Branch (1292:94): [True: 0, False: 0]
  ------------------
 1293|       |                // get more information on this sampler
 1294|      8|                ReadSamplerProperties(currentNode, pSampler);
 1295|      8|            }
 1296|      8|        }
 1297|    312|    }
 1298|    205|}
_ZN6Assimp13ColladaParser15ReadEffectFloatERN4pugi8xml_nodeERf:
 1302|     99|void ColladaParser::ReadEffectFloat(XmlNode &node, ai_real &pReal) {
 1303|     99|    pReal = 0.f;
 1304|     99|    XmlNode floatNode = node.child("float");
 1305|     99|    if (floatNode.empty()) {
  ------------------
  |  Branch (1305:9): [True: 0, False: 99]
  ------------------
 1306|      0|        return;
 1307|      0|    }
 1308|     99|    XmlParser::getValueAsReal(floatNode, pReal);
 1309|     99|}
_ZN6Assimp13ColladaParser15ReadEffectParamERN4pugi8xml_nodeERNS_7Collada11EffectParamE:
 1313|     20|void ColladaParser::ReadEffectParam(XmlNode &node, Collada::EffectParam &pParam) {
 1314|     20|    if (node.empty()) {
  ------------------
  |  Branch (1314:9): [True: 0, False: 20]
  ------------------
 1315|      0|        return;
 1316|      0|    }
 1317|       |
 1318|     20|    for (XmlNode &currentNode : node.children()) {
  ------------------
  |  Branch (1318:31): [True: 20, False: 20]
  ------------------
 1319|     20|        const std::string &currentName = currentNode.name();
 1320|     20|        if (currentName == "surface") {
  ------------------
  |  Branch (1320:13): [True: 10, False: 10]
  ------------------
 1321|       |            // image ID given inside <init_from> tags
 1322|     10|            XmlNode initNode = currentNode.child("init_from");
 1323|     10|            if (initNode) {
  ------------------
  |  Branch (1323:17): [True: 10, False: 0]
  ------------------
 1324|     10|                std::string v;
 1325|     10|                XmlParser::getValueAsString(initNode, v);
 1326|     10|                pParam.mType = Param_Surface;
 1327|     10|                pParam.mReference = v.c_str();
 1328|     10|            }
 1329|     10|        } else if (currentName == "sampler2D" && (FV_1_4_n == mFormat || FV_1_3_n == mFormat)) {
  ------------------
  |  Branch (1329:20): [True: 10, False: 0]
  |  Branch (1329:51): [True: 10, False: 0]
  |  Branch (1329:74): [True: 0, False: 0]
  ------------------
 1330|       |            // surface ID is given inside <source> tags
 1331|     10|            XmlNode source = currentNode.child("source");
 1332|     10|            if (source) {
  ------------------
  |  Branch (1332:17): [True: 10, False: 0]
  ------------------
 1333|     10|                std::string v;
 1334|     10|                XmlParser::getValueAsString(source, v);
 1335|     10|                pParam.mType = Param_Sampler;
 1336|     10|                pParam.mReference = v.c_str();
 1337|     10|            }
 1338|     10|        } else if (currentName == "sampler2D") {
  ------------------
  |  Branch (1338:20): [True: 0, False: 0]
  ------------------
 1339|       |            // surface ID is given inside <instance_image> tags
 1340|      0|            XmlNode instance_image = currentNode.child("instance_image");
 1341|      0|            if (instance_image) {
  ------------------
  |  Branch (1341:17): [True: 0, False: 0]
  ------------------
 1342|      0|                std::string url;
 1343|      0|                XmlParser::getStdStrAttribute(instance_image, "url", url);
 1344|      0|                if (url[0] != '#') {
  ------------------
  |  Branch (1344:21): [True: 0, False: 0]
  ------------------
 1345|      0|                    throw DeadlyImportError("Unsupported URL format in instance_image");
 1346|      0|                }
 1347|      0|                pParam.mType = Param_Sampler;
 1348|      0|                pParam.mReference = url.c_str() + 1;
 1349|      0|            }
 1350|      0|        }
 1351|     20|    }
 1352|     20|}
_ZN6Assimp13ColladaParser19ReadGeometryLibraryERN4pugi8xml_nodeE:
 1356|     29|void ColladaParser::ReadGeometryLibrary(XmlNode &node) {
 1357|     29|    if (node.empty()) {
  ------------------
  |  Branch (1357:9): [True: 0, False: 29]
  ------------------
 1358|      0|        return;
 1359|      0|    }
 1360|    165|    for (XmlNode &currentNode : node.children()) {
  ------------------
  |  Branch (1360:31): [True: 165, False: 29]
  ------------------
 1361|    165|        const std::string &currentName = currentNode.name();
 1362|    165|        if (currentName == "geometry") {
  ------------------
  |  Branch (1362:13): [True: 165, False: 0]
  ------------------
 1363|       |            // read ID. Another entry which is "optional" by design but obligatory in reality
 1364|       |
 1365|    165|            std::string id;
 1366|    165|            XmlParser::getStdStrAttribute(currentNode, "id", id);
 1367|       |            // create a mesh and store it in the library under its (resolved) ID
 1368|       |            // Skip and warn if ID is not unique
 1369|    165|            if (mMeshLibrary.find(id) == mMeshLibrary.cend()) {
  ------------------
  |  Branch (1369:17): [True: 165, False: 0]
  ------------------
 1370|    165|                std::unique_ptr<Mesh> mesh(new Mesh(id));
 1371|       |
 1372|    165|                XmlParser::getStdStrAttribute(currentNode, "name", mesh->mName);
 1373|       |
 1374|       |                // read on from there
 1375|    165|                ReadGeometry(currentNode, *mesh);
 1376|       |                // Read successfully, add to library
 1377|    165|                mMeshLibrary.insert({ id, mesh.release() });
 1378|    165|            }
 1379|    165|        }
 1380|    165|    }
 1381|     29|}
_ZN6Assimp13ColladaParser12ReadGeometryERN4pugi8xml_nodeERNS_7Collada4MeshE:
 1385|    165|void ColladaParser::ReadGeometry(XmlNode &node, Collada::Mesh &pMesh) {
 1386|    165|    if (node.empty()) {
  ------------------
  |  Branch (1386:9): [True: 0, False: 165]
  ------------------
 1387|      0|        return;
 1388|      0|    }
 1389|       |
 1390|    165|    for (XmlNode &currentNode : node.children()) {
  ------------------
  |  Branch (1390:31): [True: 165, False: 165]
  ------------------
 1391|    165|        const std::string &currentName = currentNode.name();
 1392|    165|        if (currentName == "mesh") {
  ------------------
  |  Branch (1392:13): [True: 165, False: 0]
  ------------------
 1393|    165|            ReadMesh(currentNode, pMesh);
 1394|    165|        }
 1395|    165|    }
 1396|    165|}
_ZN6Assimp13ColladaParser8ReadMeshERN4pugi8xml_nodeERNS_7Collada4MeshE:
 1400|    165|void ColladaParser::ReadMesh(XmlNode &node, Mesh &pMesh) {
 1401|    165|    if (node.empty()) {
  ------------------
  |  Branch (1401:9): [True: 0, False: 165]
  ------------------
 1402|      0|        return;
 1403|      0|    }
 1404|       |
 1405|    165|    XmlNodeIterator xmlIt(node, XmlNodeIterator::PreOrderMode);
 1406|    165|    XmlNode currentNode;
 1407|  12.4k|    while (xmlIt.getNext(currentNode)) {
  ------------------
  |  Branch (1407:12): [True: 12.2k, False: 165]
  ------------------
 1408|  12.2k|        const std::string &currentName = currentNode.name();
 1409|  12.2k|        if (currentName == "source") {
  ------------------
  |  Branch (1409:13): [True: 486, False: 11.7k]
  ------------------
 1410|    486|            ReadSource(currentNode);
 1411|  11.7k|        } else if (currentName == "vertices") {
  ------------------
  |  Branch (1411:20): [True: 159, False: 11.6k]
  ------------------
 1412|    159|            ReadVertexData(currentNode, pMesh);
 1413|  11.6k|        } else if (currentName == "triangles" || currentName == "lines" || currentName == "linestrips" ||
  ------------------
  |  Branch (1413:20): [True: 14, False: 11.6k]
  |  Branch (1413:50): [True: 0, False: 11.6k]
  |  Branch (1413:76): [True: 0, False: 11.6k]
  ------------------
 1414|  11.6k|                   currentName == "polygons" || currentName == "polylist" || currentName == "trifans" ||
  ------------------
  |  Branch (1414:20): [True: 11, False: 11.6k]
  |  Branch (1414:49): [True: 138, False: 11.4k]
  |  Branch (1414:78): [True: 0, False: 11.4k]
  ------------------
 1415|  11.4k|                   currentName == "tristrips") {
  ------------------
  |  Branch (1415:20): [True: 0, False: 11.4k]
  ------------------
 1416|    163|            ReadIndexData(currentNode, pMesh);
 1417|    163|        }
 1418|  12.2k|    }
 1419|    165|}
_ZN6Assimp13ColladaParser10ReadSourceERN4pugi8xml_nodeE:
 1423|  1.68k|void ColladaParser::ReadSource(XmlNode &node) {
 1424|  1.68k|    if (node.empty()) {
  ------------------
  |  Branch (1424:9): [True: 0, False: 1.68k]
  ------------------
 1425|      0|        return;
 1426|      0|    }
 1427|       |
 1428|  1.68k|    std::string sourceID;
 1429|  1.68k|    XmlParser::getStdStrAttribute(node, "id", sourceID);
 1430|  1.68k|    XmlNodeIterator xmlIt(node, XmlNodeIterator::PreOrderMode);
 1431|  1.68k|    XmlNode currentNode;
 1432|  9.21k|    while (xmlIt.getNext(currentNode)) {
  ------------------
  |  Branch (1432:12): [True: 7.52k, False: 1.68k]
  ------------------
 1433|  7.52k|        const std::string &currentName = currentNode.name();
 1434|  7.52k|        if (currentName == "float_array" || currentName == "IDREF_array" || currentName == "Name_array") {
  ------------------
  |  Branch (1434:13): [True: 1.28k, False: 6.24k]
  |  Branch (1434:45): [True: 0, False: 6.24k]
  |  Branch (1434:77): [True: 399, False: 5.84k]
  ------------------
 1435|  1.68k|            ReadDataArray(currentNode);
 1436|  5.84k|        } else if (currentName == "technique_common") {
  ------------------
  |  Branch (1436:20): [True: 1.67k, False: 4.16k]
  ------------------
 1437|  1.67k|            XmlNode technique = currentNode.child("accessor");
 1438|  1.67k|            if (!technique.empty()) {
  ------------------
  |  Branch (1438:17): [True: 1.67k, False: 0]
  ------------------
 1439|  1.67k|                ReadAccessor(technique, sourceID);
 1440|  1.67k|            }
 1441|  1.67k|        }
 1442|  7.52k|    }
 1443|  1.68k|}
_ZN6Assimp13ColladaParser13ReadDataArrayERN4pugi8xml_nodeE:
 1447|  1.68k|void ColladaParser::ReadDataArray(XmlNode &node) {
 1448|  1.68k|    std::string name = node.name();
 1449|  1.68k|    bool isStringArray = (name == "IDREF_array" || name == "Name_array");
  ------------------
  |  Branch (1449:27): [True: 0, False: 1.68k]
  |  Branch (1449:52): [True: 399, False: 1.28k]
  ------------------
 1450|       |
 1451|       |    // read attributes
 1452|  1.68k|    std::string id;
 1453|  1.68k|    XmlParser::getStdStrAttribute(node, "id", id);
 1454|  1.68k|    unsigned int count = 0;
 1455|  1.68k|    XmlParser::getUIntAttribute(node, "count", count);
 1456|  1.68k|    std::string v;
 1457|  1.68k|    XmlParser::getValueAsString(node, v);
 1458|  1.68k|    v = ai_trim(v);
 1459|  1.68k|    const char *content = v.c_str();
 1460|  1.68k|    const char *end = content + v.size();
 1461|       |
 1462|       |    // read values and store inside an array in the data library
 1463|  1.68k|    mDataLibrary[id] = Data();
 1464|  1.68k|    Data &data = mDataLibrary[id];
 1465|  1.68k|    data.mIsStringArray = isStringArray;
 1466|       |
 1467|       |    // some exporters write empty data arrays, but we need to conserve them anyways because others might reference them
 1468|  1.68k|    if (content) {
  ------------------
  |  Branch (1468:9): [True: 1.68k, False: 0]
  ------------------
 1469|  1.68k|        if (isStringArray) {
  ------------------
  |  Branch (1469:13): [True: 399, False: 1.28k]
  ------------------
 1470|    399|            data.mStrings.reserve(count);
 1471|    399|            std::string s;
 1472|       |
 1473|  1.40k|            for (unsigned int a = 0; a < count; a++) {
  ------------------
  |  Branch (1473:38): [True: 1.00k, False: 399]
  ------------------
 1474|  1.00k|                if (*content == 0) {
  ------------------
  |  Branch (1474:21): [True: 0, False: 1.00k]
  ------------------
 1475|      0|                    throw DeadlyImportError("Expected more values while reading IDREF_array contents.");
 1476|      0|                }
 1477|       |
 1478|  1.00k|                s.clear();
 1479|  7.16k|                while (!IsSpaceOrNewLine(*content)) {
  ------------------
  |  Branch (1479:24): [True: 6.15k, False: 1.00k]
  ------------------
 1480|  6.15k|                    s += *content;
 1481|  6.15k|                    content++;
 1482|  6.15k|                }
 1483|  1.00k|                data.mStrings.push_back(s);
 1484|       |
 1485|  1.00k|                SkipSpacesAndLineEnd(&content, end);
 1486|  1.00k|            }
 1487|  1.28k|        } else {
 1488|  1.28k|            data.mValues.reserve(count);
 1489|       |
 1490|   378k|            for (unsigned int a = 0; a < count; a++) {
  ------------------
  |  Branch (1490:38): [True: 377k, False: 1.28k]
  ------------------
 1491|   377k|                if (*content == 0) {
  ------------------
  |  Branch (1491:21): [True: 2, False: 377k]
  ------------------
 1492|      2|                    throw DeadlyImportError("Expected more values while reading float_array contents.");
 1493|      2|                }
 1494|       |
 1495|       |                // read a number
 1496|   377k|                ai_real value;
 1497|   377k|                content = fast_atoreal_move(content, value);
 1498|   377k|                data.mValues.push_back(value);
 1499|       |                // skip whitespace after it
 1500|   377k|                SkipSpacesAndLineEnd(&content, end);
 1501|   377k|            }
 1502|  1.28k|        }
 1503|  1.68k|    }
 1504|  1.68k|}
_ZN6Assimp13ColladaParser12ReadAccessorERN4pugi8xml_nodeERKNSt3__112basic_stringIcNS4_11char_traitsIcEENS4_9allocatorIcEEEE:
 1508|  1.67k|void ColladaParser::ReadAccessor(XmlNode &node, const std::string &pID) {
 1509|       |    // read accessor attributes
 1510|  1.67k|    std::string source;
 1511|  1.67k|    XmlParser::getStdStrAttribute(node, "source", source);
 1512|  1.67k|    if (source[0] != '#') {
  ------------------
  |  Branch (1512:9): [True: 0, False: 1.67k]
  ------------------
 1513|      0|        throw DeadlyImportError("Unknown reference format in url \"", source, "\" in source attribute of <accessor> element.");
 1514|      0|    }
 1515|  1.67k|    int count = 0;
 1516|  1.67k|    XmlParser::getIntAttribute(node, "count", count);
 1517|       |
 1518|  1.67k|    unsigned int offset = 0;
 1519|  1.67k|    if (XmlParser::hasAttribute(node, "offset")) {
  ------------------
  |  Branch (1519:9): [True: 28, False: 1.65k]
  ------------------
 1520|     28|        XmlParser::getUIntAttribute(node, "offset", offset);
 1521|     28|    }
 1522|  1.67k|    unsigned int stride = 1;
 1523|  1.67k|    if (XmlParser::hasAttribute(node, "stride")) {
  ------------------
  |  Branch (1523:9): [True: 1.67k, False: 0]
  ------------------
 1524|  1.67k|        XmlParser::getUIntAttribute(node, "stride", stride);
 1525|  1.67k|    }
 1526|       |    // store in the library under the given ID
 1527|  1.67k|    mAccessorLibrary[pID] = Accessor();
 1528|  1.67k|    Accessor &acc = mAccessorLibrary[pID];
 1529|  1.67k|    acc.mCount = count;
 1530|  1.67k|    acc.mOffset = offset;
 1531|  1.67k|    acc.mStride = stride;
 1532|  1.67k|    acc.mSource = source.c_str() + 1; // ignore the leading '#'
 1533|  1.67k|    acc.mSize = 0; // gets incremented with every param
 1534|       |
 1535|  1.67k|    XmlNodeIterator xmlIt(node, XmlNodeIterator::PreOrderMode);
 1536|  1.67k|    XmlNode currentNode;
 1537|  4.16k|    while (xmlIt.getNext(currentNode)) {
  ------------------
  |  Branch (1537:12): [True: 2.48k, False: 1.67k]
  ------------------
 1538|  2.48k|        const std::string &currentName = currentNode.name();
 1539|  2.48k|        if (currentName == "param") {
  ------------------
  |  Branch (1539:13): [True: 2.48k, False: 0]
  ------------------
 1540|       |            // read data param
 1541|  2.48k|            std::string name;
 1542|  2.48k|            if (XmlParser::hasAttribute(currentNode, "name")) {
  ------------------
  |  Branch (1542:17): [True: 1.33k, False: 1.15k]
  ------------------
 1543|  1.33k|                XmlParser::getStdStrAttribute(currentNode, "name", name);
 1544|       |
 1545|       |                // analyse for common type components and store it's sub-offset in the corresponding field
 1546|       |
 1547|       |                // Cartesian coordinates
 1548|  1.33k|                if (name == "X")
  ------------------
  |  Branch (1548:21): [True: 327, False: 1.00k]
  ------------------
 1549|    327|                    acc.mSubOffset[0] = acc.mParams.size();
 1550|  1.00k|                else if (name == "Y")
  ------------------
  |  Branch (1550:26): [True: 327, False: 679]
  ------------------
 1551|    327|                    acc.mSubOffset[1] = acc.mParams.size();
 1552|    679|                else if (name == "Z")
  ------------------
  |  Branch (1552:26): [True: 327, False: 352]
  ------------------
 1553|    327|                    acc.mSubOffset[2] = acc.mParams.size();
 1554|       |
 1555|       |                /* RGBA colors */
 1556|    352|                else if (name == "R")
  ------------------
  |  Branch (1556:26): [True: 0, False: 352]
  ------------------
 1557|      0|                    acc.mSubOffset[0] = acc.mParams.size();
 1558|    352|                else if (name == "G")
  ------------------
  |  Branch (1558:26): [True: 0, False: 352]
  ------------------
 1559|      0|                    acc.mSubOffset[1] = acc.mParams.size();
 1560|    352|                else if (name == "B")
  ------------------
  |  Branch (1560:26): [True: 0, False: 352]
  ------------------
 1561|      0|                    acc.mSubOffset[2] = acc.mParams.size();
 1562|    352|                else if (name == "A")
  ------------------
  |  Branch (1562:26): [True: 0, False: 352]
  ------------------
 1563|      0|                    acc.mSubOffset[3] = acc.mParams.size();
 1564|       |
 1565|       |                /* UVWQ (STPQ) texture coordinates */
 1566|    352|                else if (name == "S")
  ------------------
  |  Branch (1566:26): [True: 153, False: 199]
  ------------------
 1567|    153|                    acc.mSubOffset[0] = acc.mParams.size();
 1568|    199|                else if (name == "T")
  ------------------
  |  Branch (1568:26): [True: 153, False: 46]
  ------------------
 1569|    153|                    acc.mSubOffset[1] = acc.mParams.size();
 1570|     46|                else if (name == "P")
  ------------------
  |  Branch (1570:26): [True: 0, False: 46]
  ------------------
 1571|      0|                    acc.mSubOffset[2] = acc.mParams.size();
 1572|       |                /* Generic extra data, interpreted as UV data, too*/
 1573|     46|                else if (name == "U")
  ------------------
  |  Branch (1573:26): [True: 0, False: 46]
  ------------------
 1574|      0|                    acc.mSubOffset[0] = acc.mParams.size();
 1575|     46|                else if (name == "V")
  ------------------
  |  Branch (1575:26): [True: 0, False: 46]
  ------------------
 1576|      0|                    acc.mSubOffset[1] = acc.mParams.size();
 1577|  1.33k|            }
 1578|  2.48k|            if (XmlParser::hasAttribute(currentNode, "type")) {
  ------------------
  |  Branch (1578:17): [True: 2.48k, False: 0]
  ------------------
 1579|       |                // read data type
 1580|       |                // TODO: (thom) I don't have a spec here at work. Check if there are other multi-value types
 1581|       |                // which should be tested for here.
 1582|  2.48k|                std::string type;
 1583|       |
 1584|  2.48k|                XmlParser::getStdStrAttribute(currentNode, "type", type);
 1585|  2.48k|                if (type == "float4x4")
  ------------------
  |  Branch (1585:21): [True: 15, False: 2.47k]
  ------------------
 1586|     15|                    acc.mSize += 16;
 1587|  2.47k|                else
 1588|  2.47k|                    acc.mSize += 1;
 1589|  2.48k|            }
 1590|       |
 1591|  2.48k|            acc.mParams.push_back(name);
 1592|  2.48k|        }
 1593|  2.48k|    }
 1594|  1.67k|}
_ZN6Assimp13ColladaParser14ReadVertexDataERN4pugi8xml_nodeERNS_7Collada4MeshE:
 1598|    159|void ColladaParser::ReadVertexData(XmlNode &node, Mesh &pMesh) {
 1599|       |    // extract the ID of the <vertices> element. Not that we care, but to catch strange referencing schemes we should warn about
 1600|    159|    XmlParser::getStdStrAttribute(node, "id", pMesh.mVertexID);
 1601|    423|    for (XmlNode &currentNode : node.children()) {
  ------------------
  |  Branch (1601:31): [True: 423, False: 158]
  ------------------
 1602|    423|        const std::string &currentName = currentNode.name();
 1603|    423|        if (currentName == "input") {
  ------------------
  |  Branch (1603:13): [True: 422, False: 1]
  ------------------
 1604|    422|            ReadInputChannel(currentNode, pMesh.mPerVertexData);
 1605|    422|        } else {
 1606|      1|            throw DeadlyImportError("Unexpected sub element <", currentName, "> in tag <vertices>");
 1607|      1|        }
 1608|    423|    }
 1609|    159|}
_ZN6Assimp13ColladaParser13ReadIndexDataERN4pugi8xml_nodeERNS_7Collada4MeshE:
 1613|    163|void ColladaParser::ReadIndexData(XmlNode &node, Mesh &pMesh) {
 1614|    163|    std::vector<size_t> vcount;
 1615|    163|    std::vector<InputChannel> perIndexData;
 1616|       |
 1617|    163|    unsigned int numPrimitives = 0;
 1618|    163|    XmlParser::getUIntAttribute(node, "count", numPrimitives);
 1619|       |    // read primitive count from the attribute
 1620|       |    //int attrCount = GetAttribute("count");
 1621|       |    //size_t numPrimitives = (size_t)mReader->getAttributeValueAsInt(attrCount);
 1622|       |    // some mesh types (e.g. tristrips) don't specify primitive count upfront,
 1623|       |    // so we need to sum up the actual number of primitives while we read the <p>-tags
 1624|    163|    size_t actualPrimitives = 0;
 1625|    163|    SubMesh subgroup;
 1626|    163|    if (XmlParser::hasAttribute(node, "material")) {
  ------------------
  |  Branch (1626:9): [True: 33, False: 130]
  ------------------
 1627|     33|        XmlParser::getStdStrAttribute(node, "material", subgroup.mMaterial);
 1628|     33|    }
 1629|       |
 1630|       |    // distinguish between polys and triangles
 1631|    163|    std::string elementName = node.name();
 1632|    163|    PrimitiveType primType = Prim_Invalid;
 1633|    163|    if (elementName == "lines")
  ------------------
  |  Branch (1633:9): [True: 0, False: 163]
  ------------------
 1634|      0|        primType = Prim_Lines;
 1635|    163|    else if (elementName == "linestrips")
  ------------------
  |  Branch (1635:14): [True: 0, False: 163]
  ------------------
 1636|      0|        primType = Prim_LineStrip;
 1637|    163|    else if (elementName == "polygons")
  ------------------
  |  Branch (1637:14): [True: 11, False: 152]
  ------------------
 1638|     11|        primType = Prim_Polygon;
 1639|    152|    else if (elementName == "polylist")
  ------------------
  |  Branch (1639:14): [True: 138, False: 14]
  ------------------
 1640|    138|        primType = Prim_Polylist;
 1641|     14|    else if (elementName == "triangles")
  ------------------
  |  Branch (1641:14): [True: 14, False: 0]
  ------------------
 1642|     14|        primType = Prim_Triangles;
 1643|      0|    else if (elementName == "trifans")
  ------------------
  |  Branch (1643:14): [True: 0, False: 0]
  ------------------
 1644|      0|        primType = Prim_TriFans;
 1645|      0|    else if (elementName == "tristrips")
  ------------------
  |  Branch (1645:14): [True: 0, False: 0]
  ------------------
 1646|      0|        primType = Prim_TriStrips;
 1647|       |
 1648|    163|    ai_assert(primType != Prim_Invalid);
  ------------------
  |  |   67|    163|#   define ai_assert(expression) (void)((!!(expression)) || (Assimp::aiAssertViolation(#expression, __FILE__, __LINE__), 0))
  |  |  ------------------
  |  |  |  Branch (67:41): [True: 163, False: 0]
  |  |  |  Branch (67:61): [True: 0, False: 0]
  |  |  ------------------
  ------------------
 1649|       |
 1650|       |    // also a number of <input> elements, but in addition a <p> primitive collection and probably index counts for all primitives
 1651|    163|    XmlNodeIterator xmlIt(node, XmlNodeIterator::PreOrderMode);
 1652|    163|    XmlNode currentNode;
 1653|  8.50k|    while (xmlIt.getNext(currentNode)) {
  ------------------
  |  Branch (1653:12): [True: 8.34k, False: 163]
  ------------------
 1654|  8.34k|        const std::string &currentName = currentNode.name();
 1655|  8.34k|        if (currentName == "input") {
  ------------------
  |  Branch (1655:13): [True: 225, False: 8.11k]
  ------------------
 1656|    225|            ReadInputChannel(currentNode, perIndexData);
 1657|  8.11k|        } else if (currentName == "vcount") {
  ------------------
  |  Branch (1657:20): [True: 138, False: 7.98k]
  ------------------
 1658|    138|            if (!currentNode.empty()) {
  ------------------
  |  Branch (1658:17): [True: 138, False: 0]
  ------------------
 1659|    138|                if (numPrimitives) // It is possible to define a mesh without any primitives
  ------------------
  |  Branch (1659:21): [True: 138, False: 0]
  ------------------
 1660|    138|                {
 1661|       |                    // case <polylist> - specifies the number of indices for each polygon
 1662|    138|                    std::string v;
 1663|    138|                    XmlParser::getValueAsString(currentNode, v);
 1664|    138|                    const char *content = v.c_str();
 1665|    138|                    const char *end = content + v.size();
 1666|       |
 1667|    138|                    vcount.reserve(numPrimitives);
 1668|    138|                    SkipSpacesAndLineEnd(&content, end);
 1669|  14.5k|                    for (unsigned int a = 0; a < numPrimitives; a++) {
  ------------------
  |  Branch (1669:46): [True: 14.3k, False: 138]
  ------------------
 1670|  14.3k|                        if (*content == 0) {
  ------------------
  |  Branch (1670:29): [True: 0, False: 14.3k]
  ------------------
 1671|      0|                            throw DeadlyImportError("Expected more values while reading <vcount> contents.");
 1672|      0|                        }
 1673|       |                        // read a number
 1674|  14.3k|                        vcount.push_back((size_t)strtoul10(content, &content));
 1675|       |                        // skip whitespace after it
 1676|  14.3k|                        SkipSpacesAndLineEnd(&content, end);
 1677|  14.3k|                    }
 1678|    138|                }
 1679|    138|            }
 1680|  7.98k|        } else if (currentName == "p") {
  ------------------
  |  Branch (1680:20): [True: 7.98k, False: 0]
  ------------------
 1681|  7.98k|            if (!currentNode.empty()) {
  ------------------
  |  Branch (1681:17): [True: 7.98k, False: 0]
  ------------------
 1682|       |                // now here the actual fun starts - these are the indices to construct the mesh data from
 1683|  7.98k|                actualPrimitives += ReadPrimitives(currentNode, pMesh, perIndexData, numPrimitives, vcount, primType);
 1684|  7.98k|            }
 1685|  7.98k|        } else if (currentName == "extra") {
  ------------------
  |  Branch (1685:20): [True: 0, False: 0]
  ------------------
 1686|       |            // skip
 1687|      0|        } else if (currentName == "ph") {
  ------------------
  |  Branch (1687:20): [True: 0, False: 0]
  ------------------
 1688|       |            // skip
 1689|      0|        } else {
 1690|      0|            throw DeadlyImportError("Unexpected sub element <", currentName, "> in tag <", elementName, ">");
 1691|      0|        }
 1692|  8.34k|    }
 1693|       |
 1694|    163|#ifdef ASSIMP_BUILD_DEBUG
 1695|    163|    if (primType != Prim_TriFans && primType != Prim_TriStrips && primType != Prim_LineStrip &&
  ------------------
  |  Branch (1695:9): [True: 158, False: 5]
  |  Branch (1695:37): [True: 158, False: 0]
  |  Branch (1695:67): [True: 158, False: 0]
  ------------------
 1696|    158|            primType != Prim_Lines) { // this is ONLY to workaround a bug in SketchUp 15.3.331 where it writes the wrong 'count' when it writes out the 'lines'.
  ------------------
  |  Branch (1696:13): [True: 158, False: 0]
  ------------------
 1697|    158|        ai_assert(actualPrimitives == numPrimitives);
  ------------------
  |  |   67|    158|#   define ai_assert(expression) (void)((!!(expression)) || (Assimp::aiAssertViolation(#expression, __FILE__, __LINE__), 0))
  |  |  ------------------
  |  |  |  Branch (67:41): [True: 158, False: 0]
  |  |  |  Branch (67:61): [True: 0, False: 0]
  |  |  ------------------
  ------------------
 1698|    158|    }
 1699|    163|#endif
 1700|       |
 1701|       |    // only when we're done reading all <p> tags (and thus know the final vertex count) can we commit the submesh
 1702|    163|    subgroup.mNumFaces = actualPrimitives;
 1703|    163|    pMesh.mSubMeshes.push_back(subgroup);
 1704|    163|}
_ZN6Assimp13ColladaParser16ReadInputChannelERN4pugi8xml_nodeERNSt3__16vectorINS_7Collada12InputChannelENS4_9allocatorIS7_EEEE:
 1708|    647|void ColladaParser::ReadInputChannel(XmlNode &node, std::vector<InputChannel> &poChannels) {
 1709|    647|    InputChannel channel;
 1710|       |
 1711|       |    // read semantic
 1712|    647|    std::string semantic;
 1713|    647|    XmlParser::getStdStrAttribute(node, "semantic", semantic);
 1714|    647|    channel.mType = GetTypeForSemantic(semantic);
 1715|       |
 1716|       |    // read source
 1717|    647|    std::string source;
 1718|    647|    XmlParser::getStdStrAttribute(node, "source", source);
 1719|    647|    if (source[0] != '#') {
  ------------------
  |  Branch (1719:9): [True: 0, False: 647]
  ------------------
 1720|      0|        throw DeadlyImportError("Unknown reference format in url \"", source, "\" in source attribute of <input> element.");
 1721|      0|    }
 1722|    647|    channel.mAccessor = source.c_str() + 1; // skipping the leading #, hopefully the remaining text is the accessor ID only
 1723|       |
 1724|       |    // read index offset, if per-index <input>
 1725|    647|    if (XmlParser::hasAttribute(node, "offset")) {
  ------------------
  |  Branch (1725:9): [True: 225, False: 422]
  ------------------
 1726|    225|        XmlParser::getUIntAttribute(node, "offset", (unsigned int &)channel.mOffset);
 1727|    225|    }
 1728|       |
 1729|       |    // read set if texture coordinates
 1730|    647|    if (channel.mType == IT_Texcoord || channel.mType == IT_Color) {
  ------------------
  |  Branch (1730:9): [True: 157, False: 490]
  |  Branch (1730:41): [True: 2, False: 488]
  ------------------
 1731|    159|        unsigned int attrSet = 0;
 1732|    159|        if (XmlParser::getUIntAttribute(node, "set", attrSet))
  ------------------
  |  Branch (1732:13): [True: 22, False: 137]
  ------------------
 1733|     22|            channel.mIndex = attrSet;
 1734|    159|    }
 1735|       |
 1736|       |    // store, if valid type
 1737|    647|    if (channel.mType != IT_Invalid)
  ------------------
  |  Branch (1737:9): [True: 647, False: 0]
  ------------------
 1738|    647|        poChannels.push_back(channel);
 1739|    647|}
_ZN6Assimp13ColladaParser14ReadPrimitivesERN4pugi8xml_nodeERNS_7Collada4MeshERNSt3__16vectorINS4_12InputChannelENS7_9allocatorIS9_EEEEmRKNS8_ImNSA_ImEEEENS4_13PrimitiveTypeE:
 1744|  7.98k|        size_t pNumPrimitives, const std::vector<size_t> &pVCount, PrimitiveType pPrimType) {
 1745|       |    // determine number of indices coming per vertex
 1746|       |    // find the offset index for all per-vertex channels
 1747|  7.98k|    size_t numOffsets = 1;
 1748|  7.98k|    size_t perVertexOffset = SIZE_MAX; // invalid value
 1749|  22.7k|    for (const InputChannel &channel : pPerIndexChannels) {
  ------------------
  |  Branch (1749:38): [True: 22.7k, False: 7.98k]
  ------------------
 1750|  22.7k|        numOffsets = std::max(numOffsets, channel.mOffset + 1);
 1751|  22.7k|        if (channel.mType == IT_Vertex)
  ------------------
  |  Branch (1751:13): [True: 7.98k, False: 14.7k]
  ------------------
 1752|  7.98k|            perVertexOffset = channel.mOffset;
 1753|  22.7k|    }
 1754|       |
 1755|       |    // determine the expected number of indices
 1756|  7.98k|    size_t expectedPointCount = 0;
 1757|  7.98k|    switch (pPrimType) {
 1758|    138|    case Prim_Polylist: {
  ------------------
  |  Branch (1758:5): [True: 138, False: 7.84k]
  ------------------
 1759|    138|        for (size_t i : pVCount)
  ------------------
  |  Branch (1759:23): [True: 14.3k, False: 138]
  ------------------
 1760|  14.3k|            expectedPointCount += i;
 1761|    138|        break;
 1762|      0|    }
 1763|      0|    case Prim_Lines:
  ------------------
  |  Branch (1763:5): [True: 0, False: 7.98k]
  ------------------
 1764|      0|        expectedPointCount = 2 * pNumPrimitives;
 1765|      0|        break;
 1766|     14|    case Prim_Triangles:
  ------------------
  |  Branch (1766:5): [True: 14, False: 7.96k]
  ------------------
 1767|     14|        expectedPointCount = 3 * pNumPrimitives;
 1768|     14|        break;
 1769|  7.82k|    default:
  ------------------
  |  Branch (1769:5): [True: 7.82k, False: 152]
  ------------------
 1770|  7.82k|        break;
 1771|  7.98k|    }
 1772|       |
 1773|       |    // and read all indices into a temporary array
 1774|  7.98k|    std::vector<size_t> indices;
 1775|  7.98k|    if (expectedPointCount > 0) {
  ------------------
  |  Branch (1775:9): [True: 152, False: 7.82k]
  ------------------
 1776|    152|        indices.reserve(expectedPointCount * numOffsets);
 1777|    152|    }
 1778|       |
 1779|       |    // It is possible to not contain any indices
 1780|  7.98k|    if (pNumPrimitives > 0) {
  ------------------
  |  Branch (1780:9): [True: 7.98k, False: 0]
  ------------------
 1781|  7.98k|        std::string v;
 1782|  7.98k|        XmlParser::getValueAsString(node, v);
 1783|  7.98k|        const char *content = v.c_str();
 1784|  7.98k|        const char *end = content + v.size();
 1785|       |
 1786|  7.98k|        SkipSpacesAndLineEnd(&content, end);
 1787|   301k|        while (*content != 0) {
  ------------------
  |  Branch (1787:16): [True: 293k, False: 7.98k]
  ------------------
 1788|       |            // read a value.
 1789|       |            // Hack: (thom) Some exporters put negative indices sometimes. We just try to carry on anyways.
 1790|   293k|            int value = std::max(0, strtol10(content, &content));
 1791|   293k|            indices.push_back(size_t(value));
 1792|       |            // skip whitespace after it
 1793|   293k|            SkipSpacesAndLineEnd(&content, end);
 1794|   293k|        }
 1795|  7.98k|    }
 1796|       |
 1797|       |    // complain if the index count doesn't fit
 1798|  7.98k|    if (expectedPointCount > 0 && indices.size() != expectedPointCount * numOffsets) {
  ------------------
  |  Branch (1798:9): [True: 152, False: 7.82k]
  |  Branch (1798:35): [True: 1, False: 151]
  ------------------
 1799|      1|        if (pPrimType == Prim_Lines) {
  ------------------
  |  Branch (1799:13): [True: 0, False: 1]
  ------------------
 1800|       |            // HACK: We just fix this number since SketchUp 15.3.331 writes the wrong 'count' for 'lines'
 1801|      0|            ReportWarning("Expected different index count in <p> element, %zu instead of %zu.", indices.size(), expectedPointCount * numOffsets);
 1802|      0|            pNumPrimitives = (indices.size() / numOffsets) / 2;
 1803|      1|        } else {
 1804|      1|            throw DeadlyImportError("Expected different index count in <p> element.");
 1805|      1|        }
 1806|  7.98k|    } else if (expectedPointCount == 0 && (indices.size() % numOffsets) != 0) {
  ------------------
  |  Branch (1806:16): [True: 7.82k, False: 151]
  |  Branch (1806:43): [True: 0, False: 7.82k]
  ------------------
 1807|      0|        throw DeadlyImportError("Expected different index count in <p> element.");
 1808|      0|    }
 1809|       |
 1810|       |    // find the data for all sources
 1811|  16.2k|    for (auto it = pMesh.mPerVertexData.begin(); it != pMesh.mPerVertexData.end(); ++it) {
  ------------------
  |  Branch (1811:50): [True: 8.24k, False: 7.97k]
  ------------------
 1812|  8.24k|        InputChannel &input = *it;
 1813|  8.24k|        if (input.mResolved) {
  ------------------
  |  Branch (1813:13): [True: 7.82k, False: 421]
  ------------------
 1814|  7.82k|            continue;
 1815|  7.82k|        }
 1816|       |
 1817|       |        // find accessor
 1818|    421|        input.mResolved = &ResolveLibraryReference(mAccessorLibrary, input.mAccessor);
 1819|       |        // resolve accessor's data pointer as well, if necessary
 1820|    421|        const Accessor *acc = input.mResolved;
 1821|    421|        if (!acc->mData) {
  ------------------
  |  Branch (1821:13): [True: 415, False: 6]
  ------------------
 1822|    415|            acc->mData = &ResolveLibraryReference(mDataLibrary, acc->mSource);
 1823|    415|            const size_t dataSize = acc->mOffset + acc->mCount * acc->mStride;
 1824|    415|            if (dataSize > acc->mData->mValues.size()) {
  ------------------
  |  Branch (1824:17): [True: 2, False: 413]
  ------------------
 1825|      2|                throw DeadlyImportError("Not enough data for accessor");
 1826|      2|            }
 1827|    415|        }
 1828|    421|    }
 1829|       |    // and the same for the per-index channels
 1830|  30.7k|    for (auto it = pPerIndexChannels.begin(); it != pPerIndexChannels.end(); ++it) {
  ------------------
  |  Branch (1830:47): [True: 22.7k, False: 7.97k]
  ------------------
 1831|  22.7k|        InputChannel &input = *it;
 1832|  22.7k|        if (input.mResolved) {
  ------------------
  |  Branch (1832:13): [True: 14.6k, False: 8.02k]
  ------------------
 1833|  14.6k|            continue;
 1834|  14.6k|        }
 1835|       |
 1836|       |        // ignore vertex pointer, it doesn't refer to an accessor
 1837|  8.02k|        if (input.mType == IT_Vertex) {
  ------------------
  |  Branch (1837:13): [True: 7.97k, False: 52]
  ------------------
 1838|       |            // warn if the vertex channel does not refer to the <vertices> element in the same mesh
 1839|  7.97k|            if (input.mAccessor != pMesh.mVertexID) {
  ------------------
  |  Branch (1839:17): [True: 0, False: 7.97k]
  ------------------
 1840|      0|                throw DeadlyImportError("Unsupported vertex referencing scheme.");
 1841|      0|            }
 1842|  7.97k|            continue;
 1843|  7.97k|        }
 1844|       |
 1845|       |        // find accessor
 1846|     52|        input.mResolved = &ResolveLibraryReference(mAccessorLibrary, input.mAccessor);
 1847|       |        // resolve accessor's data pointer as well, if necessary
 1848|     52|        const Accessor *acc = input.mResolved;
 1849|     52|        if (!acc->mData) {
  ------------------
  |  Branch (1849:13): [True: 42, False: 10]
  ------------------
 1850|     42|            acc->mData = &ResolveLibraryReference(mDataLibrary, acc->mSource);
 1851|     42|            const size_t dataSize = acc->mOffset + acc->mCount * acc->mStride;
 1852|     42|            if (dataSize > acc->mData->mValues.size()) {
  ------------------
  |  Branch (1852:17): [True: 0, False: 42]
  ------------------
 1853|      0|                throw DeadlyImportError("Not enough data for accessor");
 1854|      0|            }
 1855|     42|        }
 1856|     52|    }
 1857|       |
 1858|       |    // For continued primitives, the given count does not come all in one <p>, but only one primitive per <p>
 1859|  7.97k|    size_t numPrimitives = pNumPrimitives;
 1860|  7.97k|    if (pPrimType == Prim_TriFans || pPrimType == Prim_Polygon) {
  ------------------
  |  Branch (1860:9): [True: 2, False: 7.97k]
  |  Branch (1860:38): [True: 7.82k, False: 148]
  ------------------
 1861|  7.82k|        numPrimitives = 1;
 1862|  7.82k|    }
 1863|       |
 1864|       |    // For continued primitives, the given count is actually the number of <p>'s inside the parent tag
 1865|  7.97k|    if (pPrimType == Prim_TriStrips) {
  ------------------
  |  Branch (1865:9): [True: 0, False: 7.97k]
  ------------------
 1866|      0|        size_t numberOfVertices = indices.size() / numOffsets;
 1867|      0|        numPrimitives = numberOfVertices - 2;
 1868|      0|    }
 1869|  7.97k|    if (pPrimType == Prim_LineStrip) {
  ------------------
  |  Branch (1869:9): [True: 0, False: 7.97k]
  ------------------
 1870|      0|        size_t numberOfVertices = indices.size() / numOffsets;
 1871|      0|        numPrimitives = numberOfVertices - 1;
 1872|      0|    }
 1873|       |
 1874|  7.97k|    pMesh.mFaceSize.reserve(numPrimitives);
 1875|  7.97k|    pMesh.mFacePosIndices.reserve(indices.size() / numOffsets);
 1876|       |
 1877|  7.97k|    size_t polylistStartVertex = 0;
 1878|  43.2k|    for (size_t currentPrimitive = 0; currentPrimitive < numPrimitives; currentPrimitive++) {
  ------------------
  |  Branch (1878:39): [True: 35.3k, False: 7.97k]
  ------------------
 1879|       |        // determine number of points for this primitive
 1880|  35.3k|        size_t numPoints = 0;
 1881|  35.3k|        switch (pPrimType) {
 1882|      0|        case Prim_Lines:
  ------------------
  |  Branch (1882:9): [True: 0, False: 35.3k]
  ------------------
 1883|      0|            numPoints = 2;
 1884|      0|            for (size_t currentVertex = 0; currentVertex < numPoints; currentVertex++)
  ------------------
  |  Branch (1884:44): [True: 0, False: 0]
  ------------------
 1885|      0|                CopyVertex(currentVertex, numOffsets, numPoints, perVertexOffset, pMesh, pPerIndexChannels, currentPrimitive, indices);
 1886|      0|            break;
 1887|      0|        case Prim_LineStrip:
  ------------------
  |  Branch (1887:9): [True: 0, False: 35.3k]
  ------------------
 1888|      0|            numPoints = 2;
 1889|      0|            for (size_t currentVertex = 0; currentVertex < numPoints; currentVertex++)
  ------------------
  |  Branch (1889:44): [True: 0, False: 0]
  ------------------
 1890|      0|                CopyVertex(currentVertex, numOffsets, 1, perVertexOffset, pMesh, pPerIndexChannels, currentPrimitive, indices);
 1891|      0|            break;
 1892|  13.1k|        case Prim_Triangles:
  ------------------
  |  Branch (1892:9): [True: 13.1k, False: 22.1k]
  ------------------
 1893|  13.1k|            numPoints = 3;
 1894|  52.6k|            for (size_t currentVertex = 0; currentVertex < numPoints; currentVertex++)
  ------------------
  |  Branch (1894:44): [True: 39.4k, False: 13.1k]
  ------------------
 1895|  39.4k|                CopyVertex(currentVertex, numOffsets, numPoints, perVertexOffset, pMesh, pPerIndexChannels, currentPrimitive, indices);
 1896|  13.1k|            break;
 1897|      0|        case Prim_TriStrips:
  ------------------
  |  Branch (1897:9): [True: 0, False: 35.3k]
  ------------------
 1898|      0|            numPoints = 3;
 1899|      0|            ReadPrimTriStrips(numOffsets, perVertexOffset, pMesh, pPerIndexChannels, currentPrimitive, indices);
 1900|      0|            break;
 1901|  14.3k|        case Prim_Polylist:
  ------------------
  |  Branch (1901:9): [True: 14.3k, False: 20.9k]
  ------------------
 1902|  14.3k|            numPoints = pVCount[currentPrimitive];
 1903|  64.6k|            for (size_t currentVertex = 0; currentVertex < numPoints; currentVertex++)
  ------------------
  |  Branch (1903:44): [True: 50.3k, False: 14.3k]
  ------------------
 1904|  50.3k|                CopyVertex(polylistStartVertex + currentVertex, numOffsets, 1, perVertexOffset, pMesh, pPerIndexChannels, 0, indices);
 1905|  14.3k|            polylistStartVertex += numPoints;
 1906|  14.3k|            break;
 1907|      0|        case Prim_TriFans:
  ------------------
  |  Branch (1907:9): [True: 0, False: 35.3k]
  ------------------
 1908|  7.82k|        case Prim_Polygon:
  ------------------
  |  Branch (1908:9): [True: 7.82k, False: 27.4k]
  ------------------
 1909|  7.82k|            numPoints = indices.size() / numOffsets;
 1910|  31.3k|            for (size_t currentVertex = 0; currentVertex < numPoints; currentVertex++)
  ------------------
  |  Branch (1910:44): [True: 23.5k, False: 7.82k]
  ------------------
 1911|  23.5k|                CopyVertex(currentVertex, numOffsets, numPoints, perVertexOffset, pMesh, pPerIndexChannels, currentPrimitive, indices);
 1912|  7.82k|            break;
 1913|      0|        default:
  ------------------
  |  Branch (1913:9): [True: 0, False: 35.3k]
  ------------------
 1914|       |            // LineStrip is not supported due to expected index unmangling
 1915|      0|            throw DeadlyImportError("Unsupported primitive type.");
 1916|  35.3k|        }
 1917|       |
 1918|       |        // store the face size to later reconstruct the face from
 1919|  35.3k|        pMesh.mFaceSize.push_back(numPoints);
 1920|  35.3k|    }
 1921|       |
 1922|       |    // if I ever get my hands on that guy who invented this steaming pile of indirection...
 1923|  7.97k|    return numPrimitives;
 1924|  7.97k|}
_ZN6Assimp13ColladaParser10CopyVertexEmmmmRNS_7Collada4MeshERNSt3__16vectorINS1_12InputChannelENS4_9allocatorIS6_EEEEmRKNS5_ImNS7_ImEEEE:
 1930|   113k|        std::vector<InputChannel> &pPerIndexChannels, size_t currentPrimitive, const std::vector<size_t> &indices) {
 1931|       |    // calculate the base offset of the vertex whose attributes we ant to copy
 1932|   113k|    const auto baseOffset = currentPrimitive * numOffsets * numPoints + currentVertex * numOffsets;
 1933|       |
 1934|       |    // don't overrun the boundaries of the index list
 1935|   113k|    ai_assert((baseOffset + numOffsets - 1) < indices.size());
  ------------------
  |  |   67|   113k|#   define ai_assert(expression) (void)((!!(expression)) || (Assimp::aiAssertViolation(#expression, __FILE__, __LINE__), 0))
  |  |  ------------------
  |  |  |  Branch (67:41): [True: 113k, False: 0]
  |  |  |  Branch (67:61): [True: 0, False: 0]
  |  |  ------------------
  ------------------
 1936|       |
 1937|       |    // extract per-vertex channels using the global per-vertex offset
 1938|   236k|    for (auto it = pMesh.mPerVertexData.begin(); it != pMesh.mPerVertexData.end(); ++it) {
  ------------------
  |  Branch (1938:50): [True: 123k, False: 113k]
  ------------------
 1939|   123k|        ExtractDataObjectFromChannel(*it, indices[baseOffset + perVertexOffset], pMesh);
 1940|   123k|    }
 1941|       |    // and extract per-index channels using there specified offset
 1942|   400k|    for (auto it = pPerIndexChannels.begin(); it != pPerIndexChannels.end(); ++it) {
  ------------------
  |  Branch (1942:47): [True: 286k, False: 113k]
  ------------------
 1943|   286k|        ExtractDataObjectFromChannel(*it, indices[baseOffset + it->mOffset], pMesh);
 1944|   286k|    }
 1945|       |
 1946|       |    // store the vertex-data index for later assignment of bone vertex weights
 1947|   113k|    if (const auto indexOffset = baseOffset + perVertexOffset; indexOffset >= indices.size()) {
  ------------------
  |  Branch (1947:64): [True: 0, False: 113k]
  ------------------
 1948|      0|        throw DeadlyImportError("index offset out of range");
 1949|      0|    }
 1950|   113k|    pMesh.mFacePosIndices.push_back(indices[baseOffset + perVertexOffset]);
 1951|   113k|}
_ZN6Assimp13ColladaParser28ExtractDataObjectFromChannelERKNS_7Collada12InputChannelEmRNS1_4MeshE:
 1969|   410k|void ColladaParser::ExtractDataObjectFromChannel(const InputChannel &pInput, size_t pLocalIndex, Mesh &pMesh) {
 1970|       |    // ignore vertex referrer - we handle them that separate
 1971|   410k|    if (pInput.mType == IT_Vertex) {
  ------------------
  |  Branch (1971:9): [True: 113k, False: 296k]
  ------------------
 1972|   113k|        return;
 1973|   113k|    }
 1974|       |
 1975|   296k|    const Accessor &acc = *pInput.mResolved;
 1976|   296k|    if (pLocalIndex >= acc.mCount) {
  ------------------
  |  Branch (1976:9): [True: 0, False: 296k]
  ------------------
 1977|      0|        throw DeadlyImportError("Invalid data index (", pLocalIndex, "/", acc.mCount, ") in primitive specification");
 1978|      0|    }
 1979|       |
 1980|       |    // get a pointer to the start of the data object referred to by the accessor and the local index
 1981|   296k|    const ai_real *dataObject = &(acc.mData->mValues[0]) + acc.mOffset + pLocalIndex * acc.mStride;
 1982|       |
 1983|       |    // assemble according to the accessors component sub-offset list. We don't care, yet,
 1984|       |    // what kind of object exactly we're extracting here
 1985|   296k|    ai_real obj[4];
 1986|  1.48M|    for (size_t c = 0; c < 4; ++c) {
  ------------------
  |  Branch (1986:24): [True: 1.18M, False: 296k]
  ------------------
 1987|  1.18M|        obj[c] = dataObject[acc.mSubOffset[c]];
 1988|  1.18M|    }
 1989|       |
 1990|       |    // now we reinterpret it according to the type we're reading here
 1991|   296k|    switch (pInput.mType) {
 1992|   113k|    case IT_Position: // ignore all position streams except 0 - there can be only one position
  ------------------
  |  Branch (1992:5): [True: 113k, False: 183k]
  ------------------
 1993|   113k|        if (pInput.mIndex == 0) {
  ------------------
  |  Branch (1993:13): [True: 113k, False: 0]
  ------------------
 1994|   113k|            pMesh.mPositions.emplace_back(obj[0], obj[1], obj[2]);
 1995|   113k|        } else {
 1996|      0|            ASSIMP_LOG_ERROR("Collada: just one vertex position stream supported");
 1997|      0|        }
 1998|   113k|        break;
 1999|   113k|    case IT_Normal:
  ------------------
  |  Branch (1999:5): [True: 113k, False: 183k]
  ------------------
 2000|       |        // pad to current vertex count if necessary
 2001|   113k|        if (pMesh.mNormals.size() < pMesh.mPositions.size() - 1)
  ------------------
  |  Branch (2001:13): [True: 0, False: 113k]
  ------------------
 2002|      0|            pMesh.mNormals.insert(pMesh.mNormals.end(), pMesh.mPositions.size() - pMesh.mNormals.size() - 1, aiVector3D(0, 1, 0));
 2003|       |
 2004|       |        // ignore all normal streams except 0 - there can be only one normal
 2005|   113k|        if (pInput.mIndex == 0) {
  ------------------
  |  Branch (2005:13): [True: 113k, False: 0]
  ------------------
 2006|   113k|            pMesh.mNormals.emplace_back(obj[0], obj[1], obj[2]);
 2007|   113k|        } else {
 2008|      0|            ASSIMP_LOG_ERROR("Collada: just one vertex normal stream supported");
 2009|      0|        }
 2010|   113k|        break;
 2011|      0|    case IT_Tangent:
  ------------------
  |  Branch (2011:5): [True: 0, False: 296k]
  ------------------
 2012|       |        // pad to current vertex count if necessary
 2013|      0|        if (pMesh.mTangents.size() < pMesh.mPositions.size() - 1)
  ------------------
  |  Branch (2013:13): [True: 0, False: 0]
  ------------------
 2014|      0|            pMesh.mTangents.insert(pMesh.mTangents.end(), pMesh.mPositions.size() - pMesh.mTangents.size() - 1, aiVector3D(1, 0, 0));
 2015|       |
 2016|       |        // ignore all tangent streams except 0 - there can be only one tangent
 2017|      0|        if (pInput.mIndex == 0) {
  ------------------
  |  Branch (2017:13): [True: 0, False: 0]
  ------------------
 2018|      0|            pMesh.mTangents.emplace_back(obj[0], obj[1], obj[2]);
 2019|      0|        } else {
 2020|      0|            ASSIMP_LOG_ERROR("Collada: just one vertex tangent stream supported");
 2021|      0|        }
 2022|      0|        break;
 2023|      0|    case IT_Bitangent:
  ------------------
  |  Branch (2023:5): [True: 0, False: 296k]
  ------------------
 2024|       |        // pad to current vertex count if necessary
 2025|      0|        if (pMesh.mBitangents.size() < pMesh.mPositions.size() - 1) {
  ------------------
  |  Branch (2025:13): [True: 0, False: 0]
  ------------------
 2026|      0|            pMesh.mBitangents.insert(pMesh.mBitangents.end(), pMesh.mPositions.size() - pMesh.mBitangents.size() - 1, aiVector3D(0, 0, 1));
 2027|      0|        }
 2028|       |
 2029|       |        // ignore all bitangent streams except 0 - there can be only one bitangent
 2030|      0|        if (pInput.mIndex == 0) {
  ------------------
  |  Branch (2030:13): [True: 0, False: 0]
  ------------------
 2031|      0|            pMesh.mBitangents.emplace_back(obj[0], obj[1], obj[2]);
 2032|      0|        } else {
 2033|      0|            ASSIMP_LOG_ERROR("Collada: just one vertex bitangent stream supported");
 2034|      0|        }
 2035|      0|        break;
 2036|  70.0k|    case IT_Texcoord:
  ------------------
  |  Branch (2036:5): [True: 70.0k, False: 226k]
  ------------------
 2037|       |        // up to 4 texture coord sets are fine, ignore the others
 2038|  70.0k|        if (pInput.mIndex < AI_MAX_NUMBER_OF_TEXTURECOORDS) {
  ------------------
  |  Branch (2038:13): [True: 70.0k, False: 0]
  ------------------
 2039|       |            // pad to current vertex count if necessary
 2040|  70.0k|            if (pMesh.mTexCoords[pInput.mIndex].size() < pMesh.mPositions.size() - 1)
  ------------------
  |  Branch (2040:17): [True: 0, False: 70.0k]
  ------------------
 2041|      0|                pMesh.mTexCoords[pInput.mIndex].insert(pMesh.mTexCoords[pInput.mIndex].end(),
 2042|      0|                        pMesh.mPositions.size() - pMesh.mTexCoords[pInput.mIndex].size() - 1, aiVector3D(0, 0, 0));
 2043|       |
 2044|  70.0k|            pMesh.mTexCoords[pInput.mIndex].emplace_back(obj[0], obj[1], obj[2]);
 2045|  70.0k|            if (0 != acc.mSubOffset[2] || 0 != acc.mSubOffset[3]) {
  ------------------
  |  Branch (2045:17): [True: 0, False: 70.0k]
  |  Branch (2045:43): [True: 0, False: 70.0k]
  ------------------
 2046|      0|                pMesh.mNumUVComponents[pInput.mIndex] = 3;
 2047|      0|            }
 2048|  70.0k|        } else {
 2049|      0|            ASSIMP_LOG_ERROR("Collada: too many texture coordinate sets. Skipping.");
 2050|      0|        }
 2051|  70.0k|        break;
 2052|    208|    case IT_Color:
  ------------------
  |  Branch (2052:5): [True: 208, False: 296k]
  ------------------
 2053|       |        // up to 4 color sets are fine, ignore the others
 2054|    208|        if (pInput.mIndex < AI_MAX_NUMBER_OF_COLOR_SETS) {
  ------------------
  |  Branch (2054:13): [True: 208, False: 0]
  ------------------
 2055|       |            // pad to current vertex count if necessary
 2056|    208|            if (pMesh.mColors[pInput.mIndex].size() < pMesh.mPositions.size() - 1)
  ------------------
  |  Branch (2056:17): [True: 0, False: 208]
  ------------------
 2057|      0|                pMesh.mColors[pInput.mIndex].insert(pMesh.mColors[pInput.mIndex].end(),
 2058|      0|                        pMesh.mPositions.size() - pMesh.mColors[pInput.mIndex].size() - 1, aiColor4D(0, 0, 0, 1));
 2059|       |
 2060|    208|            aiColor4D result(0, 0, 0, 1);
 2061|    832|            for (size_t i = 0; i < pInput.mResolved->mSize; ++i) {
  ------------------
  |  Branch (2061:32): [True: 624, False: 208]
  ------------------
 2062|    624|                result[static_cast<unsigned int>(i)] = obj[pInput.mResolved->mSubOffset[i]];
 2063|    624|            }
 2064|    208|            pMesh.mColors[pInput.mIndex].push_back(result);
 2065|    208|        } else {
 2066|      0|            ASSIMP_LOG_ERROR("Collada: too many vertex color sets. Skipping.");
 2067|      0|        }
 2068|       |
 2069|    208|        break;
 2070|      0|    default:
  ------------------
  |  Branch (2070:5): [True: 0, False: 296k]
  ------------------
 2071|       |        // IT_Invalid and IT_Vertex
 2072|      0|        ai_assert(false && "shouldn't ever get here");
  ------------------
  |  |   67|      0|#   define ai_assert(expression) (void)((!!(expression)) || (Assimp::aiAssertViolation(#expression, __FILE__, __LINE__), 0))
  |  |  ------------------
  |  |  |  Branch (67:45): [Folded, False: 0]
  |  |  |  Branch (67:45): [True: 0, Folded]
  |  |  |  Branch (67:61): [True: 0, False: 0]
  |  |  ------------------
  ------------------
 2073|   296k|    }
 2074|   296k|}
_ZN6Assimp13ColladaParser16ReadSceneLibraryERN4pugi8xml_nodeE:
 2078|     18|void ColladaParser::ReadSceneLibrary(XmlNode &node) {
 2079|     18|    if (node.empty()) {
  ------------------
  |  Branch (2079:9): [True: 0, False: 18]
  ------------------
 2080|      0|        return;
 2081|      0|    }
 2082|       |
 2083|     18|    for (XmlNode &currentNode : node.children()) {
  ------------------
  |  Branch (2083:31): [True: 18, False: 18]
  ------------------
 2084|     18|        const std::string &currentName = currentNode.name();
 2085|     18|        if (currentName == "visual_scene") {
  ------------------
  |  Branch (2085:13): [True: 18, False: 0]
  ------------------
 2086|       |            // read ID. Is optional according to the spec, but how on earth should a scene_instance refer to it then?
 2087|     18|            std::string id;
 2088|     18|            XmlParser::getStdStrAttribute(currentNode, "id", id);
 2089|       |
 2090|       |            // read name if given.
 2091|     18|            std::string attrName = "Scene";
 2092|     18|            if (XmlParser::hasAttribute(currentNode, "name")) {
  ------------------
  |  Branch (2092:17): [True: 17, False: 1]
  ------------------
 2093|     17|                XmlParser::getStdStrAttribute(currentNode, "name", attrName);
 2094|     17|            }
 2095|       |
 2096|       |            // create a node and store it in the library under its ID
 2097|     18|            Node *sceneNode = new Node;
 2098|     18|            sceneNode->mID = id;
 2099|     18|            sceneNode->mName = attrName;
 2100|     18|            mNodeLibrary[sceneNode->mID] = sceneNode;
 2101|       |
 2102|     18|            ReadSceneNode(currentNode, sceneNode);
 2103|     18|        }
 2104|     18|    }
 2105|     18|}
_ZN6Assimp13ColladaParser13ReadSceneNodeERN4pugi8xml_nodeEPNS_7Collada4NodeE:
 2109|    333|void ColladaParser::ReadSceneNode(XmlNode &node, Node *pNode) {
 2110|       |    // quit immediately on <bla/> elements
 2111|    333|    if (node.empty()) {
  ------------------
  |  Branch (2111:9): [True: 0, False: 333]
  ------------------
 2112|      0|        return;
 2113|      0|    }
 2114|       |
 2115|  1.41k|    for (XmlNode &currentNode : node.children()) {
  ------------------
  |  Branch (2115:31): [True: 1.41k, False: 333]
  ------------------
 2116|  1.41k|        const std::string &currentName = currentNode.name();
 2117|  1.41k|        if (currentName == "node") {
  ------------------
  |  Branch (2117:13): [True: 315, False: 1.10k]
  ------------------
 2118|    315|            Node *child = new Node;
 2119|    315|            if (XmlParser::hasAttribute(currentNode, "id")) {
  ------------------
  |  Branch (2119:17): [True: 315, False: 0]
  ------------------
 2120|    315|                XmlParser::getStdStrAttribute(currentNode, "id", child->mID);
 2121|    315|            }
 2122|    315|            if (XmlParser::hasAttribute(currentNode, "sid")) {
  ------------------
  |  Branch (2122:17): [True: 138, False: 177]
  ------------------
 2123|    138|                XmlParser::getStdStrAttribute(currentNode, "sid", child->mSID);
 2124|    138|            }
 2125|    315|            if (XmlParser::hasAttribute(currentNode, "name")) {
  ------------------
  |  Branch (2125:17): [True: 315, False: 0]
  ------------------
 2126|    315|                XmlParser::getStdStrAttribute(currentNode, "name", child->mName);
 2127|    315|            }
 2128|    315|            if (pNode) {
  ------------------
  |  Branch (2128:17): [True: 315, False: 0]
  ------------------
 2129|    315|                pNode->mChildren.push_back(child);
 2130|    315|                child->mParent = pNode;
 2131|    315|            } else {
 2132|       |                // no parent node given, probably called from <library_nodes> element.
 2133|       |                // create new node in node library
 2134|      0|                mNodeLibrary[child->mID] = child;
 2135|      0|            }
 2136|       |
 2137|       |            // read on recursively from there
 2138|    315|            ReadSceneNode(currentNode, child);
 2139|    315|            continue;
 2140|  1.10k|        } else if (!pNode) {
  ------------------
  |  Branch (2140:20): [True: 0, False: 1.10k]
  ------------------
 2141|       |            // For any further stuff we need a valid node to work on
 2142|      0|            continue;
 2143|      0|        }
 2144|  1.10k|        if (currentName == "lookat") {
  ------------------
  |  Branch (2144:13): [True: 0, False: 1.10k]
  ------------------
 2145|      0|            ReadNodeTransformation(currentNode, pNode, TF_LOOKAT);
 2146|  1.10k|        } else if (currentName == "matrix") {
  ------------------
  |  Branch (2146:20): [True: 19, False: 1.08k]
  ------------------
 2147|     19|            ReadNodeTransformation(currentNode, pNode, TF_MATRIX);
 2148|  1.08k|        } else if (currentName == "rotate") {
  ------------------
  |  Branch (2148:20): [True: 618, False: 467]
  ------------------
 2149|    618|            ReadNodeTransformation(currentNode, pNode, TF_ROTATE);
 2150|    618|        } else if (currentName == "scale") {
  ------------------
  |  Branch (2150:20): [True: 5, False: 462]
  ------------------
 2151|      5|            ReadNodeTransformation(currentNode, pNode, TF_SCALE);
 2152|    462|        } else if (currentName == "skew") {
  ------------------
  |  Branch (2152:20): [True: 0, False: 462]
  ------------------
 2153|      0|            ReadNodeTransformation(currentNode, pNode, TF_SKEW);
 2154|    462|        } else if (currentName == "translate") {
  ------------------
  |  Branch (2154:20): [True: 157, False: 305]
  ------------------
 2155|    157|            ReadNodeTransformation(currentNode, pNode, TF_TRANSLATE);
 2156|    305|        } else if (currentName == "render" && pNode->mParent == nullptr && 0 == pNode->mPrimaryCamera.length()) {
  ------------------
  |  Branch (2156:20): [True: 0, False: 305]
  |  Branch (2156:47): [True: 0, False: 0]
  |  Branch (2156:76): [True: 0, False: 0]
  ------------------
 2157|       |            // ... scene evaluation or, in other words, postprocessing pipeline,
 2158|       |            // or, again in other words, a turing-complete description how to
 2159|       |            // render a Collada scene. The only thing that is interesting for
 2160|       |            // us is the primary camera.
 2161|      0|            if (XmlParser::hasAttribute(currentNode, "camera_node")) {
  ------------------
  |  Branch (2161:17): [True: 0, False: 0]
  ------------------
 2162|      0|                std::string s;
 2163|      0|                XmlParser::getStdStrAttribute(currentNode, "camera_node", s);
 2164|      0|                if (s[0] != '#') {
  ------------------
  |  Branch (2164:21): [True: 0, False: 0]
  ------------------
 2165|      0|                    ASSIMP_LOG_ERROR("Collada: Unresolved reference format of camera");
 2166|      0|                } else {
 2167|      0|                    pNode->mPrimaryCamera = s.c_str() + 1;
 2168|      0|                }
 2169|      0|            }
 2170|    305|        } else if (currentName == "instance_node") {
  ------------------
  |  Branch (2170:20): [True: 0, False: 305]
  ------------------
 2171|       |            // find the node in the library
 2172|      0|            if (XmlParser::hasAttribute(currentNode, "url")) {
  ------------------
  |  Branch (2172:17): [True: 0, False: 0]
  ------------------
 2173|      0|                std::string s;
 2174|      0|                XmlParser::getStdStrAttribute(currentNode, "url", s);
 2175|      0|                if (s[0] != '#') {
  ------------------
  |  Branch (2175:21): [True: 0, False: 0]
  ------------------
 2176|      0|                    ASSIMP_LOG_ERROR("Collada: Unresolved reference format of node");
 2177|      0|                } else {
 2178|      0|                    pNode->mNodeInstances.emplace_back();
 2179|      0|                    pNode->mNodeInstances.back().mNode = s.c_str() + 1;
 2180|      0|                }
 2181|      0|            }
 2182|    305|        } else if (currentName == "instance_geometry" || currentName == "instance_controller") {
  ------------------
  |  Branch (2182:20): [True: 148, False: 157]
  |  Branch (2182:58): [True: 2, False: 155]
  ------------------
 2183|       |            // Reference to a mesh or controller, with possible material associations
 2184|    150|            ReadNodeGeometry(currentNode, pNode);
 2185|    155|        } else if (currentName == "instance_light") {
  ------------------
  |  Branch (2185:20): [True: 15, False: 140]
  ------------------
 2186|       |            // Reference to a light, name given in 'url' attribute
 2187|     15|            if (XmlParser::hasAttribute(currentNode, "url")) {
  ------------------
  |  Branch (2187:17): [True: 15, False: 0]
  ------------------
 2188|     15|                std::string url;
 2189|     15|                XmlParser::getStdStrAttribute(currentNode, "url", url);
 2190|     15|                if (url[0] != '#') {
  ------------------
  |  Branch (2190:21): [True: 0, False: 15]
  ------------------
 2191|      0|                    throw DeadlyImportError("Unknown reference format in <instance_light> element");
 2192|      0|                }
 2193|       |
 2194|     15|                pNode->mLights.emplace_back();
 2195|     15|                pNode->mLights.back().mLight = url.c_str() + 1;
 2196|     15|            }
 2197|    140|        } else if (currentName == "instance_camera") {
  ------------------
  |  Branch (2197:20): [True: 10, False: 130]
  ------------------
 2198|       |            // Reference to a camera, name given in 'url' attribute
 2199|     10|            if (XmlParser::hasAttribute(currentNode, "url")) {
  ------------------
  |  Branch (2199:17): [True: 10, False: 0]
  ------------------
 2200|     10|                std::string url;
 2201|     10|                XmlParser::getStdStrAttribute(currentNode, "url", url);
 2202|     10|                if (url[0] != '#') {
  ------------------
  |  Branch (2202:21): [True: 0, False: 10]
  ------------------
 2203|      0|                    throw DeadlyImportError("Unknown reference format in <instance_camera> element");
 2204|      0|                }
 2205|     10|                pNode->mCameras.emplace_back();
 2206|     10|                pNode->mCameras.back().mCamera = url.c_str() + 1;
 2207|     10|            }
 2208|     10|        }
 2209|  1.10k|    }
 2210|    333|}
_ZN6Assimp13ColladaParser30ReadMaterialVertexInputBindingERN4pugi8xml_nodeERNS_7Collada20SemanticMappingTableE:
 2215|     29|void ColladaParser::ReadMaterialVertexInputBinding(XmlNode &node, Collada::SemanticMappingTable &tbl) {
 2216|     29|    std::string name = node.name();
 2217|     29|    for (XmlNode &currentNode : node.children()) {
  ------------------
  |  Branch (2217:31): [True: 14, False: 29]
  ------------------
 2218|     14|        const std::string &currentName = currentNode.name();
 2219|     14|        if (currentName == "bind_vertex_input") {
  ------------------
  |  Branch (2219:13): [True: 14, False: 0]
  ------------------
 2220|     14|            Collada::InputSemanticMapEntry vn;
 2221|       |
 2222|       |            // effect semantic
 2223|     14|            if (XmlParser::hasAttribute(currentNode, "semantic")) {
  ------------------
  |  Branch (2223:17): [True: 14, False: 0]
  ------------------
 2224|     14|                std::string s;
 2225|     14|                XmlParser::getStdStrAttribute(currentNode, "semantic", s);
 2226|     14|                XmlParser::getUIntAttribute(currentNode, "input_semantic", (unsigned int &)vn.mType);
 2227|     14|            }
 2228|     14|            std::string s;
 2229|     14|            XmlParser::getStdStrAttribute(currentNode, "semantic", s);
 2230|       |
 2231|       |            // input semantic
 2232|     14|            XmlParser::getUIntAttribute(currentNode, "input_semantic", (unsigned int &)vn.mType);
 2233|       |
 2234|       |            // index of input set
 2235|     14|            if (XmlParser::hasAttribute(currentNode, "input_set")) {
  ------------------
  |  Branch (2235:17): [True: 14, False: 0]
  ------------------
 2236|     14|                XmlParser::getUIntAttribute(currentNode, "input_set", vn.mSet);
 2237|     14|            }
 2238|       |
 2239|     14|            tbl.mMap[s] = vn;
 2240|     14|        } else if (currentName == "bind") {
  ------------------
  |  Branch (2240:20): [True: 0, False: 0]
  ------------------
 2241|       |            ASSIMP_LOG_WARN("Collada: Found unsupported <bind> element");
 2242|      0|        }
 2243|     14|    }
 2244|     29|}
_ZN6Assimp13ColladaParser20ReadEmbeddedTexturesERNS_18ZipArchiveIOSystemE:
 2246|      2|void ColladaParser::ReadEmbeddedTextures(ZipArchiveIOSystem &zip_archive) {
 2247|       |    // Attempt to load any undefined Collada::Image in ImageLibrary
 2248|      2|    for (auto &it : mImageLibrary) {
  ------------------
  |  Branch (2248:19): [True: 2, False: 2]
  ------------------
 2249|      2|        if (Image &image = it.second; image.mImageData.empty()) {
  ------------------
  |  Branch (2249:39): [True: 2, False: 0]
  ------------------
 2250|      2|            std::unique_ptr<IOStream> image_file(zip_archive.Open(image.mFileName.c_str()));
 2251|      2|            if (image_file) {
  ------------------
  |  Branch (2251:17): [True: 2, False: 0]
  ------------------
 2252|      2|                image.mImageData.resize(image_file->FileSize());
 2253|      2|                image_file->Read(image.mImageData.data(), image_file->FileSize(), 1);
 2254|      2|                image.mEmbeddedFormat = BaseImporter::GetExtension(image.mFileName);
 2255|      2|                if (image.mEmbeddedFormat == "jpeg") {
  ------------------
  |  Branch (2255:21): [True: 0, False: 2]
  ------------------
 2256|      0|                    image.mEmbeddedFormat = "jpg";
 2257|      0|                }
 2258|      2|            }
 2259|      2|        }
 2260|      2|    }
 2261|      2|}
_ZN6Assimp13ColladaParser16ReadNodeGeometryERN4pugi8xml_nodeEPNS_7Collada4NodeE:
 2265|    150|void ColladaParser::ReadNodeGeometry(XmlNode &node, Node *pNode) {
 2266|       |    // referred mesh is given as an attribute of the <instance_geometry> element
 2267|    150|    std::string url;
 2268|    150|    XmlParser::getStdStrAttribute(node, "url", url);
 2269|    150|    if (url[0] != '#') {
  ------------------
  |  Branch (2269:9): [True: 0, False: 150]
  ------------------
 2270|      0|        throw DeadlyImportError("Unknown reference format");
 2271|      0|    }
 2272|       |
 2273|    150|    Collada::MeshInstance instance;
 2274|    150|    instance.mMeshOrController = url.c_str() + 1; // skipping the leading #
 2275|       |
 2276|    173|    for (XmlNode currentNode = node.first_child(); currentNode; currentNode = currentNode.next_sibling()) {
  ------------------
  |  Branch (2276:52): [True: 23, False: 150]
  ------------------
 2277|     23|        const std::string &currentName = currentNode.name();
 2278|     23|        if (currentName == "bind_material") {
  ------------------
  |  Branch (2278:13): [True: 21, False: 2]
  ------------------
 2279|     21|            XmlNode techNode = currentNode.child("technique_common");
 2280|     21|            if (techNode) {
  ------------------
  |  Branch (2280:17): [True: 21, False: 0]
  ------------------
 2281|     50|                for (XmlNode instanceMatNode = techNode.child("instance_material"); instanceMatNode; instanceMatNode = instanceMatNode.next_sibling())
  ------------------
  |  Branch (2281:85): [True: 29, False: 21]
  ------------------
 2282|     29|                {
 2283|     29|                    const std::string &instance_name = instanceMatNode.name();
 2284|     29|                    if (instance_name == "instance_material")
  ------------------
  |  Branch (2284:25): [True: 29, False: 0]
  ------------------
 2285|     29|                    {
 2286|       |                        // read ID of the geometry subgroup and the target material
 2287|     29|                        std::string group;
 2288|     29|                        XmlParser::getStdStrAttribute(instanceMatNode, "symbol", group);
 2289|     29|                        XmlParser::getStdStrAttribute(instanceMatNode, "target", url);
 2290|     29|                        const char *urlMat = url.c_str();
 2291|     29|                        Collada::SemanticMappingTable s;
 2292|     29|                        if (urlMat[0] == '#')
  ------------------
  |  Branch (2292:29): [True: 29, False: 0]
  ------------------
 2293|     29|                            urlMat++;
 2294|       |
 2295|     29|                        s.mMatName = urlMat;
 2296|     29|                        ReadMaterialVertexInputBinding(instanceMatNode, s);
 2297|       |                        // store the association
 2298|     29|                        instance.mMaterials[group] = s;
 2299|     29|                    }
 2300|     29|                }
 2301|     21|            }
 2302|     21|        }
 2303|     23|    }
 2304|       |
 2305|       |    // store it
 2306|    150|    pNode->mMeshes.push_back(instance);
 2307|    150|}
_ZN6Assimp13ColladaParser9ReadSceneERN4pugi8xml_nodeE:
 2311|     17|void ColladaParser::ReadScene(XmlNode &node) {
 2312|     17|    if (node.empty()) {
  ------------------
  |  Branch (2312:9): [True: 0, False: 17]
  ------------------
 2313|      0|        return;
 2314|      0|    }
 2315|       |
 2316|     17|    for (XmlNode &currentNode : node.children()) {
  ------------------
  |  Branch (2316:31): [True: 17, False: 16]
  ------------------
 2317|     17|        const std::string &currentName = currentNode.name();
 2318|     17|        if (currentName == "instance_visual_scene") {
  ------------------
  |  Branch (2318:13): [True: 17, False: 0]
  ------------------
 2319|       |            // should be the first and only occurrence
 2320|     17|            if (mRootNode) {
  ------------------
  |  Branch (2320:17): [True: 0, False: 17]
  ------------------
 2321|      0|                throw DeadlyImportError("Invalid scene containing multiple root nodes in <instance_visual_scene> element");
 2322|      0|            }
 2323|       |
 2324|       |            // read the url of the scene to instance. Should be of format "#some_name"
 2325|     17|            std::string url;
 2326|     17|            XmlParser::getStdStrAttribute(currentNode, "url", url);
 2327|     17|            if (url[0] != '#') {
  ------------------
  |  Branch (2327:17): [True: 0, False: 17]
  ------------------
 2328|      0|                throw DeadlyImportError("Unknown reference format in <instance_visual_scene> element");
 2329|      0|            }
 2330|       |
 2331|       |            // find the referred scene, skip the leading #
 2332|     17|            auto sit = mNodeLibrary.find(url.c_str() + 1);
 2333|     17|            if (sit == mNodeLibrary.end()) {
  ------------------
  |  Branch (2333:17): [True: 1, False: 16]
  ------------------
 2334|      1|                throw DeadlyImportError("Unable to resolve visual_scene reference \"", std::string(std::move(url)), "\" in <instance_visual_scene> element.");
 2335|      1|            }
 2336|     16|            mRootNode = sit->second;
 2337|     16|        }
 2338|     17|    }
 2339|     17|}
_ZNK6Assimp13ColladaParser24CalculateResultTransformERKNSt3__16vectorINS_7Collada9TransformENS1_9allocatorIS4_EEEE:
 2343|    732|aiMatrix4x4 ColladaParser::CalculateResultTransform(const std::vector<Transform> &pTransforms) const {
 2344|    732|    aiMatrix4x4 res;
 2345|       |
 2346|  2.38k|    for (std::vector<Transform>::const_iterator it = pTransforms.begin(); it != pTransforms.end(); ++it) {
  ------------------
  |  Branch (2346:75): [True: 1.64k, False: 732]
  ------------------
 2347|  1.64k|        const Transform &tf = *it;
 2348|  1.64k|        switch (tf.mType) {
 2349|      0|        case TF_LOOKAT: {
  ------------------
  |  Branch (2349:9): [True: 0, False: 1.64k]
  ------------------
 2350|      0|            aiVector3D pos(tf.f[0], tf.f[1], tf.f[2]);
 2351|      0|            aiVector3D dstPos(tf.f[3], tf.f[4], tf.f[5]);
 2352|      0|            aiVector3D up = aiVector3D(tf.f[6], tf.f[7], tf.f[8]).Normalize();
 2353|      0|            aiVector3D dir = aiVector3D(dstPos - pos).Normalize();
 2354|      0|            aiVector3D right = (dir ^ up).Normalize();
 2355|       |
 2356|      0|            res *= aiMatrix4x4(
 2357|      0|                    right.x, up.x, -dir.x, pos.x,
 2358|      0|                    right.y, up.y, -dir.y, pos.y,
 2359|      0|                    right.z, up.z, -dir.z, pos.z,
 2360|      0|                    0, 0, 0, 1);
 2361|      0|            break;
 2362|      0|        }
 2363|  1.32k|        case TF_ROTATE: {
  ------------------
  |  Branch (2363:9): [True: 1.32k, False: 326]
  ------------------
 2364|  1.32k|            aiMatrix4x4 rot;
 2365|  1.32k|            ai_real angle = tf.f[3] * ai_real(AI_MATH_PI) / ai_real(180.0);
 2366|  1.32k|            aiVector3D axis(tf.f[0], tf.f[1], tf.f[2]);
 2367|  1.32k|            aiMatrix4x4::Rotation(angle, axis, rot);
 2368|  1.32k|            res *= rot;
 2369|  1.32k|            break;
 2370|      0|        }
 2371|     93|        case TF_TRANSLATE: {
  ------------------
  |  Branch (2371:9): [True: 93, False: 1.55k]
  ------------------
 2372|     93|            aiMatrix4x4 trans;
 2373|     93|            aiMatrix4x4::Translation(aiVector3D(tf.f[0], tf.f[1], tf.f[2]), trans);
 2374|     93|            res *= trans;
 2375|     93|            break;
 2376|      0|        }
 2377|      5|        case TF_SCALE: {
  ------------------
  |  Branch (2377:9): [True: 5, False: 1.64k]
  ------------------
 2378|      5|            aiMatrix4x4 scale(tf.f[0], 0.0f, 0.0f, 0.0f, 0.0f, tf.f[1], 0.0f, 0.0f, 0.0f, 0.0f, tf.f[2], 0.0f,
 2379|      5|                    0.0f, 0.0f, 0.0f, 1.0f);
 2380|      5|            res *= scale;
 2381|      5|            break;
 2382|      0|        }
 2383|      0|        case TF_SKEW:
  ------------------
  |  Branch (2383:9): [True: 0, False: 1.64k]
  ------------------
 2384|       |            // TODO: (thom)
 2385|      0|            ai_assert(false);
  ------------------
  |  |   67|      0|#   define ai_assert(expression) (void)((!!(expression)) || (Assimp::aiAssertViolation(#expression, __FILE__, __LINE__), 0))
  |  |  ------------------
  |  |  |  Branch (67:41): [Folded, False: 0]
  |  |  |  Branch (67:61): [True: 0, False: 0]
  |  |  ------------------
  ------------------
 2386|      0|            break;
 2387|    228|        case TF_MATRIX: {
  ------------------
  |  Branch (2387:9): [True: 228, False: 1.42k]
  ------------------
 2388|    228|            aiMatrix4x4 mat(tf.f[0], tf.f[1], tf.f[2], tf.f[3], tf.f[4], tf.f[5], tf.f[6], tf.f[7],
 2389|    228|                    tf.f[8], tf.f[9], tf.f[10], tf.f[11], tf.f[12], tf.f[13], tf.f[14], tf.f[15]);
 2390|    228|            res *= mat;
 2391|    228|            break;
 2392|      0|        }
 2393|      0|        default:
  ------------------
  |  Branch (2393:9): [True: 0, False: 1.64k]
  ------------------
 2394|      0|            ai_assert(false);
  ------------------
  |  |   67|      0|#   define ai_assert(expression) (void)((!!(expression)) || (Assimp::aiAssertViolation(#expression, __FILE__, __LINE__), 0))
  |  |  ------------------
  |  |  |  Branch (67:41): [Folded, False: 0]
  |  |  |  Branch (67:61): [True: 0, False: 0]
  |  |  ------------------
  ------------------
 2395|      0|            break;
 2396|  1.64k|        }
 2397|  1.64k|    }
 2398|       |
 2399|    732|    return res;
 2400|    732|}
_ZN6Assimp13ColladaParser18GetTypeForSemanticERKNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEE:
 2404|    647|InputType ColladaParser::GetTypeForSemantic(const std::string &semantic) {
 2405|    647|    if (semantic.empty()) {
  ------------------
  |  Branch (2405:9): [True: 0, False: 647]
  ------------------
 2406|      0|        ASSIMP_LOG_WARN("Vertex input type is empty.");
 2407|      0|        return IT_Invalid;
 2408|      0|    }
 2409|       |
 2410|    647|    if (semantic == "POSITION")
  ------------------
  |  Branch (2410:9): [True: 158, False: 489]
  ------------------
 2411|    158|        return IT_Position;
 2412|    489|    else if (semantic == "TEXCOORD")
  ------------------
  |  Branch (2412:14): [True: 157, False: 332]
  ------------------
 2413|    157|        return IT_Texcoord;
 2414|    332|    else if (semantic == "NORMAL")
  ------------------
  |  Branch (2414:14): [True: 167, False: 165]
  ------------------
 2415|    167|        return IT_Normal;
 2416|    165|    else if (semantic == "COLOR")
  ------------------
  |  Branch (2416:14): [True: 2, False: 163]
  ------------------
 2417|      2|        return IT_Color;
 2418|    163|    else if (semantic == "VERTEX")
  ------------------
  |  Branch (2418:14): [True: 163, False: 0]
  ------------------
 2419|    163|        return IT_Vertex;
 2420|      0|    else if (semantic == "BINORMAL" || semantic == "TEXBINORMAL")
  ------------------
  |  Branch (2420:14): [True: 0, False: 0]
  |  Branch (2420:40): [True: 0, False: 0]
  ------------------
 2421|      0|        return IT_Bitangent;
 2422|      0|    else if (semantic == "TANGENT" || semantic == "TEXTANGENT")
  ------------------
  |  Branch (2422:14): [True: 0, False: 0]
  |  Branch (2422:39): [True: 0, False: 0]
  ------------------
 2423|      0|        return IT_Tangent;
 2424|       |
 2425|    647|    ASSIMP_LOG_WARN("Unknown vertex input type \"", semantic, "\". Ignoring.");
 2426|      0|    return IT_Invalid;
 2427|    647|}
ColladaParser.cpp:_ZL16ReadMetaDataItemRN4pugi8xml_nodeERNSt3__13mapINS2_12basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEE8aiStringNS2_4lessIS9_EENS7_INS2_4pairIKS9_SA_EEEEEE:
  141|    232|static void ReadMetaDataItem(XmlNode &node, ColladaParser::StringMetaData &metadata) {
  142|    232|    const MetaKeyPairVector &key_renaming = GetColladaAssimpMetaKeysCamelCase();
  143|    232|    const std::string name = node.name();
  144|    232|    if (name.empty()) {
  ------------------
  |  Branch (144:9): [True: 0, False: 232]
  ------------------
  145|      0|        return;
  146|      0|    }
  147|       |
  148|    232|    std::string v;
  149|    232|    if (!XmlParser::getValueAsString(node, v)) {
  ------------------
  |  Branch (149:9): [True: 0, False: 232]
  ------------------
  150|      0|        return;
  151|      0|    }
  152|       |
  153|    232|    v = ai_trim(v);
  154|    232|    aiString aistr;
  155|    232|    aistr.Set(v);
  156|       |
  157|    232|    std::string camel_key_str(name);
  158|    232|    ToCamelCase(camel_key_str);
  159|       |
  160|    232|    size_t found_index;
  161|    232|    if (FindCommonKey(camel_key_str, key_renaming, found_index)) {
  ------------------
  |  Branch (161:9): [True: 41, False: 191]
  ------------------
  162|     41|        metadata.emplace(key_renaming[found_index].second, aistr);
  163|    191|    } else {
  164|    191|        metadata.emplace(camel_key_str, aistr);
  165|    191|    }
  166|    232|}
ColladaParser.cpp:_ZL13FindCommonKeyRKNSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEEERKNS_6vectorINS_4pairIS5_S5_EENS3_ISA_EEEERm:
   80|    232|static bool FindCommonKey(const std::string &collada_key, const MetaKeyPairVector &key_renaming, size_t &found_index) {
   81|    625|    for (size_t i = 0; i < key_renaming.size(); ++i) {
  ------------------
  |  Branch (81:24): [True: 434, False: 191]
  ------------------
   82|    434|        if (key_renaming[i].first == collada_key) {
  ------------------
  |  Branch (82:13): [True: 41, False: 393]
  ------------------
   83|     41|            found_index = i;
   84|     41|            return true;
   85|     41|        }
   86|    434|    }
   87|    191|    found_index = std::numeric_limits<size_t>::max();
   88|       |
   89|    191|    return false;
   90|    232|}
ColladaParser.cpp:_ZL16readUrlAttributeRN4pugi8xml_nodeERNSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEE:
   93|     36|static void readUrlAttribute(XmlNode &node, std::string &url) {
   94|     36|    url.clear();
   95|     36|    if (!XmlParser::getStdStrAttribute(node, "url", url)) {
  ------------------
  |  Branch (95:9): [True: 0, False: 36]
  ------------------
   96|      0|        return;
   97|      0|    }
   98|     36|    if (url[0] != '#') {
  ------------------
  |  Branch (98:9): [True: 0, False: 36]
  ------------------
   99|      0|        throw DeadlyImportError("Unknown reference format");
  100|      0|    }
  101|     36|    url = url.c_str() + 1;
  102|     36|}
ColladaParser.cpp:_ZL20ReadAnimationSamplerRKN4pugi8xml_nodeERN6Assimp7Collada16AnimationChannelE:
  170|    397|static void ReadAnimationSampler(const XmlNode &node, AnimationChannel &pChannel) {
  171|  1.19k|    for (XmlNode &currentNode : node.children()) {
  ------------------
  |  Branch (171:31): [True: 1.19k, False: 397]
  ------------------
  172|  1.19k|        const std::string &currentName = currentNode.name();
  173|  1.19k|        if (currentName == "input") {
  ------------------
  |  Branch (173:13): [True: 1.19k, False: 0]
  ------------------
  174|  1.19k|            if (XmlParser::hasAttribute(currentNode, "semantic")) {
  ------------------
  |  Branch (174:17): [True: 1.19k, False: 0]
  ------------------
  175|  1.19k|                std::string semantic, sourceAttr;
  176|  1.19k|                XmlParser::getStdStrAttribute(currentNode, "semantic", semantic);
  177|  1.19k|                if (XmlParser::hasAttribute(currentNode, "source")) {
  ------------------
  |  Branch (177:21): [True: 1.19k, False: 0]
  ------------------
  178|  1.19k|                    XmlParser::getStdStrAttribute(currentNode, "source", sourceAttr);
  179|  1.19k|                    const char *source = sourceAttr.c_str();
  180|  1.19k|                    if (source[0] != '#') {
  ------------------
  |  Branch (180:25): [True: 0, False: 1.19k]
  ------------------
  181|      0|                        throw DeadlyImportError("Unsupported URL format");
  182|      0|                    }
  183|  1.19k|                    source++;
  184|       |
  185|  1.19k|                    if (semantic == "INPUT") {
  ------------------
  |  Branch (185:25): [True: 397, False: 794]
  ------------------
  186|    397|                        pChannel.mSourceTimes = source;
  187|    794|                    } else if (semantic == "OUTPUT") {
  ------------------
  |  Branch (187:32): [True: 397, False: 397]
  ------------------
  188|    397|                        pChannel.mSourceValues = source;
  189|    397|                    } else if (semantic == "IN_TANGENT") {
  ------------------
  |  Branch (189:32): [True: 0, False: 397]
  ------------------
  190|      0|                        pChannel.mInTanValues = source;
  191|    397|                    } else if (semantic == "OUT_TANGENT") {
  ------------------
  |  Branch (191:32): [True: 0, False: 397]
  ------------------
  192|      0|                        pChannel.mOutTanValues = source;
  193|    397|                    } else if (semantic == "INTERPOLATION") {
  ------------------
  |  Branch (193:32): [True: 397, False: 0]
  ------------------
  194|    397|                        pChannel.mInterpolationValues = source;
  195|    397|                    }
  196|  1.19k|                }
  197|  1.19k|            }
  198|  1.19k|        }
  199|  1.19k|    }
  200|    397|}
ColladaParser.cpp:_ZL20ReadControllerJointsRKN4pugi8xml_nodeERN6Assimp7Collada10ControllerE:
  204|      2|static void ReadControllerJoints(const XmlNode &node, Controller &pController) {
  205|      4|    for (XmlNode &currentNode : node.children()) {
  ------------------
  |  Branch (205:31): [True: 4, False: 2]
  ------------------
  206|      4|        const std::string &currentName = currentNode.name();
  207|      4|        if (currentName == "input") {
  ------------------
  |  Branch (207:13): [True: 4, False: 0]
  ------------------
  208|      4|            const char *attrSemantic = currentNode.attribute("semantic").as_string();
  209|      4|            const char *attrSource = currentNode.attribute("source").as_string();
  210|      4|            if (attrSource[0] != '#') {
  ------------------
  |  Branch (210:17): [True: 0, False: 4]
  ------------------
  211|      0|                throw DeadlyImportError("Unsupported URL format in \"", attrSource, "\" in source attribute of <joints> data <input> element");
  212|      0|            }
  213|      4|            ++attrSource;
  214|       |            // parse source URL to corresponding source
  215|      4|            if (strcmp(attrSemantic, "JOINT") == 0) {
  ------------------
  |  Branch (215:17): [True: 2, False: 2]
  ------------------
  216|      2|                pController.mJointNameSource = attrSource;
  217|      2|            } else if (strcmp(attrSemantic, "INV_BIND_MATRIX") == 0) {
  ------------------
  |  Branch (217:24): [True: 2, False: 0]
  ------------------
  218|      2|                pController.mJointOffsetMatrixSource = attrSource;
  219|      2|            } else {
  220|      0|                throw DeadlyImportError("Unknown semantic \"", attrSemantic, "\" in <joints> data <input> element");
  221|      0|            }
  222|      4|        }
  223|      4|    }
  224|      2|}
ColladaParser.cpp:_ZL21ReadControllerWeightsRN4pugi8xml_nodeERN6Assimp7Collada10ControllerE:
  294|      2|static void ReadControllerWeights(XmlNode &node, Controller &pController) {
  295|       |    // Read vertex count from attributes and resize the array accordingly
  296|      2|    int vertexCount = 0;
  297|      2|    XmlParser::getIntAttribute(node, "count", vertexCount);
  298|      2|    pController.mWeightCounts.resize(vertexCount);
  299|       |
  300|      8|    for (XmlNode &currentNode : node.children()) {
  ------------------
  |  Branch (300:31): [True: 8, False: 2]
  ------------------
  301|      8|        const std::string &currentName = currentNode.name();
  302|      8|        if (currentName == "input") {
  ------------------
  |  Branch (302:13): [True: 4, False: 4]
  ------------------
  303|      4|            ReadControllerWeightsInput(currentNode, pController);
  304|      4|        } else if (currentName == "vcount" && vertexCount > 0) {
  ------------------
  |  Branch (304:20): [True: 2, False: 2]
  |  Branch (304:47): [True: 2, False: 0]
  ------------------
  305|      2|            ReadControllerWeightsVCount(currentNode, pController);
  306|      2|        } else if (currentName == "v" && vertexCount > 0) {
  ------------------
  |  Branch (306:20): [True: 2, False: 0]
  |  Branch (306:42): [True: 2, False: 0]
  ------------------
  307|      2|            ReadControllerWeightsJoint2verts(currentNode, pController);
  308|      2|        }
  309|      8|    }
  310|      2|}
ColladaParser.cpp:_ZL26ReadControllerWeightsInputRKN4pugi8xml_nodeERN6Assimp7Collada10ControllerE:
  227|      4|static void ReadControllerWeightsInput(const XmlNode &currentNode, Controller &pController) {
  228|      4|    InputChannel channel;
  229|       |
  230|      4|    const char *attrSemantic = currentNode.attribute("semantic").as_string();
  231|      4|    const char *attrSource = currentNode.attribute("source").as_string();
  232|      4|    channel.mOffset = currentNode.attribute("offset").as_int();
  233|       |
  234|       |    // local URLS always start with a '#'. We don't support global URLs
  235|      4|    if (attrSource[0] != '#') {
  ------------------
  |  Branch (235:9): [True: 0, False: 4]
  ------------------
  236|      0|        throw DeadlyImportError("Unsupported URL format in \"", attrSource, "\" in source attribute of <vertex_weights> data <input> element");
  237|      0|    }
  238|      4|    channel.mAccessor = attrSource + 1;
  239|       |
  240|       |    // parse source URL to corresponding source
  241|      4|    if (strcmp(attrSemantic, "JOINT") == 0) {
  ------------------
  |  Branch (241:9): [True: 2, False: 2]
  ------------------
  242|      2|        pController.mWeightInputJoints = channel;
  243|      2|    } else if (strcmp(attrSemantic, "WEIGHT") == 0) {
  ------------------
  |  Branch (243:16): [True: 2, False: 0]
  ------------------
  244|      2|        pController.mWeightInputWeights = channel;
  245|      2|    } else {
  246|      0|        throw DeadlyImportError("Unknown semantic \"", attrSemantic, "\" in <vertex_weights> data <input> element");
  247|      0|    }
  248|      4|}
ColladaParser.cpp:_ZL27ReadControllerWeightsVCountRKN4pugi8xml_nodeERN6Assimp7Collada10ControllerE:
  251|      2|static void ReadControllerWeightsVCount(const XmlNode &currentNode, Controller &pController) {
  252|      2|    const std::string stdText = currentNode.text().as_string();
  253|      2|    const char *text = stdText.c_str();
  254|      2|    const char *end = text + stdText.size();
  255|      2|    size_t numWeights = 0;
  256|    146|    for (auto it = pController.mWeightCounts.begin(); it != pController.mWeightCounts.end(); ++it) {
  ------------------
  |  Branch (256:55): [True: 144, False: 2]
  ------------------
  257|    144|        if (*text == 0) {
  ------------------
  |  Branch (257:13): [True: 0, False: 144]
  ------------------
  258|      0|            throw DeadlyImportError("Out of data while reading <vcount>");
  259|      0|        }
  260|       |
  261|    144|        *it = strtoul10(text, &text);
  262|    144|        numWeights += *it;
  263|    144|        SkipSpacesAndLineEnd(&text, end);
  264|    144|    }
  265|       |    // reserve weight count
  266|      2|    pController.mWeights.resize(numWeights);
  267|      2|}
ColladaParser.cpp:_ZL32ReadControllerWeightsJoint2vertsRN4pugi8xml_nodeERN6Assimp7Collada10ControllerE:
  270|      2|static void ReadControllerWeightsJoint2verts(XmlNode &currentNode, Controller &pController) {
  271|       |    // read JointIndex - WeightIndex pairs
  272|      2|    std::string stdText;
  273|      2|    XmlParser::getValueAsString(currentNode, stdText);
  274|      2|    const char *text = stdText.c_str();
  275|      2|    const char *end = text + stdText.size();
  276|    222|    for (auto it = pController.mWeights.begin(); it != pController.mWeights.end(); ++it) {
  ------------------
  |  Branch (276:50): [True: 220, False: 2]
  ------------------
  277|    220|        if (text == nullptr) {
  ------------------
  |  Branch (277:13): [True: 0, False: 220]
  ------------------
  278|      0|            throw DeadlyImportError("Out of data while reading <vertex_weights>");
  279|      0|        }
  280|    220|        SkipSpacesAndLineEnd(&text, end);
  281|    220|        it->first = strtoul10(text, &text);
  282|    220|        SkipSpacesAndLineEnd(&text, end);
  283|    220|        if (*text == 0) {
  ------------------
  |  Branch (283:13): [True: 0, False: 220]
  ------------------
  284|      0|            throw DeadlyImportError("Out of data while reading <vertex_weights>");
  285|      0|        }
  286|    220|        it->second = strtoul10(text, &text);
  287|    220|        SkipSpacesAndLineEnd(&text, end);
  288|    220|    }
  289|       |
  290|      2|}
ColladaParser.cpp:_ZL12ReadMaterialRKN4pugi8xml_nodeERN6Assimp7Collada8MaterialE:
  314|     36|static void ReadMaterial(const XmlNode &node, Material &pMaterial) {
  315|     36|    for (XmlNode &currentNode : node.children()) {
  ------------------
  |  Branch (315:31): [True: 36, False: 36]
  ------------------
  316|     36|        const std::string &currentName = currentNode.name();
  317|     36|        if (currentName == "instance_effect") {
  ------------------
  |  Branch (317:13): [True: 36, False: 0]
  ------------------
  318|     36|            std::string url;
  319|     36|            readUrlAttribute(currentNode, url);
  320|     36|            pMaterial.mEffect = url;
  321|     36|        }
  322|     36|    }
  323|     36|}
ColladaParser.cpp:_ZL9ReadLightRN4pugi8xml_nodeERN6Assimp7Collada5LightE:
  327|     15|static void ReadLight(XmlNode &node, Light &pLight) {
  328|     15|    XmlNodeIterator xmlIt(node, XmlNodeIterator::PreOrderMode);
  329|     15|    XmlNode currentNode;
  330|       |    // TODO: Check the current technique and skip over unsupported extra techniques
  331|       |
  332|    371|    while (xmlIt.getNext(currentNode)) {
  ------------------
  |  Branch (332:12): [True: 356, False: 15]
  ------------------
  333|    356|        const std::string &currentName = currentNode.name();
  334|    356|        if (currentName == "spot") {
  ------------------
  |  Branch (334:13): [True: 1, False: 355]
  ------------------
  335|      1|            pLight.mType = aiLightSource_SPOT;
  336|    355|        } else if (currentName == "ambient") {
  ------------------
  |  Branch (336:20): [True: 1, False: 354]
  ------------------
  337|      1|            pLight.mType = aiLightSource_AMBIENT;
  338|    354|        } else if (currentName == "directional") {
  ------------------
  |  Branch (338:20): [True: 5, False: 349]
  ------------------
  339|      5|            pLight.mType = aiLightSource_DIRECTIONAL;
  340|    349|        } else if (currentName == "point") {
  ------------------
  |  Branch (340:20): [True: 8, False: 341]
  ------------------
  341|      8|            pLight.mType = aiLightSource_POINT;
  342|    341|        } else if (currentName == "color") {
  ------------------
  |  Branch (342:20): [True: 15, False: 326]
  ------------------
  343|       |            // text content contains 3 floats
  344|     15|            std::string v;
  345|     15|            XmlParser::getValueAsString(currentNode, v);
  346|     15|            const char *content = v.c_str();
  347|     15|            const char *end = content + v.size();
  348|       |
  349|     15|            content = fast_atoreal_move(content, pLight.mColor.r);
  350|     15|            SkipSpacesAndLineEnd(&content, end);
  351|       |
  352|     15|            content = fast_atoreal_move(content, pLight.mColor.g);
  353|     15|            SkipSpacesAndLineEnd(&content, end);
  354|       |
  355|     15|            content = fast_atoreal_move(content, pLight.mColor.b);
  356|     15|            SkipSpacesAndLineEnd(&content, end);
  357|    326|        } else if (currentName == "constant_attenuation") {
  ------------------
  |  Branch (357:20): [True: 9, False: 317]
  ------------------
  358|      9|            XmlParser::getValueAsReal(currentNode, pLight.mAttConstant);
  359|    317|        } else if (currentName == "linear_attenuation") {
  ------------------
  |  Branch (359:20): [True: 9, False: 308]
  ------------------
  360|      9|            XmlParser::getValueAsReal(currentNode, pLight.mAttLinear);
  361|    308|        } else if (currentName == "quadratic_attenuation") {
  ------------------
  |  Branch (361:20): [True: 9, False: 299]
  ------------------
  362|      9|            XmlParser::getValueAsReal(currentNode, pLight.mAttQuadratic);
  363|    299|        } else if (currentName == "falloff_angle") {
  ------------------
  |  Branch (363:20): [True: 1, False: 298]
  ------------------
  364|      1|            XmlParser::getValueAsReal(currentNode, pLight.mFalloffAngle);
  365|    298|        } else if (currentName == "falloff_exponent") {
  ------------------
  |  Branch (365:20): [True: 1, False: 297]
  ------------------
  366|      1|            XmlParser::getValueAsReal(currentNode, pLight.mFalloffExponent);
  367|      1|        }
  368|       |        // FCOLLADA extensions
  369|       |        // -------------------------------------------------------
  370|    297|        else if (currentName == "outer_cone") {
  ------------------
  |  Branch (370:18): [True: 0, False: 297]
  ------------------
  371|      0|            XmlParser::getValueAsReal(currentNode, pLight.mOuterAngle);
  372|    297|        } else if (currentName == "penumbra_angle") { // this one is deprecated, now calculated using outer_cone
  ------------------
  |  Branch (372:20): [True: 0, False: 297]
  ------------------
  373|      0|            XmlParser::getValueAsReal(currentNode, pLight.mPenumbraAngle);
  374|    297|        } else if (currentName == "intensity") {
  ------------------
  |  Branch (374:20): [True: 1, False: 296]
  ------------------
  375|      1|            XmlParser::getValueAsReal(currentNode, pLight.mIntensity);
  376|    296|        } else if (currentName == "falloff") {
  ------------------
  |  Branch (376:20): [True: 0, False: 296]
  ------------------
  377|      0|            XmlParser::getValueAsReal(currentNode, pLight.mOuterAngle);
  378|    296|        } else if (currentName == "hotspot_beam") {
  ------------------
  |  Branch (378:20): [True: 0, False: 296]
  ------------------
  379|      0|            XmlParser::getValueAsReal(currentNode, pLight.mFalloffAngle);
  380|      0|        }
  381|       |        // OpenCOLLADA extensions
  382|       |        // -------------------------------------------------------
  383|    296|        else if (currentName == "decay_falloff") {
  ------------------
  |  Branch (383:18): [True: 0, False: 296]
  ------------------
  384|      0|            XmlParser::getValueAsReal(currentNode, pLight.mOuterAngle);
  385|      0|        }
  386|    356|    }
  387|     15|}
ColladaParser.cpp:_ZL10ReadCameraRN4pugi8xml_nodeERN6Assimp7Collada6CameraE:
  391|     10|static void ReadCamera(XmlNode &node, Camera &camera) {
  392|     10|    XmlNodeIterator xmlIt(node, XmlNodeIterator::PreOrderMode);
  393|     10|    XmlNode currentNode;
  394|     80|    while (xmlIt.getNext(currentNode)) {
  ------------------
  |  Branch (394:12): [True: 70, False: 10]
  ------------------
  395|     70|        const std::string &currentName = currentNode.name();
  396|     70|        if (currentName == "orthographic") {
  ------------------
  |  Branch (396:13): [True: 0, False: 70]
  ------------------
  397|      0|            camera.mOrtho = true;
  398|     70|        } else if (currentName == "xfov" || currentName == "xmag") {
  ------------------
  |  Branch (398:20): [True: 0, False: 70]
  |  Branch (398:45): [True: 0, False: 70]
  ------------------
  399|      0|            XmlParser::getValueAsReal(currentNode, camera.mHorFov);
  400|     70|        } else if (currentName == "yfov" || currentName == "ymag") {
  ------------------
  |  Branch (400:20): [True: 10, False: 60]
  |  Branch (400:45): [True: 0, False: 60]
  ------------------
  401|     10|            XmlParser::getValueAsReal(currentNode, camera.mVerFov);
  402|     60|        } else if (currentName == "aspect_ratio") {
  ------------------
  |  Branch (402:20): [True: 10, False: 50]
  ------------------
  403|     10|            XmlParser::getValueAsReal(currentNode, camera.mAspect);
  404|     50|        } else if (currentName == "znear") {
  ------------------
  |  Branch (404:20): [True: 10, False: 40]
  ------------------
  405|     10|            XmlParser::getValueAsReal(currentNode, camera.mZNear);
  406|     40|        } else if (currentName == "zfar") {
  ------------------
  |  Branch (406:20): [True: 10, False: 30]
  ------------------
  407|     10|            XmlParser::getValueAsReal(currentNode, camera.mZFar);
  408|     10|        }
  409|     70|    }
  410|     10|}
ColladaParser.cpp:_ZL22ReadNodeTransformationRN4pugi8xml_nodeEPN6Assimp7Collada4NodeENS3_13TransformTypeE:
  106|    799|static void ReadNodeTransformation(XmlNode &node, Node *pNode, TransformType pType) {
  107|    799|    if (node.empty()) {
  ------------------
  |  Branch (107:9): [True: 0, False: 799]
  ------------------
  108|      0|        return;
  109|      0|    }
  110|       |
  111|    799|    std::string tagName = node.name();
  112|       |
  113|    799|    Transform tf;
  114|    799|    tf.mType = pType;
  115|       |
  116|       |    // read SID
  117|    799|    if (XmlParser::hasAttribute(node, "sid")) {
  ------------------
  |  Branch (117:9): [True: 543, False: 256]
  ------------------
  118|    543|        XmlParser::getStdStrAttribute(node, "sid", tf.mID);
  119|    543|    }
  120|       |
  121|       |    // how many parameters to read per transformation type
  122|    799|    static constexpr unsigned int sNumParameters[] = { 9, 4, 3, 3, 7, 16 };
  123|    799|    std::string value;
  124|    799|    XmlParser::getValueAsString(node, value);
  125|    799|    const char *content = value.c_str();
  126|    799|    const char *end = value.c_str() + value.size();
  127|       |    // read as many parameters and store in the transformation
  128|  4.06k|    for (unsigned int a = 0; a < sNumParameters[pType]; a++) {
  ------------------
  |  Branch (128:30): [True: 3.26k, False: 799]
  ------------------
  129|       |        // skip whitespace before the number
  130|  3.26k|        SkipSpacesAndLineEnd(&content, end);
  131|       |        // read a number
  132|  3.26k|        content = fast_atoreal_move(content, tf.f[a]);
  133|  3.26k|    }
  134|       |
  135|       |    // place the transformation at the queue of the node
  136|    799|    pNode->mTransforms.push_back(tf);
  137|    799|}

_ZNK6Assimp13ColladaParser23ResolveLibraryReferenceIPNS_7Collada4MeshEEERKT_RKNSt3__13mapINS8_12basic_stringIcNS8_11char_traitsIcEENS8_9allocatorIcEEEES5_NS8_4lessISF_EENSD_INS8_4pairIKSF_S5_EEEEEERSJ_:
  309|      1|const Type &ColladaParser::ResolveLibraryReference(const std::map<std::string, Type> &pLibrary, const std::string &pURL) const {
  310|      1|    typename std::map<std::string, Type>::const_iterator it = pLibrary.find(pURL);
  311|      1|    if (it == pLibrary.end()) {
  ------------------
  |  Branch (311:9): [True: 0, False: 1]
  ------------------
  312|      0|        throw DeadlyImportError("Unable to resolve library reference \"", pURL, "\".");
  313|      0|    }
  314|      1|    return it->second;
  315|      1|}
_ZNK6Assimp13ColladaParser23ResolveLibraryReferenceINS_7Collada8AccessorEEERKT_RKNSt3__13mapINS7_12basic_stringIcNS7_11char_traitsIcEENS7_9allocatorIcEEEES4_NS7_4lessISE_EENSC_INS7_4pairIKSE_S4_EEEEEERSI_:
  309|    885|const Type &ColladaParser::ResolveLibraryReference(const std::map<std::string, Type> &pLibrary, const std::string &pURL) const {
  310|    885|    typename std::map<std::string, Type>::const_iterator it = pLibrary.find(pURL);
  311|    885|    if (it == pLibrary.end()) {
  ------------------
  |  Branch (311:9): [True: 2, False: 883]
  ------------------
  312|      2|        throw DeadlyImportError("Unable to resolve library reference \"", pURL, "\".");
  313|      2|    }
  314|    883|    return it->second;
  315|    885|}
_ZNK6Assimp13ColladaParser23ResolveLibraryReferenceINS_7Collada4DataEEERKT_RKNSt3__13mapINS7_12basic_stringIcNS7_11char_traitsIcEENS7_9allocatorIcEEEES4_NS7_4lessISE_EENSC_INS7_4pairIKSE_S4_EEEEEERSI_:
  309|    868|const Type &ColladaParser::ResolveLibraryReference(const std::map<std::string, Type> &pLibrary, const std::string &pURL) const {
  310|    868|    typename std::map<std::string, Type>::const_iterator it = pLibrary.find(pURL);
  311|    868|    if (it == pLibrary.end()) {
  ------------------
  |  Branch (311:9): [True: 0, False: 868]
  ------------------
  312|      0|        throw DeadlyImportError("Unable to resolve library reference \"", pURL, "\".");
  313|      0|    }
  314|    868|    return it->second;
  315|    868|}

_ZN6Assimp3DXF10LineReaderC2ERNS_12StreamReaderILb0ELb0EEE:
   63|     27|    explicit LineReader(StreamReaderLE& reader) : splitter(reader,false,true), groupcode( 0 ), end() {
   64|       |        // empty
   65|     27|    }
_ZNK6Assimp3DXF10LineReader3EndEv:
   88|   249k|    bool End() const {
   89|   249k|        return !((bool)*this);
   90|   249k|    }
_ZNK6Assimp3DXF10LineReadercvbEv:
  150|   249k|    operator bool() const {
  151|   249k|        return end <= 1;
  152|   249k|    }
_ZNK6Assimp3DXF10LineReader2IsEiPKc:
   68|   345k|    bool Is(int gc, const char* what) const {
   69|   345k|        return groupcode == gc && !strcmp(what,value.c_str());
  ------------------
  |  Branch (69:16): [True: 161k, False: 183k]
  |  Branch (69:35): [True: 16.6k, False: 144k]
  ------------------
   70|   345k|    }
_ZNK6Assimp3DXF10LineReader2IsEi:
   73|   123k|    bool Is(int gc) const {
   74|   123k|        return groupcode == gc;
   75|   123k|    }
_ZNK6Assimp3DXF10LineReader5ValueEv:
   83|  11.9k|    const std::string& Value() const {
   84|  11.9k|        return value;
   85|  11.9k|    }
_ZN6Assimp3DXF10LineReaderppEv:
  109|   233k|    LineReader& operator++() {
  110|   233k|        if (end) {
  ------------------
  |  Branch (110:13): [True: 18, False: 233k]
  ------------------
  111|     18|            if (end == 1) {
  ------------------
  |  Branch (111:17): [True: 18, False: 0]
  ------------------
  112|     18|                ++end;
  113|     18|            }
  114|     18|            return *this;
  115|     18|        }
  116|       |
  117|   233k|        try {
  118|   233k|            groupcode = strtol10(splitter->c_str());
  119|   233k|            splitter++;
  120|       |
  121|   233k|            value = *splitter;
  122|   233k|            splitter++;
  123|       |
  124|       |            // automatically skip over {} meta blocks (these are for application use
  125|       |            // and currently not relevant for Assimp).
  126|   233k|            if (value.length() && value[0] == '{') {
  ------------------
  |  Branch (126:17): [True: 232k, False: 1.52k]
  |  Branch (126:35): [True: 237, False: 232k]
  ------------------
  127|       |
  128|    237|                size_t cnt = 0;
  129|  1.66k|                for(;splitter->length() && splitter->at(0) != '}'; splitter++, cnt++);
  ------------------
  |  Branch (129:22): [True: 1.62k, False: 42]
  |  Branch (129:44): [True: 1.42k, False: 195]
  ------------------
  130|       |
  131|    237|                splitter++;
  132|    237|                ASSIMP_LOG_VERBOSE_DEBUG("DXF: skipped over control group (",cnt," lines)");
  133|    237|            }
  134|   233k|        } catch(std::logic_error&) {
  135|     20|            ai_assert(!splitter);
  136|     20|        }
  137|   233k|        if (!splitter) {
  ------------------
  |  Branch (137:13): [True: 24, False: 233k]
  ------------------
  138|     24|            end = 1;
  139|     24|        }
  140|   233k|        return *this;
  141|   233k|    }
_ZN6Assimp3DXF10LineReaderppEi:
  144|   125k|    LineReader& operator++(int) {
  145|   125k|        return ++(*this);
  146|   125k|    }
_ZNK6Assimp3DXF10LineReader9GroupCodeEv:
   78|   146k|    int GroupCode() const {
   79|   146k|        return groupcode;
   80|   146k|    }
_ZNK6Assimp3DXF10LineReader12ValueAsFloatEv:
  103|  41.1k|    ai_real ValueAsFloat() const {
  104|  41.1k|        return fast_atof(value.c_str());
  105|  41.1k|    }
_ZN6Assimp3DXF8PolyLineC2Ev:
  163|  2.00k|    PolyLine() : flags() {
  164|       |        // empty
  165|  2.00k|    }
_ZNK6Assimp3DXF10LineReader16ValueAsSignedIntEv:
   98|  18.2k|    int ValueAsSignedInt() const {
   99|  18.2k|        return strtol10(value.c_str());
  100|  18.2k|    }
_ZNK6Assimp3DXF10LineReader18ValueAsUnsignedIntEv:
   93|  20.4k|    unsigned int ValueAsUnsignedInt() const {
   94|  20.4k|        return strtoul10(value.c_str());
   95|  20.4k|    }
_ZN6Assimp3DXF11InsertBlockC2Ev:
  179|  1.34k|    InsertBlock() : pos(0.f, 0.f, 0.f), scale(1.f,1.f,1.f), angle(0.0f) {
  180|       |        // empty
  181|  1.34k|    }

_ZNK6Assimp11DXFImporter7CanReadERKNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEPNS_8IOSystemEb:
  356|    380|bool DXFImporter::CanRead( const std::string& filename, IOSystem* pIOHandler, bool /*checkSig*/ ) const {
  357|    380|    static const char *tokens[] = { "SECTION", "HEADER", "ENDSEC", "BLOCKS" };
  358|       |    return SearchFileHeaderForToken(pIOHandler, filename, tokens, AI_COUNT_OF(tokens), 32);
  359|    380|}
_ZNK6Assimp11DXFImporter7GetInfoEv:
  363|    661|const aiImporterDesc* DXFImporter::GetInfo () const {
  364|    661|    return &desc;
  365|    661|}
_ZN6Assimp11DXFImporter14InternReadFileERKNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEP7aiScenePNS_8IOSystemE:
  369|     27|void DXFImporter::InternReadFile( const std::string& filename, aiScene* pScene, IOSystem* pIOHandler) {
  370|     27|    std::shared_ptr<IOStream> file = std::shared_ptr<IOStream>( pIOHandler->Open( filename) );
  371|       |
  372|       |    // Check whether we can read the file
  373|     27|    if (file == nullptr) {
  ------------------
  |  Branch (373:9): [True: 0, False: 27]
  ------------------
  374|      0|        throw DeadlyImportError( "Failed to open DXF file ", filename, "");
  375|      0|    }
  376|       |
  377|       |    // Check whether this is a binary DXF file - we can't read binary DXF files :-(
  378|     27|    char buff[AI_DXF_BINARY_IDENT_LEN] = {0};
  379|     27|    file->Read(buff,AI_DXF_BINARY_IDENT_LEN,1);
  380|       |
  381|     27|    if (0 == memcmp(AI_DXF_BINARY_IDENT,buff,AI_DXF_BINARY_IDENT_LEN)) {
  ------------------
  |  Branch (381:9): [True: 0, False: 27]
  ------------------
  382|      0|        throw DeadlyImportError("DXF: Binary files are not supported at the moment");
  383|      0|    }
  384|       |
  385|       |    // DXF files can grow very large, so read them via the StreamReader,
  386|       |    // which will choose a suitable strategy.
  387|     27|    file->Seek(0,aiOrigin_SET);
  388|     27|    StreamReaderLE stream( std::move(file) );
  389|       |
  390|     27|    DXF::LineReader reader (stream);
  391|     27|    DXF::FileData output;
  392|       |
  393|       |    // now get all lines of the file and process top-level sections
  394|     27|    bool eof = false;
  395|  4.83k|    while(!reader.End()) {
  ------------------
  |  Branch (395:11): [True: 4.81k, False: 21]
  ------------------
  396|       |
  397|       |        // blocks table - these 'build blocks' are later (in ENTITIES)
  398|       |        // referenced an included via INSERT statements.
  399|  4.81k|        if (reader.Is(2,"BLOCKS")) {
  ------------------
  |  Branch (399:13): [True: 12, False: 4.80k]
  ------------------
  400|     12|            ParseBlocks(reader,output);
  401|     12|            continue;
  402|     12|        }
  403|       |
  404|       |        // primary entity table
  405|  4.80k|        if (reader.Is(2,"ENTITIES")) {
  ------------------
  |  Branch (405:13): [True: 24, False: 4.77k]
  ------------------
  406|     24|            ParseEntities(reader,output);
  407|     24|            continue;
  408|     24|        }
  409|       |
  410|       |        // skip unneeded sections entirely to avoid any problems with them
  411|       |        // altogether.
  412|  4.77k|        else if (reader.Is(2,"CLASSES") || reader.Is(2,"TABLES")) {
  ------------------
  |  Branch (412:18): [True: 0, False: 4.77k]
  |  Branch (412:44): [True: 1, False: 4.77k]
  ------------------
  413|      1|            SkipSection(reader);
  414|      1|            continue;
  415|      1|        }
  416|       |
  417|  4.77k|        else if (reader.Is(2,"HEADER")) {
  ------------------
  |  Branch (417:18): [True: 6, False: 4.77k]
  ------------------
  418|      6|            ParseHeader(reader,output);
  419|      6|            continue;
  420|      6|        }
  421|       |
  422|       |        // comments
  423|  4.77k|        else if (reader.Is(999)) {
  ------------------
  |  Branch (423:18): [True: 0, False: 4.77k]
  ------------------
  424|      0|            ASSIMP_LOG_INFO("DXF Comment: ", reader.Value());
  425|      0|        }
  426|       |
  427|       |        // don't read past the official EOF sign
  428|  4.77k|        else if (reader.Is(0,"EOF")) {
  ------------------
  |  Branch (428:18): [True: 6, False: 4.76k]
  ------------------
  429|      6|            eof = true;
  430|      6|            break;
  431|      6|        }
  432|       |
  433|  4.76k|        ++reader;
  434|  4.76k|    }
  435|     27|    if (!eof) {
  ------------------
  |  Branch (435:9): [True: 18, False: 9]
  ------------------
  436|     18|        ASSIMP_LOG_WARN("DXF: EOF reached, but did not encounter DXF EOF marker");
  437|     18|    }
  438|       |
  439|     27|    ConvertMeshes(pScene,output);
  440|       |
  441|       |    // Now rotate the whole scene by 90 degrees around the x axis to convert from AutoCAD's to Assimp's coordinate system
  442|     27|    pScene->mRootNode->mTransformation = aiMatrix4x4(
  443|     27|        1.f,0.f,0.f,0.f,
  444|     27|        0.f,0.f,1.f,0.f,
  445|     27|        0.f,-1.f,0.f,0.f,
  446|     27|        0.f,0.f,0.f,1.f) * pScene->mRootNode->mTransformation;
  447|     27|}
_ZN6Assimp11DXFImporter13ConvertMeshesEP7aiSceneRNS_3DXF8FileDataE:
  450|     24|void DXFImporter::ConvertMeshes(aiScene* pScene, DXF::FileData& output) {
  451|       |    // the process of resolving all the INSERT statements can grow the
  452|       |    // poly-count excessively, so log the original number.
  453|       |    // XXX Option to import blocks as separate nodes?
  454|     24|    if (!DefaultLogger::isNullLogger()) {
  ------------------
  |  Branch (454:9): [True: 0, False: 24]
  ------------------
  455|      0|        unsigned int vcount = 0, icount = 0;
  456|      0|        for (const DXF::Block& bl : output.blocks) {
  ------------------
  |  Branch (456:35): [True: 0, False: 0]
  ------------------
  457|      0|            for (std::shared_ptr<const DXF::PolyLine> pl : bl.lines) {
  ------------------
  |  Branch (457:58): [True: 0, False: 0]
  ------------------
  458|      0|                vcount += static_cast<unsigned int>(pl->positions.size());
  459|      0|                icount += static_cast<unsigned int>(pl->counts.size());
  460|      0|            }
  461|      0|        }
  462|       |
  463|      0|        ASSIMP_LOG_VERBOSE_DEBUG("DXF: Unexpanded polycount is ", icount, ", vertex count is ", vcount);
  464|      0|    }
  465|       |
  466|     24|    if (output.blocks.empty()) {
  ------------------
  |  Branch (466:9): [True: 2, False: 22]
  ------------------
  467|      2|        throw DeadlyImportError("DXF: no data blocks loaded");
  468|      2|    }
  469|       |
  470|     22|    DXF::Block* entities( nullptr );
  471|       |
  472|       |    // index blocks by name
  473|     22|    DXF::BlockMap blocks_by_name;
  474|     40|    for (DXF::Block& bl : output.blocks) {
  ------------------
  |  Branch (474:25): [True: 40, False: 22]
  ------------------
  475|     40|        blocks_by_name[bl.name] = &bl;
  476|     40|        if ( !entities && bl.name == AI_DXF_ENTITIES_MAGIC_BLOCK ) {
  ------------------
  |  |  334|     35|#define AI_DXF_ENTITIES_MAGIC_BLOCK "$ASSIMP_ENTITIES_MAGIC"
  ------------------
  |  Branch (476:14): [True: 35, False: 5]
  |  Branch (476:27): [True: 21, False: 14]
  ------------------
  477|     21|            entities = &bl;
  478|     21|        }
  479|     40|    }
  480|       |
  481|     22|    if (!entities) {
  ------------------
  |  Branch (481:9): [True: 1, False: 21]
  ------------------
  482|      1|        throw DeadlyImportError("DXF: no ENTITIES data block loaded");
  483|      1|    }
  484|       |
  485|     21|    typedef std::map<std::string, unsigned int> LayerMap;
  486|       |
  487|     21|    LayerMap layers;
  488|     21|    std::vector< std::vector< const DXF::PolyLine*> > corr;
  489|       |
  490|       |    // now expand all block references in the primary ENTITIES block
  491|       |    // XXX this involves heavy memory copying, consider a faster solution for future versions.
  492|     21|    ExpandBlockReferences(*entities,blocks_by_name);
  493|       |
  494|     21|    unsigned int cur = 0;
  495|  17.1k|    for (std::shared_ptr<const DXF::PolyLine> pl : entities->lines) {
  ------------------
  |  Branch (495:50): [True: 17.1k, False: 21]
  ------------------
  496|  17.1k|        if (pl->positions.size()) {
  ------------------
  |  Branch (496:13): [True: 17.1k, False: 0]
  ------------------
  497|       |
  498|  17.1k|            std::map<std::string, unsigned int>::iterator it = layers.find(pl->layer);
  499|  17.1k|            if (it == layers.end()) {
  ------------------
  |  Branch (499:17): [True: 28, False: 17.1k]
  ------------------
  500|     28|                ++pScene->mNumMeshes;
  501|       |
  502|     28|                layers[pl->layer] = cur++;
  503|       |
  504|     28|                std::vector< const DXF::PolyLine* > pv;
  505|     28|                pv.push_back(&*pl);
  506|       |
  507|     28|                corr.push_back(pv);
  508|     28|            }
  509|  17.1k|            else {
  510|  17.1k|                corr[(*it).second].push_back(&*pl);
  511|  17.1k|            }
  512|  17.1k|        }
  513|  17.1k|    }
  514|       |
  515|     21|    if ( 0 == pScene->mNumMeshes) {
  ------------------
  |  Branch (515:10): [True: 4, False: 17]
  ------------------
  516|      4|        throw DeadlyImportError("DXF: this file contains no 3d data");
  517|      4|    }
  518|       |
  519|     17|    pScene->mMeshes = new aiMesh*[ pScene->mNumMeshes ] ();
  520|       |
  521|     28|    for(const LayerMap::value_type& elem : layers){
  ------------------
  |  Branch (521:42): [True: 28, False: 15]
  ------------------
  522|     28|        aiMesh* const mesh =  pScene->mMeshes[elem.second] = new aiMesh();
  523|     28|        mesh->mName.Set(elem.first);
  524|       |
  525|     28|        unsigned int cvert = 0,cface = 0;
  526|  17.1k|        for(const DXF::PolyLine* pl : corr[elem.second]){
  ------------------
  |  Branch (526:37): [True: 17.1k, False: 28]
  ------------------
  527|       |            // sum over all faces since we need to 'verbosify' them.
  528|  17.1k|            cvert += std::accumulate(pl->counts.begin(),pl->counts.end(),0);
  529|  17.1k|            cface += static_cast<unsigned int>(pl->counts.size());
  530|  17.1k|        }
  531|       |
  532|     28|        aiVector3D* verts = mesh->mVertices = new aiVector3D[cvert];
  533|     28|        aiColor4D* colors = mesh->mColors[0] = new aiColor4D[cvert];
  534|     28|        aiFace* faces = mesh->mFaces = new aiFace[cface];
  535|       |
  536|     28|        mesh->mNumVertices = cvert;
  537|     28|        mesh->mNumFaces = cface;
  538|       |
  539|     28|        unsigned int prims = 0;
  540|     28|        unsigned int overall_indices = 0;
  541|  17.1k|        for(const DXF::PolyLine* pl : corr[elem.second]){
  ------------------
  |  Branch (541:37): [True: 17.1k, False: 26]
  ------------------
  542|       |
  543|  17.1k|            std::vector<unsigned int>::const_iterator it = pl->indices.begin();
  544|  22.4k|            for(unsigned int facenumv : pl->counts) {
  ------------------
  |  Branch (544:39): [True: 22.4k, False: 17.1k]
  ------------------
  545|  22.4k|                aiFace& face = *faces++;
  546|  22.4k|                face.mIndices = new unsigned int[face.mNumIndices = facenumv];
  547|       |
  548|  99.3k|                for (unsigned int i = 0; i < facenumv; ++i) {
  ------------------
  |  Branch (548:42): [True: 76.9k, False: 22.4k]
  ------------------
  549|  76.9k|                    face.mIndices[i] = overall_indices++;
  550|       |
  551|  76.9k|                    ai_assert(pl->positions.size() == pl->colors.size());
  552|  76.9k|                    if (*it >= pl->positions.size()) {
  ------------------
  |  Branch (552:25): [True: 2, False: 76.9k]
  ------------------
  553|      2|                        throw DeadlyImportError("DXF: vertex index out of bounds");
  554|      2|                    }
  555|       |
  556|  76.9k|                    *verts++ = pl->positions[*it];
  557|  76.9k|                    *colors++ = pl->colors[*it++];
  558|  76.9k|                }
  559|       |
  560|       |                // set primitive flags now, this saves the extra pass in ScenePreprocessor.
  561|  22.4k|                switch(face.mNumIndices) {
  562|    149|                    case 1:
  ------------------
  |  Branch (562:21): [True: 149, False: 22.2k]
  ------------------
  563|    149|                        prims |= aiPrimitiveType_POINT;
  564|    149|                        break;
  565|    402|                    case 2:
  ------------------
  |  Branch (565:21): [True: 402, False: 22.0k]
  ------------------
  566|    402|                        prims |= aiPrimitiveType_LINE;
  567|    402|                        break;
  568|  11.4k|                    case 3:
  ------------------
  |  Branch (568:21): [True: 11.4k, False: 10.9k]
  ------------------
  569|  11.4k|                        prims |= aiPrimitiveType_TRIANGLE;
  570|  11.4k|                        break;
  571|  10.4k|                    default:
  ------------------
  |  Branch (571:21): [True: 10.4k, False: 11.9k]
  ------------------
  572|  10.4k|                        prims |= aiPrimitiveType_POLYGON;
  573|  10.4k|                        break;
  574|  22.4k|                }
  575|  22.4k|            }
  576|  17.1k|        }
  577|       |
  578|     26|        mesh->mPrimitiveTypes = prims;
  579|     26|        mesh->mMaterialIndex = 0;
  580|     26|    }
  581|       |
  582|     15|    GenerateHierarchy(pScene,output);
  583|     15|    GenerateMaterials(pScene,output);
  584|     15|}
_ZN6Assimp11DXFImporter21ExpandBlockReferencesERNS_3DXF5BlockERKNSt3__13mapINS4_12basic_stringIcNS4_11char_traitsIcEENS4_9allocatorIcEEEEPKS2_NS4_4lessISB_EENS9_INS4_4pairIKSB_SD_EEEEEE:
  588|     21|void DXFImporter::ExpandBlockReferences(DXF::Block& bl,const DXF::BlockMap& blocks_by_name) {
  589|  1.12k|    for (const DXF::InsertBlock& insert : bl.insertions) {
  ------------------
  |  Branch (589:41): [True: 1.12k, False: 21]
  ------------------
  590|       |
  591|       |        // first check if the referenced blocks exists ...
  592|  1.12k|        const DXF::BlockMap::const_iterator it = blocks_by_name.find(insert.name);
  593|  1.12k|        if (it == blocks_by_name.end()) {
  ------------------
  |  Branch (593:13): [True: 644, False: 483]
  ------------------
  594|    644|            ASSIMP_LOG_ERROR("DXF: Failed to resolve block reference: ", insert.name,"; skipping" );
  595|    644|            continue;
  596|    644|        }
  597|       |
  598|       |        // XXX this would be the place to implement recursive expansion if needed.
  599|    483|        const DXF::Block& bl_src = *(*it).second;
  600|       |
  601|    483|        const size_t size = bl_src.lines.size(); // the size may increase in the loop
  602|  16.6k|        for (size_t i = 0; i < size; ++i) {
  ------------------
  |  Branch (602:28): [True: 16.2k, False: 483]
  ------------------
  603|  16.2k|            std::shared_ptr<const DXF::PolyLine> pl_in = bl_src.lines[i];
  604|  16.2k|            if (!pl_in) {
  ------------------
  |  Branch (604:17): [True: 0, False: 16.2k]
  ------------------
  605|      0|                ASSIMP_LOG_ERROR("DXF: PolyLine instance is nullptr, skipping.");
  606|      0|                continue;
  607|      0|            }
  608|       |
  609|  16.2k|            std::shared_ptr<DXF::PolyLine> pl_out = std::shared_ptr<DXF::PolyLine>(new DXF::PolyLine(*pl_in));
  610|       |
  611|  16.2k|            if (bl_src.base.Length() || insert.scale.x!=1.f || insert.scale.y!=1.f || insert.scale.z!=1.f || insert.angle || insert.pos.Length()) {
  ------------------
  |  Branch (611:17): [True: 15.6k, False: 571]
  |  Branch (611:41): [True: 0, False: 571]
  |  Branch (611:64): [True: 0, False: 571]
  |  Branch (611:87): [True: 0, False: 571]
  |  Branch (611:110): [True: 0, False: 571]
  |  Branch (611:126): [True: 0, False: 571]
  ------------------
  612|       |                // manual coordinate system transformation
  613|       |                // XXX order
  614|  15.6k|                aiMatrix4x4 trafo, tmp;
  615|  15.6k|                aiMatrix4x4::Translation(-bl_src.base,trafo);
  616|       |                //Need to translate position before scaling the insert
  617|       |                //otherwise the position ends up being the position*scaling
  618|       |                //STH 2024.01.17
  619|  15.6k|                trafo *= aiMatrix4x4::Translation(insert.pos,tmp);
  620|  15.6k|                trafo *= aiMatrix4x4::Scaling(insert.scale,tmp);
  621|       |                //trafo *= aiMatrix4x4::Translation(insert.pos,tmp);
  622|       |
  623|       |                // XXX rotation currently ignored - I didn't find an appropriate sample model.
  624|  15.6k|                if (insert.angle != 0.f) {
  ------------------
  |  Branch (624:21): [True: 0, False: 15.6k]
  ------------------
  625|      0|                    ASSIMP_LOG_WARN("DXF: BLOCK rotation not currently implemented");
  626|      0|                }
  627|       |
  628|  55.4k|                for (aiVector3D& v : pl_out->positions) {
  ------------------
  |  Branch (628:36): [True: 55.4k, False: 15.6k]
  ------------------
  629|  55.4k|                    v *= trafo;
  630|  55.4k|                }
  631|  15.6k|            }
  632|       |
  633|  16.2k|            bl.lines.push_back(pl_out);
  634|  16.2k|        }
  635|    483|    }
  636|     21|}
_ZN6Assimp11DXFImporter17GenerateMaterialsEP7aiSceneRNS_3DXF8FileDataE:
  639|     15|void DXFImporter::GenerateMaterials(aiScene* pScene, DXF::FileData& /*output*/) {
  640|       |    // generate an almost-white default material. Reason:
  641|       |    // the default vertex color is GREY, so we are
  642|       |    // already at Assimp's usual default color.
  643|       |    // generate a default material
  644|     15|    aiMaterial* pcMat = new aiMaterial();
  645|     15|    aiString s;
  646|     15|    s.Set(AI_DEFAULT_MATERIAL_NAME);
  647|     15|    pcMat->AddProperty(&s, AI_MATKEY_NAME);
  648|       |
  649|     15|    aiColor4D clrDiffuse(0.9f,0.9f,0.9f,1.0f);
  650|     15|    pcMat->AddProperty(&clrDiffuse,1,AI_MATKEY_COLOR_DIFFUSE);
  651|       |
  652|     15|    clrDiffuse = aiColor4D(1.0f,1.0f,1.0f,1.0f);
  653|     15|    pcMat->AddProperty(&clrDiffuse,1,AI_MATKEY_COLOR_SPECULAR);
  654|       |
  655|     15|    clrDiffuse = aiColor4D(0.05f,0.05f,0.05f,1.0f);
  656|     15|    pcMat->AddProperty(&clrDiffuse,1,AI_MATKEY_COLOR_AMBIENT);
  657|       |
  658|     15|    pScene->mNumMaterials = 1;
  659|     15|    pScene->mMaterials = new aiMaterial*[1];
  660|     15|    pScene->mMaterials[0] = pcMat;
  661|     15|}
_ZN6Assimp11DXFImporter17GenerateHierarchyEP7aiSceneRNS_3DXF8FileDataE:
  664|     15|void DXFImporter::GenerateHierarchy(aiScene* pScene, DXF::FileData& /*output*/) {
  665|       |    // generate the output scene graph, which is just the root node with a single child for each layer.
  666|     15|    pScene->mRootNode = new aiNode();
  667|     15|    pScene->mRootNode->mName.Set("<DXF_ROOT>");
  668|       |
  669|     15|    if (1 == pScene->mNumMeshes)    {
  ------------------
  |  Branch (669:9): [True: 13, False: 2]
  ------------------
  670|     13|        pScene->mRootNode->mMeshes = new unsigned int[ pScene->mRootNode->mNumMeshes = 1 ];
  671|     13|        pScene->mRootNode->mMeshes[0] = 0;
  672|     13|    } else {
  673|      2|        pScene->mRootNode->mChildren = new aiNode*[ pScene->mRootNode->mNumChildren = pScene->mNumMeshes ];
  674|     15|        for (unsigned int m = 0; m < pScene->mRootNode->mNumChildren;++m)   {
  ------------------
  |  Branch (674:34): [True: 13, False: 2]
  ------------------
  675|     13|            aiNode* p = pScene->mRootNode->mChildren[m] = new aiNode();
  676|     13|            p->mName = pScene->mMeshes[m]->mName;
  677|       |
  678|     13|            p->mMeshes = new unsigned int[p->mNumMeshes = 1];
  679|     13|            p->mMeshes[0] = m;
  680|     13|            p->mParent = pScene->mRootNode;
  681|     13|        }
  682|      2|    }
  683|     15|}
_ZN6Assimp11DXFImporter11SkipSectionERNS_3DXF10LineReaderE:
  687|      1|void DXFImporter::SkipSection(DXF::LineReader& reader) {
  688|      2|    for( ;!reader.End() && !reader.Is(0,"ENDSEC"); reader++);
  ------------------
  |  Branch (688:11): [True: 2, False: 0]
  |  Branch (688:28): [True: 1, False: 1]
  ------------------
  689|      1|}
_ZN6Assimp11DXFImporter11ParseHeaderERNS_3DXF10LineReaderERNS1_8FileDataE:
  692|      6|void DXFImporter::ParseHeader(DXF::LineReader& reader, DXF::FileData& ) {
  693|  2.48k|    for( ;!reader.End() && !reader.Is(0,"ENDSEC"); reader++);
  ------------------
  |  Branch (693:11): [True: 2.48k, False: 0]
  |  Branch (693:28): [True: 2.47k, False: 6]
  ------------------
  694|      6|}
_ZN6Assimp11DXFImporter11ParseBlocksERNS_3DXF10LineReaderERNS1_8FileDataE:
  697|     12|void DXFImporter::ParseBlocks(DXF::LineReader& reader, DXF::FileData& output) {
  698|  56.6k|    while( !reader.End() && !reader.Is(0,"ENDSEC")) {
  ------------------
  |  Branch (698:12): [True: 56.6k, False: 6]
  |  Branch (698:29): [True: 56.6k, False: 6]
  ------------------
  699|  56.6k|        if (reader.Is(0,"BLOCK")) {
  ------------------
  |  Branch (699:13): [True: 19, False: 56.6k]
  ------------------
  700|     19|            ParseBlock(++reader,output);
  701|     19|            continue;
  702|     19|        }
  703|  56.6k|        ++reader;
  704|  56.6k|    }
  705|       |
  706|       |    ASSIMP_LOG_VERBOSE_DEBUG("DXF: got ", output.blocks.size()," entries in BLOCKS" );
  707|     12|}
_ZN6Assimp11DXFImporter10ParseBlockERNS_3DXF10LineReaderERNS1_8FileDataE:
  710|     19|void DXFImporter::ParseBlock(DXF::LineReader& reader, DXF::FileData& output) {
  711|       |    // push a new block onto the stack.
  712|     19|    output.blocks.emplace_back();
  713|     19|    DXF::Block& block = output.blocks.back();
  714|       |
  715|  1.25k|    while( !reader.End() && !reader.Is(0,"ENDBLK")) {
  ------------------
  |  Branch (715:12): [True: 1.24k, False: 4]
  |  Branch (715:29): [True: 1.23k, False: 8]
  ------------------
  716|       |
  717|  1.23k|        switch(reader.GroupCode()) {
  ------------------
  |  Branch (717:16): [True: 90, False: 1.14k]
  ------------------
  718|     18|            case GroupCode_Name:
  ------------------
  |  Branch (718:13): [True: 18, False: 1.22k]
  ------------------
  719|     18|                block.name = reader.Value();
  720|     18|                break;
  721|       |
  722|      7|            case GroupCode_XComp:
  ------------------
  |  Branch (722:13): [True: 7, False: 1.23k]
  ------------------
  723|      7|                block.base.x = reader.ValueAsFloat();
  724|      7|                break;
  725|      7|            case GroupCode_YComp:
  ------------------
  |  Branch (725:13): [True: 7, False: 1.23k]
  ------------------
  726|      7|                block.base.y = reader.ValueAsFloat();
  727|      7|                break;
  728|     58|            case GroupCode_ZComp:
  ------------------
  |  Branch (728:13): [True: 58, False: 1.18k]
  ------------------
  729|     58|                block.base.z = reader.ValueAsFloat();
  730|     58|                break;
  731|  1.23k|        }
  732|       |
  733|  1.23k|        if (reader.Is(0,"POLYLINE")) {
  ------------------
  |  Branch (733:13): [True: 1, False: 1.23k]
  ------------------
  734|      1|            ParsePolyLine(++reader,output);
  735|      1|            continue;
  736|      1|        }
  737|       |
  738|       |        // XXX is this a valid case?
  739|  1.23k|        if (reader.Is(0,"INSERT")) {
  ------------------
  |  Branch (739:13): [True: 7, False: 1.23k]
  ------------------
  740|      7|            ASSIMP_LOG_WARN("DXF: INSERT within a BLOCK not currently supported; skipping");
  741|  1.88k|            for( ;!reader.End() && !reader.Is(0,"ENDBLK"); ++reader);
  ------------------
  |  Branch (741:19): [True: 1.88k, False: 1]
  |  Branch (741:36): [True: 1.87k, False: 6]
  ------------------
  742|      7|            break;
  743|      7|        }
  744|       |
  745|  1.23k|        else if (reader.Is(0,"3DFACE") || reader.Is(0,"LINE") || reader.Is(0,"3DLINE")) {
  ------------------
  |  Branch (745:18): [True: 0, False: 1.23k]
  |  Branch (745:43): [True: 238, False: 993]
  |  Branch (745:66): [True: 0, False: 993]
  ------------------
  746|       |            //http://sourceforge.net/tracker/index.php?func=detail&aid=2970566&group_id=226462&atid=1067632
  747|    238|            Parse3DFace(++reader, output);
  748|    238|            continue;
  749|    238|        }
  750|    993|        ++reader;
  751|    993|    }
  752|     19|}
_ZN6Assimp11DXFImporter13ParseEntitiesERNS_3DXF10LineReaderERNS1_8FileDataE:
  755|     24|void DXFImporter::ParseEntities(DXF::LineReader& reader, DXF::FileData& output) {
  756|       |    // Push a new block onto the stack.
  757|     24|    output.blocks.emplace_back();
  758|     24|    DXF::Block& block = output.blocks.back();
  759|       |
  760|     24|    block.name = AI_DXF_ENTITIES_MAGIC_BLOCK;
  ------------------
  |  |  334|     24|#define AI_DXF_ENTITIES_MAGIC_BLOCK "$ASSIMP_ENTITIES_MAGIC"
  ------------------
  761|       |
  762|  20.5k|    while( !reader.End() && !reader.Is(0,"ENDSEC")) {
  ------------------
  |  Branch (762:12): [True: 20.5k, False: 13]
  |  Branch (762:29): [True: 20.4k, False: 11]
  ------------------
  763|  20.4k|        if (reader.Is(0,"POLYLINE")) {
  ------------------
  |  Branch (763:13): [True: 368, False: 20.1k]
  ------------------
  764|    368|            ParsePolyLine(++reader,output);
  765|    368|            continue;
  766|    368|        }
  767|       |
  768|  20.1k|        else if (reader.Is(0,"INSERT")) {
  ------------------
  |  Branch (768:18): [True: 1.34k, False: 18.7k]
  ------------------
  769|  1.34k|            ParseInsertion(++reader,output);
  770|  1.34k|            continue;
  771|  1.34k|        }
  772|       |
  773|  18.7k|        else if (reader.Is(0,"3DFACE") || reader.Is(0,"LINE") || reader.Is(0,"3DLINE")) {
  ------------------
  |  Branch (773:18): [True: 685, False: 18.0k]
  |  Branch (773:43): [True: 710, False: 17.3k]
  |  Branch (773:66): [True: 0, False: 17.3k]
  ------------------
  774|       |            //http://sourceforge.net/tracker/index.php?func=detail&aid=2970566&group_id=226462&atid=1067632
  775|  1.39k|            Parse3DFace(++reader, output);
  776|  1.39k|            continue;
  777|  1.39k|        }
  778|       |
  779|  17.3k|        ++reader;
  780|  17.3k|    }
  781|       |
  782|       |    ASSIMP_LOG_VERBOSE_DEBUG( "DXF: got ", block.lines.size()," polylines and ", block.insertions.size(),
  783|     24|        " inserted blocks in ENTITIES" );
  784|     24|}
_ZN6Assimp11DXFImporter14ParseInsertionERNS_3DXF10LineReaderERNS1_8FileDataE:
  786|  1.34k|void DXFImporter::ParseInsertion(DXF::LineReader& reader, DXF::FileData& output) {
  787|  1.34k|    output.blocks.back().insertions.emplace_back();
  788|  1.34k|    DXF::InsertBlock& bl = output.blocks.back().insertions.back();
  789|       |
  790|  2.47k|    while( !reader.End() && !reader.Is(0)) {
  ------------------
  |  Branch (790:12): [True: 2.47k, False: 0]
  |  Branch (790:29): [True: 1.12k, False: 1.34k]
  ------------------
  791|  1.12k|        switch(reader.GroupCode()) {
  ------------------
  |  Branch (791:16): [True: 907, False: 219]
  ------------------
  792|       |            // name of referenced block
  793|    763|        case GroupCode_Name:
  ------------------
  |  Branch (793:9): [True: 763, False: 363]
  ------------------
  794|    763|            bl.name = reader.Value();
  795|    763|            break;
  796|       |
  797|       |            // translation
  798|      2|        case GroupCode_XComp:
  ------------------
  |  Branch (798:9): [True: 2, False: 1.12k]
  ------------------
  799|      2|            bl.pos.x = reader.ValueAsFloat();
  800|      2|            break;
  801|      3|        case GroupCode_YComp:
  ------------------
  |  Branch (801:9): [True: 3, False: 1.12k]
  ------------------
  802|      3|            bl.pos.y = reader.ValueAsFloat();
  803|      3|            break;
  804|      7|        case GroupCode_ZComp:
  ------------------
  |  Branch (804:9): [True: 7, False: 1.11k]
  ------------------
  805|      7|            bl.pos.z = reader.ValueAsFloat();
  806|      7|            break;
  807|       |
  808|       |            // scaling
  809|      2|        case 41:
  ------------------
  |  Branch (809:9): [True: 2, False: 1.12k]
  ------------------
  810|      2|            bl.scale.x = reader.ValueAsFloat();
  811|      2|            break;
  812|      2|        case 42:
  ------------------
  |  Branch (812:9): [True: 2, False: 1.12k]
  ------------------
  813|      2|            bl.scale.y = reader.ValueAsFloat();
  814|      2|            break;
  815|      2|        case 43:
  ------------------
  |  Branch (815:9): [True: 2, False: 1.12k]
  ------------------
  816|      2|            bl.scale.z = reader.ValueAsFloat();
  817|      2|            break;
  818|       |
  819|       |            // rotation angle
  820|    126|        case 50:
  ------------------
  |  Branch (820:9): [True: 126, False: 1.00k]
  ------------------
  821|    126|            bl.angle = reader.ValueAsFloat();
  822|    126|            break;
  823|  1.12k|        }
  824|  1.12k|        reader++;
  825|  1.12k|    }
  826|  1.34k|}
_ZN6Assimp11DXFImporter13ParsePolyLineERNS_3DXF10LineReaderERNS1_8FileDataE:
  835|    369|void DXFImporter::ParsePolyLine(DXF::LineReader& reader, DXF::FileData& output) {
  836|    369|    output.blocks.back().lines.push_back( std::shared_ptr<DXF::PolyLine>( new DXF::PolyLine() ) );
  837|    369|    DXF::PolyLine& line = *output.blocks.back().lines.back();
  838|       |
  839|    369|    unsigned int iguess = 0, vguess = 0;
  840|  31.6k|    while( !reader.End() && !reader.Is(0,"ENDSEC")) {
  ------------------
  |  Branch (840:12): [True: 31.6k, False: 2]
  |  Branch (840:29): [True: 31.6k, False: 0]
  ------------------
  841|       |
  842|  31.6k|        if (reader.Is(0,"VERTEX")) {
  ------------------
  |  Branch (842:13): [True: 12.8k, False: 18.7k]
  ------------------
  843|  12.8k|            ParsePolyLineVertex(++reader,line);
  844|  12.8k|            if (reader.Is(0,"SEQEND")) {
  ------------------
  |  Branch (844:17): [True: 367, False: 12.4k]
  ------------------
  845|    367|                break;
  846|    367|            }
  847|  12.4k|            continue;
  848|  12.8k|        }
  849|       |
  850|  18.7k|        switch(reader.GroupCode())
  ------------------
  |  Branch (850:16): [True: 793, False: 17.9k]
  ------------------
  851|  18.7k|        {
  852|       |        // flags --- important that we know whether it is a
  853|       |        // polyface mesh or 'just' a line.
  854|    737|        case 70:
  ------------------
  |  Branch (854:9): [True: 737, False: 18.0k]
  ------------------
  855|    737|            if (!line.flags)    {
  ------------------
  |  Branch (855:17): [True: 367, False: 370]
  ------------------
  856|    367|                line.flags = reader.ValueAsSignedInt();
  857|    367|            }
  858|    737|            break;
  859|       |
  860|       |        // optional number of vertices
  861|     20|        case 71:
  ------------------
  |  Branch (861:9): [True: 20, False: 18.7k]
  ------------------
  862|     20|            vguess = reader.ValueAsSignedInt();
  863|     20|            line.positions.reserve(vguess);
  864|     20|            break;
  865|       |
  866|       |        // optional number of faces
  867|     23|        case 72:
  ------------------
  |  Branch (867:9): [True: 23, False: 18.7k]
  ------------------
  868|     23|            iguess = reader.ValueAsSignedInt();
  869|     23|            line.indices.reserve(iguess);
  870|     23|            break;
  871|       |
  872|       |        // 8 specifies the layer on which this line is placed on
  873|     13|        case 8:
  ------------------
  |  Branch (873:9): [True: 13, False: 18.7k]
  ------------------
  874|     13|            line.layer = reader.Value();
  875|     13|            break;
  876|  18.7k|        }
  877|       |
  878|  18.7k|        reader++;
  879|  18.7k|    }
  880|       |
  881|    369|    if (vguess && line.positions.size() != vguess) {
  ------------------
  |  Branch (881:9): [True: 12, False: 357]
  |  Branch (881:19): [True: 3, False: 9]
  ------------------
  882|      3|        ASSIMP_LOG_WARN("DXF: unexpected vertex count in polymesh: ",
  883|      3|            line.positions.size(),", expected ", vguess );
  884|      3|    }
  885|       |
  886|    369|    if (line.flags & DXF_POLYLINE_FLAG_POLYFACEMESH ) {
  ------------------
  |  Branch (886:9): [True: 365, False: 4]
  ------------------
  887|    365|        if (line.positions.size() < 3 || line.indices.size() < 3)   {
  ------------------
  |  Branch (887:13): [True: 0, False: 365]
  |  Branch (887:42): [True: 354, False: 11]
  ------------------
  888|    354|            ASSIMP_LOG_WARN("DXF: not enough vertices for polymesh; ignoring");
  889|    354|            output.blocks.back().lines.pop_back();
  890|    354|            return;
  891|    354|        }
  892|       |
  893|       |        // if these numbers are wrong, parsing might have gone wild.
  894|       |        // however, the docs state that applications are not required
  895|       |        // to set the 71 and 72 fields, respectively, to valid values.
  896|       |        // So just fire a warning.
  897|     11|        if (iguess && line.counts.size() != iguess) {
  ------------------
  |  Branch (897:13): [True: 11, False: 0]
  |  Branch (897:23): [True: 2, False: 9]
  ------------------
  898|      2|            ASSIMP_LOG_WARN( "DXF: unexpected face count in polymesh: ", line.counts.size(),", expected ", iguess );
  899|      2|        }
  900|     11|    }
  901|      4|    else if (!line.indices.size() && !line.counts.size()) {
  ------------------
  |  Branch (901:14): [True: 3, False: 1]
  |  Branch (901:38): [True: 3, False: 0]
  ------------------
  902|       |        // a poly-line - so there are no indices yet.
  903|      3|        size_t guess = line.positions.size() + (line.flags & DXF_POLYLINE_FLAG_CLOSED ? 1 : 0);
  ------------------
  |  Branch (903:49): [True: 1, False: 2]
  ------------------
  904|      3|        line.indices.reserve(guess);
  905|       |
  906|      3|        line.counts.reserve(guess/2);
  907|      8|        for (unsigned int i = 0; i < line.positions.size()/2; ++i) {
  ------------------
  |  Branch (907:34): [True: 5, False: 3]
  ------------------
  908|      5|            line.indices.push_back(i*2);
  909|      5|            line.indices.push_back(i*2+1);
  910|      5|            line.counts.push_back(2);
  911|      5|        }
  912|       |
  913|       |        // closed polyline?
  914|      3|        if (line.flags & DXF_POLYLINE_FLAG_CLOSED) {
  ------------------
  |  Branch (914:13): [True: 1, False: 2]
  ------------------
  915|      1|            line.indices.push_back(static_cast<unsigned int>(line.positions.size()-1));
  916|      1|            line.indices.push_back(0);
  917|      1|            line.counts.push_back(2);
  918|      1|        }
  919|      3|    }
  920|    369|}
_ZN6Assimp11DXFImporter19ParsePolyLineVertexERNS_3DXF10LineReaderERNS1_8PolyLineE:
  926|  12.8k|void DXFImporter::ParsePolyLineVertex(DXF::LineReader& reader, DXF::PolyLine& line) {
  927|  12.8k|    unsigned int cnti = 0, flags = 0;
  928|  12.8k|    unsigned int indices[4];
  929|       |
  930|  12.8k|    aiVector3D out;
  931|  12.8k|    aiColor4D clr = AI_DXF_DEFAULT_COLOR;
  932|       |
  933|   116k|    while( !reader.End() ) {
  ------------------
  |  Branch (933:12): [True: 116k, False: 1]
  ------------------
  934|       |
  935|   116k|        if (reader.Is(0)) { // SEQEND or another VERTEX
  ------------------
  |  Branch (935:13): [True: 12.8k, False: 103k]
  ------------------
  936|  12.8k|            break;
  937|  12.8k|        }
  938|       |
  939|   103k|        switch (reader.GroupCode()) {
  ------------------
  |  Branch (939:17): [True: 81.2k, False: 22.2k]
  ------------------
  940|  10.7k|        case 8:
  ------------------
  |  Branch (940:9): [True: 10.7k, False: 92.7k]
  ------------------
  941|       |                // layer to which the vertex belongs to - assume that
  942|       |                // this is always the layer the top-level poly-line
  943|       |                // entity resides on as well.
  944|  10.7k|                if(reader.Value() != line.layer) {
  ------------------
  |  Branch (944:20): [True: 0, False: 10.7k]
  ------------------
  945|      0|                    ASSIMP_LOG_WARN("DXF: expected vertex to be part of a poly-face but the 0x128 flag isn't set");
  946|      0|                }
  947|  10.7k|                break;
  948|       |
  949|  12.7k|        case 70:
  ------------------
  |  Branch (949:9): [True: 12.7k, False: 90.7k]
  ------------------
  950|  12.7k|                flags = reader.ValueAsUnsignedInt();
  951|  12.7k|                break;
  952|       |
  953|       |        // VERTEX COORDINATES
  954|  10.7k|        case GroupCode_XComp:
  ------------------
  |  Branch (954:9): [True: 10.7k, False: 92.7k]
  ------------------
  955|  10.7k|            out.x = reader.ValueAsFloat();
  956|  10.7k|            break;
  957|       |
  958|  10.7k|        case GroupCode_YComp:
  ------------------
  |  Branch (958:9): [True: 10.7k, False: 92.7k]
  ------------------
  959|  10.7k|            out.y = reader.ValueAsFloat();
  960|  10.7k|            break;
  961|       |
  962|  10.7k|        case GroupCode_ZComp:
  ------------------
  |  Branch (962:9): [True: 10.7k, False: 92.7k]
  ------------------
  963|  10.7k|            out.z = reader.ValueAsFloat();
  964|  10.7k|            break;
  965|       |
  966|       |        // POLYFACE vertex indices
  967|  5.77k|        case 71:
  ------------------
  |  Branch (967:9): [True: 5.77k, False: 97.7k]
  ------------------
  968|  11.5k|        case 72:
  ------------------
  |  Branch (968:9): [True: 5.77k, False: 97.7k]
  ------------------
  969|  17.3k|        case 73:
  ------------------
  |  Branch (969:9): [True: 5.77k, False: 97.7k]
  ------------------
  970|  17.8k|        case 74: {
  ------------------
  |  Branch (970:9): [True: 527, False: 102k]
  ------------------
  971|  17.8k|                if (cnti == 4) {
  ------------------
  |  Branch (971:21): [True: 2, False: 17.8k]
  ------------------
  972|      2|                    ASSIMP_LOG_WARN("DXF: more than 4 indices per face not supported; ignoring");
  973|      2|                    break;
  974|      2|                }
  975|  17.8k|                const int index = reader.ValueAsSignedInt();
  976|  17.8k|                if (index >= 0) {
  ------------------
  |  Branch (976:21): [True: 17.2k, False: 596]
  ------------------
  977|  17.2k|                    indices[cnti++] = static_cast<unsigned int>(index);
  978|  17.2k|                } else {
  979|    596|                    indices[cnti++] = static_cast<unsigned int>(-index);
  980|    596|                }
  981|  17.8k|            }
  982|      0|            break;
  983|       |
  984|       |        // color
  985|  7.57k|        case 62:
  ------------------
  |  Branch (985:9): [True: 7.57k, False: 95.9k]
  ------------------
  986|  7.57k|            clr = g_aclrDxfIndexColors[reader.ValueAsUnsignedInt() % AI_DXF_NUM_INDEX_COLORS];
  ------------------
  |  |  333|  7.57k|#define AI_DXF_NUM_INDEX_COLORS (sizeof(g_aclrDxfIndexColors)/sizeof(g_aclrDxfIndexColors[0]))
  ------------------
  987|  7.57k|            break;
  988|   103k|        };
  989|       |
  990|   103k|        reader++;
  991|   103k|    }
  992|       |
  993|  12.8k|    if (line.flags & DXF_POLYLINE_FLAG_POLYFACEMESH && !(flags & DXF_VERTEX_FLAG_PART_OF_POLYFACE)) {
  ------------------
  |  |  922|  11.8k|#define DXF_VERTEX_FLAG_PART_OF_POLYFACE 0x80
  ------------------
  |  Branch (993:9): [True: 11.8k, False: 1.02k]
  |  Branch (993:56): [True: 357, False: 11.4k]
  ------------------
  994|    357|        ASSIMP_LOG_WARN("DXF: expected vertex to be part of a polyface but the 0x128 flag isn't set");
  995|    357|    }
  996|       |
  997|  12.8k|    if (cnti) {
  ------------------
  |  Branch (997:9): [True: 5.91k, False: 6.94k]
  ------------------
  998|  5.91k|        line.counts.push_back(cnti);
  999|  23.7k|        for (unsigned int i = 0; i < cnti; ++i) {
  ------------------
  |  Branch (999:34): [True: 17.8k, False: 5.91k]
  ------------------
 1000|       |            // IMPORTANT NOTE: POLYMESH indices are ONE-BASED
 1001|  17.8k|            if (indices[i] == 0) {
  ------------------
  |  Branch (1001:17): [True: 0, False: 17.8k]
  ------------------
 1002|      0|                ASSIMP_LOG_WARN("DXF: invalid vertex index, indices are one-based.");
 1003|      0|                --line.counts.back();
 1004|       |                // Workaround to fix issue 2229
 1005|      0|                if (line.counts.back() == 0) {
  ------------------
  |  Branch (1005:21): [True: 0, False: 0]
  ------------------
 1006|      0|                    line.counts.pop_back();
 1007|      0|                }
 1008|      0|                continue;
 1009|      0|            }
 1010|  17.8k|            line.indices.push_back(indices[i]-1);
 1011|  17.8k|        }
 1012|  6.94k|    } else {
 1013|  6.94k|        line.positions.push_back(out);
 1014|  6.94k|        line.colors.push_back(clr);
 1015|  6.94k|    }
 1016|  12.8k|}
_ZN6Assimp11DXFImporter11Parse3DFaceERNS_3DXF10LineReaderERNS1_8FileDataE:
 1019|  1.63k|void DXFImporter::Parse3DFace(DXF::LineReader& reader, DXF::FileData& output) {
 1020|       |    // (note) this is also used for for parsing line entities, so we
 1021|       |    // must handle the vertex_count == 2 case as well.
 1022|       |
 1023|  1.63k|    output.blocks.back().lines.push_back( std::shared_ptr<DXF::PolyLine>( new DXF::PolyLine() )  );
 1024|  1.63k|    DXF::PolyLine& line = *output.blocks.back().lines.back();
 1025|       |
 1026|  1.63k|    aiVector3D vip[4];
 1027|  1.63k|    aiColor4D  clr = AI_DXF_DEFAULT_COLOR;
 1028|       |
 1029|  1.63k|    bool b[4] = {false,false,false,false};
 1030|  11.6k|    while( !reader.End() ) {
  ------------------
  |  Branch (1030:12): [True: 11.6k, False: 2]
  ------------------
 1031|       |
 1032|       |        // next entity with a groupcode == 0 is probably already the next vertex or polymesh entity
 1033|  11.6k|        if (reader.GroupCode() == 0) {
  ------------------
  |  Branch (1033:13): [True: 1.62k, False: 10.0k]
  ------------------
 1034|  1.62k|            break;
 1035|  1.62k|        }
 1036|  10.0k|        switch (reader.GroupCode()) {
  ------------------
  |  Branch (1036:17): [True: 9.15k, False: 913]
  ------------------
 1037|       |
 1038|       |        // 8 specifies the layer
 1039|    352|        case 8:
  ------------------
  |  Branch (1039:9): [True: 352, False: 9.71k]
  ------------------
 1040|    352|            line.layer = reader.Value();
 1041|    352|            break;
 1042|       |
 1043|       |        // x position of the first corner
 1044|    848|        case 10:
  ------------------
  |  Branch (1044:9): [True: 848, False: 9.22k]
  ------------------
 1045|    848|            vip[0].x = reader.ValueAsFloat();
 1046|    848|            b[2] = true;
 1047|    848|            break;
 1048|       |
 1049|       |        // y position of the first corner
 1050|    288|        case 20:
  ------------------
  |  Branch (1050:9): [True: 288, False: 9.78k]
  ------------------
 1051|    288|            vip[0].y = reader.ValueAsFloat();
 1052|    288|            b[2] = true;
 1053|    288|            break;
 1054|       |
 1055|       |        // z position of the first corner
 1056|  1.22k|        case 30:
  ------------------
  |  Branch (1056:9): [True: 1.22k, False: 8.84k]
  ------------------
 1057|  1.22k|            vip[0].z = reader.ValueAsFloat();
 1058|  1.22k|            b[2] = true;
 1059|  1.22k|            break;
 1060|       |
 1061|       |        // x position of the second corner
 1062|    701|        case 11:
  ------------------
  |  Branch (1062:9): [True: 701, False: 9.36k]
  ------------------
 1063|    701|            vip[1].x = reader.ValueAsFloat();
 1064|    701|            b[3] = true;
 1065|    701|            break;
 1066|       |
 1067|       |        // y position of the second corner
 1068|    288|        case 21:
  ------------------
  |  Branch (1068:9): [True: 288, False: 9.78k]
  ------------------
 1069|    288|            vip[1].y = reader.ValueAsFloat();
 1070|    288|            b[3] = true;
 1071|    288|            break;
 1072|       |
 1073|       |        // z position of the second corner
 1074|  1.20k|        case 31:
  ------------------
  |  Branch (1074:9): [True: 1.20k, False: 8.85k]
  ------------------
 1075|  1.20k|            vip[1].z = reader.ValueAsFloat();
 1076|  1.20k|            b[3] = true;
 1077|  1.20k|            break;
 1078|       |
 1079|       |        // x position of the third corner
 1080|    293|        case 12:
  ------------------
  |  Branch (1080:9): [True: 293, False: 9.77k]
  ------------------
 1081|    293|            vip[2].x = reader.ValueAsFloat();
 1082|    293|            b[0] = true;
 1083|    293|            break;
 1084|       |
 1085|       |        // y position of the third corner
 1086|    288|        case 22:
  ------------------
  |  Branch (1086:9): [True: 288, False: 9.78k]
  ------------------
 1087|    288|            vip[2].y = reader.ValueAsFloat();
 1088|    288|            b[0] = true;
 1089|    288|            break;
 1090|       |
 1091|       |        // z position of the third corner
 1092|  1.62k|        case 32:
  ------------------
  |  Branch (1092:9): [True: 1.62k, False: 8.44k]
  ------------------
 1093|  1.62k|            vip[2].z = reader.ValueAsFloat();
 1094|  1.62k|            b[0] = true;
 1095|  1.62k|            break;
 1096|       |
 1097|       |        // x position of the fourth corner
 1098|    645|        case 13:
  ------------------
  |  Branch (1098:9): [True: 645, False: 9.42k]
  ------------------
 1099|    645|            vip[3].x = reader.ValueAsFloat();
 1100|    645|            b[1] = true;
 1101|    645|            break;
 1102|       |
 1103|       |        // y position of the fourth corner
 1104|    671|        case 23:
  ------------------
  |  Branch (1104:9): [True: 671, False: 9.39k]
  ------------------
 1105|    671|            vip[3].y = reader.ValueAsFloat();
 1106|    671|            b[1] = true;
 1107|    671|            break;
 1108|       |
 1109|       |        // z position of the fourth corner
 1110|    527|        case 33:
  ------------------
  |  Branch (1110:9): [True: 527, False: 9.54k]
  ------------------
 1111|    527|            vip[3].z = reader.ValueAsFloat();
 1112|    527|            b[1] = true;
 1113|    527|            break;
 1114|       |
 1115|       |        // color
 1116|    197|        case 62:
  ------------------
  |  Branch (1116:9): [True: 197, False: 9.87k]
  ------------------
 1117|    197|            clr = g_aclrDxfIndexColors[reader.ValueAsUnsignedInt() % AI_DXF_NUM_INDEX_COLORS];
  ------------------
  |  |  333|    197|#define AI_DXF_NUM_INDEX_COLORS (sizeof(g_aclrDxfIndexColors)/sizeof(g_aclrDxfIndexColors[0]))
  ------------------
 1118|    197|            break;
 1119|  10.0k|        };
 1120|       |
 1121|  10.0k|        ++reader;
 1122|  10.0k|    }
 1123|       |
 1124|       |    // the fourth corner may even be identical to the third,
 1125|       |    // in this case we treat it as if it didn't exist.
 1126|  1.63k|    if (vip[3] == vip[2]) {
  ------------------
  |  Branch (1126:9): [True: 199, False: 1.43k]
  ------------------
 1127|    199|        b[1] = false;
 1128|    199|    }
 1129|       |
 1130|       |    // sanity checks to see if we got something meaningful
 1131|  1.63k|    if ((b[1] && !b[0]) || !b[2] || !b[3]) {
  ------------------
  |  Branch (1131:10): [True: 1.00k, False: 627]
  |  Branch (1131:18): [True: 56, False: 947]
  |  Branch (1131:28): [True: 141, False: 1.43k]
  |  Branch (1131:37): [True: 78, False: 1.35k]
  ------------------
 1132|    275|        ASSIMP_LOG_WARN("DXF: unexpected vertex setup in 3DFACE/LINE/FACE entity; ignoring");
 1133|    275|        output.blocks.back().lines.pop_back();
 1134|    275|        return;
 1135|    275|    }
 1136|       |
 1137|  1.35k|    const unsigned int cnt = (2+(b[0]?1:0)+(b[1]?1:0));
  ------------------
  |  Branch (1137:34): [True: 1.27k, False: 83]
  |  Branch (1137:45): [True: 928, False: 427]
  ------------------
 1138|  1.35k|    line.counts.push_back(cnt);
 1139|       |
 1140|  6.26k|    for (unsigned int i = 0; i < cnt; ++i) {
  ------------------
  |  Branch (1140:30): [True: 4.91k, False: 1.35k]
  ------------------
 1141|  4.91k|        line.indices.push_back(static_cast<unsigned int>(line.positions.size()));
 1142|  4.91k|        line.positions.push_back(vip[i]);
 1143|  4.91k|        line.colors.push_back(clr);
 1144|  4.91k|    }
 1145|  1.35k|}

_ZN6Assimp11DXFImporterC2Ev:
   71|    624|    DXFImporter() = default;

_ZN6Assimp3FBX4Node9AddP70intERKNSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEEi:
   64|  39.5k|void FBX::Node::AddP70int(const std::string& cur_name, int32_t value) {
   65|  39.5k|    FBX::Node n("P");
   66|  39.5k|    n.AddProperties(cur_name, "int", "Integer", "", value);
   67|  39.5k|    AddChild(n);
   68|  39.5k|}
_ZN6Assimp3FBX4Node10AddP70boolERKNSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEEb:
   70|  43.7k|void FBX::Node::AddP70bool(const std::string& cur_name, bool value) {
   71|  43.7k|    FBX::Node n("P");
   72|  43.7k|    n.AddProperties(cur_name, "bool", "", "", int32_t(value));
   73|  43.7k|    AddChild(n);
   74|  43.7k|}
_ZN6Assimp3FBX4Node12AddP70doubleERKNSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEEd:
   76|  5.83k|void FBX::Node::AddP70double(const std::string &cur_name, double value) {    FBX::Node n("P");
   77|  5.83k|    n.AddProperties(cur_name, "double", "Number", "", value);
   78|  5.83k|    AddChild(n);
   79|  5.83k|}
_ZN6Assimp3FBX4Node13AddP70numberAERKNSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEEd:
   81|  6.65k|void FBX::Node::AddP70numberA(const std::string &cur_name, double value) {
   82|  6.65k|    FBX::Node n("P");
   83|  6.65k|    n.AddProperties(cur_name, "Number", "", "A", value);
   84|  6.65k|    AddChild(n);
   85|  6.65k|}
_ZN6Assimp3FBX4Node11AddP70colorERKNSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEEddd:
   88|    964|        const std::string &cur_name, double r, double g, double b) {
   89|    964|    FBX::Node n("P");
   90|    964|    n.AddProperties(cur_name, "ColorRGB", "Color", "", r, g, b);
   91|    964|    AddChild(n);
   92|    964|}
_ZN6Assimp3FBX4Node12AddP70colorAERKNSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEEddd:
   95|  1.50k|        const std::string &cur_name, double r, double g, double b) {
   96|  1.50k|    FBX::Node n("P");
   97|  1.50k|    n.AddProperties(cur_name, "Color", "", "A", r, g, b);
   98|  1.50k|    AddChild(n);
   99|  1.50k|}
_ZN6Assimp3FBX4Node12AddP70vectorERKNSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEEddd:
  102|  4.74k|        const std::string &cur_name, double x, double y, double z) {
  103|  4.74k|    FBX::Node n("P");
  104|  4.74k|    n.AddProperties(cur_name, "Vector3D", "Vector", "", x, y, z);
  105|  4.74k|    AddChild(n);
  106|  4.74k|}
_ZN6Assimp3FBX4Node13AddP70vectorAERKNSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEEddd:
  109|    438|        const std::string &cur_name, double x, double y, double z) {
  110|    438|    FBX::Node n("P");
  111|    438|    n.AddProperties(cur_name, "Vector", "", "A", x, y, z);
  112|    438|    AddChild(n);
  113|    438|}
_ZN6Assimp3FBX4Node12AddP70stringERKNSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEESA_:
  116|    675|        const std::string &cur_name, const std::string &value) {
  117|    675|    FBX::Node n("P");
  118|    675|    n.AddProperties(cur_name, "KString", "", "", value);
  119|    675|    AddChild(n);
  120|    675|}
_ZN6Assimp3FBX4Node10AddP70enumERKNSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEEi:
  123|  38.9k|        const std::string &cur_name, int32_t value) {
  124|  38.9k|    FBX::Node n("P");
  125|  38.9k|    n.AddProperties(cur_name, "enum", "", "", value);
  126|  38.9k|    AddChild(n);
  127|  38.9k|}
_ZN6Assimp3FBX4Node10AddP70timeERKNSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEEl:
  130|    680|        const std::string &cur_name, int64_t value) {
  131|    680|    FBX::Node n("P");
  132|    680|    n.AddProperties(cur_name, "KTime", "Time", "", value);
  133|    680|    AddChild(n);
  134|    680|}
_ZN6Assimp3FBX4Node4DumpERKNSt3__110shared_ptrINS_8IOStreamEEEbi:
  141|    832|        bool binary, int indent) {
  142|    832|    if (binary) {
  ------------------
  |  Branch (142:9): [True: 832, False: 0]
  ------------------
  143|    832|        Assimp::StreamWriterLE outstream(outfile);
  144|    832|        DumpBinary(outstream);
  145|    832|    } else {
  146|      0|        std::ostringstream ss;
  147|      0|        DumpAscii(ss, indent);
  148|      0|        std::string s = ss.str();
  149|      0|        outfile->Write(s.c_str(), s.size(), 1);
  150|      0|    }
  151|    832|}
_ZN6Assimp3FBX4Node4DumpERNS_12StreamWriterILb0ELb0EEEbi:
  156|   222k|) {
  157|   222k|    if (binary) {
  ------------------
  |  Branch (157:9): [True: 222k, False: 0]
  ------------------
  158|   222k|        DumpBinary(outstream);
  159|   222k|    } else {
  160|      0|        std::ostringstream ss;
  161|      0|        DumpAscii(ss, indent);
  162|      0|        outstream.PutString(ss.str());
  163|      0|    }
  164|   222k|}
_ZN6Assimp3FBX4Node5BeginERNS_12StreamWriterILb0ELb0EEEbi:
  172|  25.7k|) {
  173|  25.7k|    if (binary) {
  ------------------
  |  Branch (173:9): [True: 25.7k, False: 0]
  ------------------
  174|  25.7k|        BeginBinary(s);
  175|  25.7k|    } else {
  176|       |        // assume we're at the correct place to start already
  177|      0|        (void)indent;
  178|      0|        std::ostringstream ss;
  179|      0|        BeginAscii(ss, indent);
  180|      0|        s.PutString(ss.str());
  181|      0|    }
  182|  25.7k|}
_ZN6Assimp3FBX4Node14DumpPropertiesERNS_12StreamWriterILb0ELb0EEEbi:
  187|  25.1k|) {
  188|  25.1k|    if (binary) {
  ------------------
  |  Branch (188:9): [True: 25.1k, False: 0]
  ------------------
  189|  25.1k|        DumpPropertiesBinary(s);
  190|  25.1k|    } else {
  191|      0|        std::ostringstream ss;
  192|      0|        DumpPropertiesAscii(ss, indent);
  193|      0|        s.PutString(ss.str());
  194|      0|    }
  195|  25.1k|}
_ZN6Assimp3FBX4Node13EndPropertiesERNS_12StreamWriterILb0ELb0EEEbi:
  200|  25.3k|) {
  201|  25.3k|    EndProperties(s, binary, indent, properties.size());
  202|  25.3k|}
_ZN6Assimp3FBX4Node13EndPropertiesERNS_12StreamWriterILb0ELb0EEEbim:
  208|  25.5k|) {
  209|  25.5k|    if (binary) {
  ------------------
  |  Branch (209:9): [True: 25.5k, False: 0]
  ------------------
  210|  25.5k|        EndPropertiesBinary(s, num_properties);
  211|  25.5k|    } else {
  212|       |        // nothing to do
  213|      0|        (void)indent;
  214|      0|    }
  215|  25.5k|}
_ZN6Assimp3FBX4Node13BeginChildrenERNS_12StreamWriterILb0ELb0EEEbi:
  220|  25.7k|) {
  221|  25.7k|    if (binary) {
  ------------------
  |  Branch (221:9): [True: 25.7k, False: 0]
  ------------------
  222|       |        // nothing to do
  223|  25.7k|    } else {
  224|      0|        std::ostringstream ss;
  225|      0|        BeginChildrenAscii(ss, indent);
  226|      0|        s.PutString(ss.str());
  227|      0|    }
  228|  25.7k|}
_ZN6Assimp3FBX4Node3EndERNS_12StreamWriterILb0ELb0EEEbib:
  248|  25.7k|) {
  249|  25.7k|    if (binary) {
  ------------------
  |  Branch (249:9): [True: 25.7k, False: 0]
  ------------------
  250|  25.7k|        EndBinary(s, has_children);
  251|  25.7k|    } else {
  252|      0|        std::ostringstream ss;
  253|      0|        EndAscii(ss, indent, has_children);
  254|      0|        if (ss.tellp() > 0)
  ------------------
  |  Branch (254:13): [True: 0, False: 0]
  ------------------
  255|      0|            s.PutString(ss.str());
  256|      0|    }
  257|  25.7k|}
_ZN6Assimp3FBX4Node10DumpBinaryERNS_12StreamWriterILb0ELb0EEE:
  263|   779k|{
  264|       |    // write header section (with placeholders for some things)
  265|   779k|    BeginBinary(s);
  266|       |
  267|       |    // write properties
  268|   779k|    DumpPropertiesBinary(s);
  269|       |
  270|       |    // go back and fill in property related placeholders
  271|   779k|    EndPropertiesBinary(s, properties.size());
  272|       |
  273|       |    // write children
  274|   779k|    DumpChildrenBinary(s);
  275|       |
  276|       |    // finish, filling in end offset placeholder
  277|   779k|    EndBinary(s, force_has_children || !children.empty());
  ------------------
  |  Branch (277:18): [True: 264, False: 779k]
  |  Branch (277:40): [True: 157k, False: 621k]
  ------------------
  278|   779k|}
_ZN6Assimp3FBX4Node11BeginBinaryERNS_12StreamWriterILb0ELb0EEE:
  306|   843k|{
  307|       |    // remember start pos so we can come back and write the end pos
  308|   843k|    this->start_pos = s.Tell();
  309|       |
  310|       |    // placeholders for end pos and property section info
  311|   843k|    s.PutU8(0); // end pos
  312|   843k|    s.PutU8(0); // number of properties
  313|   843k|    s.PutU8(0); // total property section length
  314|       |
  315|       |    // node name
  316|   843k|    s.PutU1(uint8_t(name.size())); // length of node name
  317|   843k|    s.PutString(name); // node name as raw bytes
  318|       |
  319|       |    // property data comes after here
  320|   843k|    this->property_start = s.Tell();
  321|   843k|}
_ZN6Assimp3FBX4Node20DumpPropertiesBinaryERNS_12StreamWriterILb0ELb0EEE:
  324|   805k|{
  325|  1.63M|    for (auto &p : properties) {
  ------------------
  |  Branch (325:18): [True: 1.63M, False: 805k]
  ------------------
  326|  1.63M|        p.DumpBinary(s);
  327|  1.63M|    }
  328|   805k|}
_ZN6Assimp3FBX4Node19EndPropertiesBinaryERNS_12StreamWriterILb0ELb0EEEm:
  333|   843k|) {
  334|   843k|    if (num_properties == 0) { return; }
  ------------------
  |  Branch (334:9): [True: 79.8k, False: 763k]
  ------------------
  335|   763k|    size_t pos = s.Tell();
  336|       |    ai_assert(pos > property_start);
  337|   763k|    size_t property_section_size = pos - property_start;
  338|   763k|    s.Seek(start_pos + 8); // 8 bytes of uint64_t of end_pos
  339|   763k|    s.PutU8(num_properties);
  340|   763k|    s.PutU8(property_section_size);
  341|   763k|    s.Seek(pos);
  342|   763k|}
_ZN6Assimp3FBX4Node18DumpChildrenBinaryERNS_12StreamWriterILb0ELb0EEE:
  345|   779k|{
  346|   779k|    for (FBX::Node& child : children) {
  ------------------
  |  Branch (346:27): [True: 556k, False: 779k]
  ------------------
  347|   556k|        child.DumpBinary(s);
  348|   556k|    }
  349|   779k|}
_ZN6Assimp3FBX4Node9EndBinaryERNS_12StreamWriterILb0ELb0EEEb:
  354|   843k|) {
  355|       |    // if there were children, add a null record
  356|   843k|    if (has_children) { s.PutString(Assimp::FBX::NULL_RECORD_STRING); }
  ------------------
  |  Branch (356:9): [True: 183k, False: 659k]
  ------------------
  357|       |
  358|       |    // now go back and write initial pos
  359|   843k|    this->end_pos = s.Tell();
  360|   843k|    s.Seek(start_pos);
  361|   843k|    s.PutU8(end_pos);
  362|   843k|    s.Seek(end_pos);
  363|   843k|}
_ZN6Assimp3FBX4Node23WritePropertyNodeBinaryERKNSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEERKNS2_6vectorIdNS6_IdEEEERNS_12StreamWriterILb0ELb0EEE:
  487|  25.1k|){
  488|  25.1k|    FBX::Node node(name);
  489|  25.1k|    node.BeginBinary(s);
  490|  25.1k|    s.PutU1('d');
  491|  25.1k|    s.PutU4(uint32_t(v.size())); // number of elements
  492|  25.1k|    s.PutU4(0); // no encoding (1 would be zip-compressed)
  493|  25.1k|    s.PutU4(uint32_t(v.size()) * 8); // data size
  494|  19.2M|    for (auto it = v.begin(); it != v.end(); ++it) { s.PutF8(*it); }
  ------------------
  |  Branch (494:31): [True: 19.1M, False: 25.1k]
  ------------------
  495|  25.1k|    node.EndPropertiesBinary(s, 1);
  496|  25.1k|    node.EndBinary(s, false);
  497|  25.1k|}
_ZN6Assimp3FBX4Node23WritePropertyNodeBinaryERKNSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEERKNS2_6vectorIiNS6_IiEEEERNS_12StreamWriterILb0ELb0EEE:
  505|  12.8k|){
  506|  12.8k|    FBX::Node node(name);
  507|  12.8k|    node.BeginBinary(s);
  508|  12.8k|    s.PutU1('i');
  509|  12.8k|    s.PutU4(uint32_t(v.size())); // number of elements
  510|  12.8k|    s.PutU4(0); // no encoding (1 would be zip-compressed)
  511|  12.8k|    s.PutU4(uint32_t(v.size()) * 4); // data size
  512|  5.74M|    for (auto it = v.begin(); it != v.end(); ++it) { s.PutI4(*it); }
  ------------------
  |  Branch (512:31): [True: 5.72M, False: 12.8k]
  ------------------
  513|  12.8k|    node.EndPropertiesBinary(s, 1);
  514|  12.8k|    node.EndBinary(s, false);
  515|  12.8k|}
_ZN6Assimp3FBX4Node17WritePropertyNodeERKNSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEERKNS2_6vectorIdNS6_IdEEEERNS_12StreamWriterILb0ELb0EEEbi:
  527|  25.1k|){
  528|  25.1k|    if (binary) {
  ------------------
  |  Branch (528:9): [True: 25.1k, False: 0]
  ------------------
  529|  25.1k|        FBX::Node::WritePropertyNodeBinary(name, v, s);
  530|  25.1k|    } else {
  531|      0|        FBX::Node::WritePropertyNodeAscii(name, v, s, indent);
  532|      0|    }
  533|  25.1k|}
_ZN6Assimp3FBX4Node17WritePropertyNodeERKNSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEERKNS2_6vectorIiNS6_IiEEEERNS_12StreamWriterILb0ELb0EEEbi:
  543|  12.8k|){
  544|  12.8k|    if (binary) {
  ------------------
  |  Branch (544:9): [True: 12.8k, False: 0]
  ------------------
  545|  12.8k|        FBX::Node::WritePropertyNodeBinary(name, v, s);
  546|  12.8k|    } else {
  547|      0|        FBX::Node::WritePropertyNodeAscii(name, v, s, indent);
  548|      0|    }
  549|  12.8k|}

_ZN6Assimp3FBX4NodeC2ERKNSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEE:
   77|   657k|    : name(n)
   78|   657k|    , force_has_children( false ) {
   79|       |        // empty
   80|   657k|    }
_ZN6Assimp3FBX4Node8AddChildERKS1_:
  105|   228k|    void AddChild(const Node& node) { children.push_back(node); }
_ZN6Assimp3FBX4NodeC2Ev:
   73|  13.2k|    Node() = default;
_ZN6Assimp3FBX4Node17WritePropertyNodeIiEEvRKNSt3__112basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEET_RNS_12StreamWriterILb0ELb0EEEbi:
  180|  25.7k|    ) {
  181|  25.7k|        FBX::FBXExportProperty p(value);
  182|  25.7k|        FBX::Node node(name, std::move(p));
  183|  25.7k|        node.Dump(s, binary, indent);
  184|  25.7k|    }
_ZN6Assimp3FBX4NodeC2IJNS0_17FBXExportPropertyEEEERKNSt3__112basic_stringIcNS4_11char_traitsIcEENS4_9allocatorIcEEEEDpOT_:
   85|  64.0k|    : name(n)
   86|  64.0k|    , force_has_children(false) {
   87|  64.0k|        AddProperties(std::forward<More>(more)...);
   88|  64.0k|    }
_ZN6Assimp3FBX4Node13AddPropertiesINS0_17FBXExportPropertyEJEEEvOT_DpOT0_:
   98|   141k|    void AddProperties(T&& value, More&&... more) {
   99|   141k|        properties.emplace_back(std::forward<T>(value));
  100|   141k|        AddProperties(std::forward<More>(more)...);
  101|   141k|    }
_ZN6Assimp3FBX4Node13AddPropertiesEv:
  102|   712k|    void AddProperties() {}
_ZN6Assimp3FBX4Node8AddChildIJiEEEvRKNSt3__112basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEEDpOT_:
  112|   111k|    ) {
  113|   111k|        FBX::Node c(name);
  114|   111k|        c.AddProperties(std::forward<More>(more)...);
  115|   111k|        children.push_back(std::move(c));
  116|   111k|    }
_ZN6Assimp3FBX4Node13AddPropertiesIiJEEEvOT_DpOT0_:
   98|   193k|    void AddProperties(T&& value, More&&... more) {
   99|   193k|        properties.emplace_back(std::forward<T>(value));
  100|   193k|        AddProperties(std::forward<More>(more)...);
  101|   193k|    }
_ZN6Assimp3FBX4Node17WritePropertyNodeINSt3__112basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEEEEvRKS9_T_RNS_12StreamWriterILb0ELb0EEEbi:
  180|    624|    ) {
  181|    624|        FBX::FBXExportProperty p(value);
  182|    624|        FBX::Node node(name, std::move(p));
  183|    624|        node.Dump(s, binary, indent);
  184|    624|    }
_ZN6Assimp3FBX4Node17WritePropertyNodeINSt3__16vectorIhNS3_9allocatorIhEEEEEEvRKNS3_12basic_stringIcNS3_11char_traitsIcEENS5_IcEEEET_RNS_12StreamWriterILb0ELb0EEEbi:
  180|    208|    ) {
  181|    208|        FBX::FBXExportProperty p(value);
  182|    208|        FBX::Node node(name, std::move(p));
  183|    208|        node.Dump(s, binary, indent);
  184|    208|    }
_ZN6Assimp3FBX4Node6AddP70IJEEEvRKNSt3__112basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEESB_SB_SB_DpOT_:
  142|    858|    ) {
  143|    858|        Node n("P");
  144|    858|        n.AddProperties(name, type, type2, flags, std::forward<More>(more)...);
  145|    858|        AddChild(n);
  146|    858|    }
_ZN6Assimp3FBX4Node13AddPropertiesIRKNSt3__112basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEEJSB_SB_SB_EEEvOT_DpOT0_:
   98|    858|    void AddProperties(T&& value, More&&... more) {
   99|    858|        properties.emplace_back(std::forward<T>(value));
  100|    858|        AddProperties(std::forward<More>(more)...);
  101|    858|    }
_ZN6Assimp3FBX4Node13AddPropertiesIRKNSt3__112basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEEJSB_SB_EEEvOT_DpOT0_:
   98|    858|    void AddProperties(T&& value, More&&... more) {
   99|    858|        properties.emplace_back(std::forward<T>(value));
  100|    858|        AddProperties(std::forward<More>(more)...);
  101|    858|    }
_ZN6Assimp3FBX4Node13AddPropertiesIRKNSt3__112basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEEJSB_EEEvOT_DpOT0_:
   98|    858|    void AddProperties(T&& value, More&&... more) {
   99|    858|        properties.emplace_back(std::forward<T>(value));
  100|    858|        AddProperties(std::forward<More>(more)...);
  101|    858|    }
_ZN6Assimp3FBX4Node13AddPropertiesIRKNSt3__112basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEEJEEEvOT_DpOT0_:
   98|  46.1k|    void AddProperties(T&& value, More&&... more) {
   99|  46.1k|        properties.emplace_back(std::forward<T>(value));
  100|  46.1k|        AddProperties(std::forward<More>(more)...);
  101|  46.1k|    }
_ZN6Assimp3FBX4Node13AddPropertiesIRlJRA1_KcRA6_S4_EEEvOT_DpOT0_:
   98|    208|    void AddProperties(T&& value, More&&... more) {
   99|    208|        properties.emplace_back(std::forward<T>(value));
  100|    208|        AddProperties(std::forward<More>(more)...);
  101|    208|    }
_ZN6Assimp3FBX4Node13AddPropertiesIRA1_KcJRA6_S3_EEEvOT_DpOT0_:
   98|    208|    void AddProperties(T&& value, More&&... more) {
   99|    208|        properties.emplace_back(std::forward<T>(value));
  100|    208|        AddProperties(std::forward<More>(more)...);
  101|    208|    }
_ZN6Assimp3FBX4Node13AddPropertiesIRA6_KcJEEEvOT_DpOT0_:
   98|    613|    void AddProperties(T&& value, More&&... more) {
   99|    613|        properties.emplace_back(std::forward<T>(value));
  100|    613|        AddProperties(std::forward<More>(more)...);
  101|    613|    }
_ZN6Assimp3FBX4Node8AddChildIJlEEEvRKNSt3__112basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEEDpOT_:
  112|    208|    ) {
  113|    208|        FBX::Node c(name);
  114|    208|        c.AddProperties(std::forward<More>(more)...);
  115|    208|        children.push_back(std::move(c));
  116|    208|    }
_ZN6Assimp3FBX4Node13AddPropertiesIlJEEEvOT_DpOT0_:
   98|    234|    void AddProperties(T&& value, More&&... more) {
   99|    234|        properties.emplace_back(std::forward<T>(value));
  100|    234|        AddProperties(std::forward<More>(more)...);
  101|    234|    }
_ZN6Assimp3FBX4NodeC2IJRA15_KcEEERKNSt3__112basic_stringIcNS6_11char_traitsIcEENS6_9allocatorIcEEEEDpOT_:
   85|    334|    : name(n)
   86|    334|    , force_has_children(false) {
   87|    334|        AddProperties(std::forward<More>(more)...);
   88|    334|    }
_ZN6Assimp3FBX4Node13AddPropertiesIRA15_KcJEEEvOT_DpOT0_:
   98|  12.9k|    void AddProperties(T&& value, More&&... more) {
   99|  12.9k|        properties.emplace_back(std::forward<T>(value));
  100|  12.9k|        AddProperties(std::forward<More>(more)...);
  101|  12.9k|    }
_ZN6Assimp3FBX4Node8AddChildIJRiEEEvRKNSt3__112basic_stringIcNS4_11char_traitsIcEENS4_9allocatorIcEEEEDpOT_:
  112|  1.21k|    ) {
  113|  1.21k|        FBX::Node c(name);
  114|  1.21k|        c.AddProperties(std::forward<More>(more)...);
  115|  1.21k|        children.push_back(std::move(c));
  116|  1.21k|    }
_ZN6Assimp3FBX4Node13AddPropertiesIRiJEEEvOT_DpOT0_:
   98|  79.7k|    void AddProperties(T&& value, More&&... more) {
   99|  79.7k|        properties.emplace_back(std::forward<T>(value));
  100|  79.7k|        AddProperties(std::forward<More>(more)...);
  101|  79.7k|    }
_ZN6Assimp3FBX4NodeC2IJRA13_KcEEERKNSt3__112basic_stringIcNS6_11char_traitsIcEENS6_9allocatorIcEEEEDpOT_:
   85|     52|    : name(n)
   86|     52|    , force_has_children(false) {
   87|     52|        AddProperties(std::forward<More>(more)...);
   88|     52|    }
_ZN6Assimp3FBX4Node13AddPropertiesIRA13_KcJEEEvOT_DpOT0_:
   98|     52|    void AddProperties(T&& value, More&&... more) {
   99|     52|        properties.emplace_back(std::forward<T>(value));
  100|     52|        AddProperties(std::forward<More>(more)...);
  101|     52|    }
_ZN6Assimp3FBX4Node6AddP70IJdEEEvRKNSt3__112basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEESB_SB_SB_DpOT_:
  142|    442|    ) {
  143|    442|        Node n("P");
  144|    442|        n.AddProperties(name, type, type2, flags, std::forward<More>(more)...);
  145|    442|        AddChild(n);
  146|    442|    }
_ZN6Assimp3FBX4Node13AddPropertiesIRKNSt3__112basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEEJSB_SB_SB_dEEEvOT_DpOT0_:
   98|    442|    void AddProperties(T&& value, More&&... more) {
   99|    442|        properties.emplace_back(std::forward<T>(value));
  100|    442|        AddProperties(std::forward<More>(more)...);
  101|    442|    }
_ZN6Assimp3FBX4Node13AddPropertiesIRKNSt3__112basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEEJSB_SB_dEEEvOT_DpOT0_:
   98|    442|    void AddProperties(T&& value, More&&... more) {
   99|    442|        properties.emplace_back(std::forward<T>(value));
  100|    442|        AddProperties(std::forward<More>(more)...);
  101|    442|    }
_ZN6Assimp3FBX4Node13AddPropertiesIRKNSt3__112basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEEJSB_dEEEvOT_DpOT0_:
   98|    442|    void AddProperties(T&& value, More&&... more) {
   99|    442|        properties.emplace_back(std::forward<T>(value));
  100|    442|        AddProperties(std::forward<More>(more)...);
  101|    442|    }
_ZN6Assimp3FBX4Node13AddPropertiesIRKNSt3__112basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEEJdEEEvOT_DpOT0_:
   98|    442|    void AddProperties(T&& value, More&&... more) {
   99|    442|        properties.emplace_back(std::forward<T>(value));
  100|    442|        AddProperties(std::forward<More>(more)...);
  101|    442|    }
_ZN6Assimp3FBX4Node13AddPropertiesIdJEEEvOT_DpOT0_:
   98|  2.49k|    void AddProperties(T&& value, More&&... more) {
   99|  2.49k|        properties.emplace_back(std::forward<T>(value));
  100|  2.49k|        AddProperties(std::forward<More>(more)...);
  101|  2.49k|    }
_ZN6Assimp3FBX4Node6AddP70IJiEEEvRKNSt3__112basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEESB_SB_SB_DpOT_:
  142|    286|    ) {
  143|    286|        Node n("P");
  144|    286|        n.AddProperties(name, type, type2, flags, std::forward<More>(more)...);
  145|    286|        AddChild(n);
  146|    286|    }
_ZN6Assimp3FBX4Node13AddPropertiesIRKNSt3__112basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEEJSB_SB_SB_iEEEvOT_DpOT0_:
   98|    286|    void AddProperties(T&& value, More&&... more) {
   99|    286|        properties.emplace_back(std::forward<T>(value));
  100|    286|        AddProperties(std::forward<More>(more)...);
  101|    286|    }
_ZN6Assimp3FBX4Node13AddPropertiesIRKNSt3__112basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEEJSB_SB_iEEEvOT_DpOT0_:
   98|    286|    void AddProperties(T&& value, More&&... more) {
   99|    286|        properties.emplace_back(std::forward<T>(value));
  100|    286|        AddProperties(std::forward<More>(more)...);
  101|    286|    }
_ZN6Assimp3FBX4Node13AddPropertiesIRKNSt3__112basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEEJSB_iEEEvOT_DpOT0_:
   98|    286|    void AddProperties(T&& value, More&&... more) {
   99|    286|        properties.emplace_back(std::forward<T>(value));
  100|    286|        AddProperties(std::forward<More>(more)...);
  101|    286|    }
_ZN6Assimp3FBX4Node13AddPropertiesIRKNSt3__112basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEEJiEEEvOT_DpOT0_:
   98|    286|    void AddProperties(T&& value, More&&... more) {
   99|    286|        properties.emplace_back(std::forward<T>(value));
  100|    286|        AddProperties(std::forward<More>(more)...);
  101|    286|    }
_ZN6Assimp3FBX4Node6AddP70IJlEEEvRKNSt3__112basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEESB_SB_SB_DpOT_:
  142|     26|    ) {
  143|     26|        Node n("P");
  144|     26|        n.AddProperties(name, type, type2, flags, std::forward<More>(more)...);
  145|     26|        AddChild(n);
  146|     26|    }
_ZN6Assimp3FBX4Node13AddPropertiesIRKNSt3__112basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEEJSB_SB_SB_lEEEvOT_DpOT0_:
   98|     26|    void AddProperties(T&& value, More&&... more) {
   99|     26|        properties.emplace_back(std::forward<T>(value));
  100|     26|        AddProperties(std::forward<More>(more)...);
  101|     26|    }
_ZN6Assimp3FBX4Node13AddPropertiesIRKNSt3__112basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEEJSB_SB_lEEEvOT_DpOT0_:
   98|     26|    void AddProperties(T&& value, More&&... more) {
   99|     26|        properties.emplace_back(std::forward<T>(value));
  100|     26|        AddProperties(std::forward<More>(more)...);
  101|     26|    }
_ZN6Assimp3FBX4Node13AddPropertiesIRKNSt3__112basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEEJSB_lEEEvOT_DpOT0_:
   98|     26|    void AddProperties(T&& value, More&&... more) {
   99|     26|        properties.emplace_back(std::forward<T>(value));
  100|     26|        AddProperties(std::forward<More>(more)...);
  101|     26|    }
_ZN6Assimp3FBX4Node13AddPropertiesIRKNSt3__112basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEEJlEEEvOT_DpOT0_:
   98|     26|    void AddProperties(T&& value, More&&... more) {
   99|     26|        properties.emplace_back(std::forward<T>(value));
  100|     26|        AddProperties(std::forward<More>(more)...);
  101|     26|    }
_ZN6Assimp3FBX4NodeC2IJRA14_KcEEERKNSt3__112basic_stringIcNS6_11char_traitsIcEENS6_9allocatorIcEEEEDpOT_:
   85|    208|    : name(n)
   86|    208|    , force_has_children(false) {
   87|    208|        AddProperties(std::forward<More>(more)...);
   88|    208|    }
_ZN6Assimp3FBX4Node13AddPropertiesIRA14_KcJEEEvOT_DpOT0_:
   98|  12.8k|    void AddProperties(T&& value, More&&... more) {
   99|  12.8k|        properties.emplace_back(std::forward<T>(value));
  100|  12.8k|        AddProperties(std::forward<More>(more)...);
  101|  12.8k|    }
_ZN6Assimp3FBX4NodeC2IJRA12_KcEEERKNSt3__112basic_stringIcNS6_11char_traitsIcEENS6_9allocatorIcEEEEDpOT_:
   85|    208|    : name(n)
   86|    208|    , force_has_children(false) {
   87|    208|        AddProperties(std::forward<More>(more)...);
   88|    208|    }
_ZN6Assimp3FBX4Node13AddPropertiesIRA12_KcJEEEvOT_DpOT0_:
   98|    208|    void AddProperties(T&& value, More&&... more) {
   99|    208|        properties.emplace_back(std::forward<T>(value));
  100|    208|        AddProperties(std::forward<More>(more)...);
  101|    208|    }
_ZN6Assimp3FBX4NodeC2IJRA6_KcEEERKNSt3__112basic_stringIcNS6_11char_traitsIcEENS6_9allocatorIcEEEEDpOT_:
   85|    256|    : name(n)
   86|    256|    , force_has_children(false) {
   87|    256|        AddProperties(std::forward<More>(more)...);
   88|    256|    }
_ZN6Assimp3FBX4NodeC2IJRA8_KcEEERKNSt3__112basic_stringIcNS6_11char_traitsIcEENS6_9allocatorIcEEEEDpOT_:
   85|    430|    : name(n)
   86|    430|    , force_has_children(false) {
   87|    430|        AddProperties(std::forward<More>(more)...);
   88|    430|    }
_ZN6Assimp3FBX4Node13AddPropertiesIRA8_KcJEEEvOT_DpOT0_:
   98|  16.0k|    void AddProperties(T&& value, More&&... more) {
   99|  16.0k|        properties.emplace_back(std::forward<T>(value));
  100|  16.0k|        AddProperties(std::forward<More>(more)...);
  101|  16.0k|    }
_ZN6Assimp3FBX4Node6AddP70IJdddEEEvRKNSt3__112basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEESB_SB_SB_DpOT_:
  142|  1.83k|    ) {
  143|  1.83k|        Node n("P");
  144|  1.83k|        n.AddProperties(name, type, type2, flags, std::forward<More>(more)...);
  145|  1.83k|        AddChild(n);
  146|  1.83k|    }
_ZN6Assimp3FBX4Node13AddPropertiesIRKNSt3__112basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEEJSB_SB_SB_dddEEEvOT_DpOT0_:
   98|  1.83k|    void AddProperties(T&& value, More&&... more) {
   99|  1.83k|        properties.emplace_back(std::forward<T>(value));
  100|  1.83k|        AddProperties(std::forward<More>(more)...);
  101|  1.83k|    }
_ZN6Assimp3FBX4Node13AddPropertiesIRKNSt3__112basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEEJSB_SB_dddEEEvOT_DpOT0_:
   98|  1.83k|    void AddProperties(T&& value, More&&... more) {
   99|  1.83k|        properties.emplace_back(std::forward<T>(value));
  100|  1.83k|        AddProperties(std::forward<More>(more)...);
  101|  1.83k|    }
_ZN6Assimp3FBX4Node13AddPropertiesIRKNSt3__112basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEEJSB_dddEEEvOT_DpOT0_:
   98|  1.83k|    void AddProperties(T&& value, More&&... more) {
   99|  1.83k|        properties.emplace_back(std::forward<T>(value));
  100|  1.83k|        AddProperties(std::forward<More>(more)...);
  101|  1.83k|    }
_ZN6Assimp3FBX4Node13AddPropertiesIRKNSt3__112basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEEJdddEEEvOT_DpOT0_:
   98|  1.83k|    void AddProperties(T&& value, More&&... more) {
   99|  1.83k|        properties.emplace_back(std::forward<T>(value));
  100|  1.83k|        AddProperties(std::forward<More>(more)...);
  101|  1.83k|    }
_ZN6Assimp3FBX4Node13AddPropertiesIdJddEEEvOT_DpOT0_:
   98|  1.83k|    void AddProperties(T&& value, More&&... more) {
   99|  1.83k|        properties.emplace_back(std::forward<T>(value));
  100|  1.83k|        AddProperties(std::forward<More>(more)...);
  101|  1.83k|    }
_ZN6Assimp3FBX4Node13AddPropertiesIdJdEEEvOT_DpOT0_:
   98|  2.03k|    void AddProperties(T&& value, More&&... more) {
   99|  2.03k|        properties.emplace_back(std::forward<T>(value));
  100|  2.03k|        AddProperties(std::forward<More>(more)...);
  101|  2.03k|    }
_ZN6Assimp3FBX4NodeC2IJRA9_KcEEERKNSt3__112basic_stringIcNS6_11char_traitsIcEENS6_9allocatorIcEEEEDpOT_:
   85|    415|    : name(n)
   86|    415|    , force_has_children(false) {
   87|    415|        AddProperties(std::forward<More>(more)...);
   88|    415|    }
_ZN6Assimp3FBX4Node13AddPropertiesIRA9_KcJEEEvOT_DpOT0_:
   98|  3.49k|    void AddProperties(T&& value, More&&... more) {
   99|  3.49k|        properties.emplace_back(std::forward<T>(value));
  100|  3.49k|        AddProperties(std::forward<More>(more)...);
  101|  3.49k|    }
_ZN6Assimp3FBX4Node11AddPropertyIRA16_KcEEvOT_:
   92|     57|    void AddProperty(T&& value) {
   93|     57|        properties.emplace_back(std::forward<T>(value));
   94|     57|    }
_ZN6Assimp3FBX4Node11AddPropertyIRA18_KcEEvOT_:
   92|    117|    void AddProperty(T&& value) {
   93|    117|        properties.emplace_back(std::forward<T>(value));
   94|    117|    }
_ZN6Assimp3FBX4Node6AddP70IJRA1_KcEEEvRKNSt3__112basic_stringIcNS6_11char_traitsIcEENS6_9allocatorIcEEEESE_SE_SE_DpOT_:
  142|     48|    ) {
  143|     48|        Node n("P");
  144|     48|        n.AddProperties(name, type, type2, flags, std::forward<More>(more)...);
  145|     48|        AddChild(n);
  146|     48|    }
_ZN6Assimp3FBX4Node13AddPropertiesIRKNSt3__112basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEEJSB_SB_SB_RA1_KcEEEvOT_DpOT0_:
   98|     48|    void AddProperties(T&& value, More&&... more) {
   99|     48|        properties.emplace_back(std::forward<T>(value));
  100|     48|        AddProperties(std::forward<More>(more)...);
  101|     48|    }
_ZN6Assimp3FBX4Node13AddPropertiesIRKNSt3__112basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEEJSB_SB_RA1_KcEEEvOT_DpOT0_:
   98|     48|    void AddProperties(T&& value, More&&... more) {
   99|     48|        properties.emplace_back(std::forward<T>(value));
  100|     48|        AddProperties(std::forward<More>(more)...);
  101|     48|    }
_ZN6Assimp3FBX4Node13AddPropertiesIRKNSt3__112basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEEJSB_RA1_KcEEEvOT_DpOT0_:
   98|     48|    void AddProperties(T&& value, More&&... more) {
   99|     48|        properties.emplace_back(std::forward<T>(value));
  100|     48|        AddProperties(std::forward<More>(more)...);
  101|     48|    }
_ZN6Assimp3FBX4Node13AddPropertiesIRKNSt3__112basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEEJRA1_KcEEEvOT_DpOT0_:
   98|    146|    void AddProperties(T&& value, More&&... more) {
   99|    146|        properties.emplace_back(std::forward<T>(value));
  100|    146|        AddProperties(std::forward<More>(more)...);
  101|    146|    }
_ZN6Assimp3FBX4Node13AddPropertiesIRA1_KcJEEEvOT_DpOT0_:
   98|  23.2k|    void AddProperties(T&& value, More&&... more) {
   99|  23.2k|        properties.emplace_back(std::forward<T>(value));
  100|  23.2k|        AddProperties(std::forward<More>(more)...);
  101|  23.2k|    }
_ZN6Assimp3FBX4NodeC2IJRA19_KcEEERKNSt3__112basic_stringIcNS6_11char_traitsIcEENS6_9allocatorIcEEEEDpOT_:
   85|     26|    : name(n)
   86|     26|    , force_has_children(false) {
   87|     26|        AddProperties(std::forward<More>(more)...);
   88|     26|    }
_ZN6Assimp3FBX4Node13AddPropertiesIRA19_KcJEEEvOT_DpOT0_:
   98|  12.1k|    void AddProperties(T&& value, More&&... more) {
   99|  12.1k|        properties.emplace_back(std::forward<T>(value));
  100|  12.1k|        AddProperties(std::forward<More>(more)...);
  101|  12.1k|    }
_ZN6Assimp3FBX4NodeC2IJRA17_KcEEERKNSt3__112basic_stringIcNS6_11char_traitsIcEENS6_9allocatorIcEEEEDpOT_:
   85|     26|    : name(n)
   86|     26|    , force_has_children(false) {
   87|     26|        AddProperties(std::forward<More>(more)...);
   88|     26|    }
_ZN6Assimp3FBX4Node13AddPropertiesIRA17_KcJEEEvOT_DpOT0_:
   98|    124|    void AddProperties(T&& value, More&&... more) {
   99|    124|        properties.emplace_back(std::forward<T>(value));
  100|    124|        AddProperties(std::forward<More>(more)...);
  101|    124|    }
_ZN6Assimp3FBX4NodeC2IJRA5_KcEEERKNSt3__112basic_stringIcNS6_11char_traitsIcEENS6_9allocatorIcEEEEDpOT_:
   85|     19|    : name(n)
   86|     19|    , force_has_children(false) {
   87|     19|        AddProperties(std::forward<More>(more)...);
   88|     19|    }
_ZN6Assimp3FBX4Node13AddPropertiesIRA5_KcJEEEvOT_DpOT0_:
   98|    327|    void AddProperties(T&& value, More&&... more) {
   99|    327|        properties.emplace_back(std::forward<T>(value));
  100|    327|        AddProperties(std::forward<More>(more)...);
  101|    327|    }
_ZN6Assimp3FBX4Node11AddPropertyIRlEEvOT_:
   92|  12.8k|    void AddProperty(T&& value) {
   93|  12.8k|        properties.emplace_back(std::forward<T>(value));
   94|  12.8k|    }
_ZN6Assimp3FBX4Node11AddPropertyINSt3__112basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEEEEvOT_:
   92|  12.8k|    void AddProperty(T&& value) {
   93|  12.8k|        properties.emplace_back(std::forward<T>(value));
   94|  12.8k|    }
_ZN6Assimp3FBX4Node8AddChildIJRA8_KcEEEvRKNSt3__112basic_stringIcNS6_11char_traitsIcEENS6_9allocatorIcEEEEDpOT_:
  112|  12.4k|    ) {
  113|  12.4k|        FBX::Node c(name);
  114|  12.4k|        c.AddProperties(std::forward<More>(more)...);
  115|  12.4k|        children.push_back(std::move(c));
  116|  12.4k|    }
_ZN6Assimp3FBX4Node8AddChildIJRNSt3__16vectorIiNS3_9allocatorIiEEEEEEEvRKNS3_12basic_stringIcNS3_11char_traitsIcEENS5_IcEEEEDpOT_:
  112|  15.7k|    ) {
  113|  15.7k|        FBX::Node c(name);
  114|  15.7k|        c.AddProperties(std::forward<More>(more)...);
  115|  15.7k|        children.push_back(std::move(c));
  116|  15.7k|    }
_ZN6Assimp3FBX4Node13AddPropertiesIRNSt3__16vectorIiNS3_9allocatorIiEEEEJEEEvOT_DpOT0_:
   98|  15.7k|    void AddProperties(T&& value, More&&... more) {
   99|  15.7k|        properties.emplace_back(std::forward<T>(value));
  100|  15.7k|        AddProperties(std::forward<More>(more)...);
  101|  15.7k|    }
_ZN6Assimp3FBX4Node11AddPropertyIRA5_KcEEvOT_:
   92|  12.6k|    void AddProperty(T&& value) {
   93|  12.6k|        properties.emplace_back(std::forward<T>(value));
   94|  12.6k|    }
_ZN6Assimp3FBX4NodeC2IJiEEERKNSt3__112basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEEDpOT_:
   85|  37.7k|    : name(n)
   86|  37.7k|    , force_has_children(false) {
   87|  37.7k|        AddProperties(std::forward<More>(more)...);
   88|  37.7k|    }
_ZN6Assimp3FBX4Node17WritePropertyNodeIPKcEEvRKNSt3__112basic_stringIcNS5_11char_traitsIcEENS5_9allocatorIcEEEET_RNS_12StreamWriterILb0ELb0EEEbi:
  180|  37.4k|    ) {
  181|  37.4k|        FBX::FBXExportProperty p(value);
  182|  37.4k|        FBX::Node node(name, std::move(p));
  183|  37.4k|        node.Dump(s, binary, indent);
  184|  37.4k|    }
_ZN6Assimp3FBX4Node8AddChildIJRA1_KcEEEvRKNSt3__112basic_stringIcNS6_11char_traitsIcEENS6_9allocatorIcEEEEDpOT_:
  112|  12.6k|    ) {
  113|  12.6k|        FBX::Node c(name);
  114|  12.6k|        c.AddProperties(std::forward<More>(more)...);
  115|  12.6k|        children.push_back(std::move(c));
  116|  12.6k|    }
_ZN6Assimp3FBX4Node8AddChildIJRA14_KcEEEvRKNSt3__112basic_stringIcNS6_11char_traitsIcEENS6_9allocatorIcEEEEDpOT_:
  112|  12.6k|    ) {
  113|  12.6k|        FBX::Node c(name);
  114|  12.6k|        c.AddProperties(std::forward<More>(more)...);
  115|  12.6k|        children.push_back(std::move(c));
  116|  12.6k|    }
_ZN6Assimp3FBX4Node8AddChildIJRA10_KcEEEvRKNSt3__112basic_stringIcNS6_11char_traitsIcEENS6_9allocatorIcEEEEDpOT_:
  112|    290|    ) {
  113|    290|        FBX::Node c(name);
  114|    290|        c.AddProperties(std::forward<More>(more)...);
  115|    290|        children.push_back(std::move(c));
  116|    290|    }
_ZN6Assimp3FBX4Node13AddPropertiesIRA10_KcJEEEvOT_DpOT0_:
   98|    290|    void AddProperties(T&& value, More&&... more) {
   99|    290|        properties.emplace_back(std::forward<T>(value));
  100|    290|        AddProperties(std::forward<More>(more)...);
  101|    290|    }
_ZN6Assimp3FBX4Node8AddChildIJRA19_KcEEEvRKNSt3__112basic_stringIcNS6_11char_traitsIcEENS6_9allocatorIcEEEEDpOT_:
  112|  12.1k|    ) {
  113|  12.1k|        FBX::Node c(name);
  114|  12.1k|        c.AddProperties(std::forward<More>(more)...);
  115|  12.1k|        children.push_back(std::move(c));
  116|  12.1k|    }
_ZN6Assimp3FBX4Node8AddChildIJRA18_KcEEEvRKNSt3__112basic_stringIcNS6_11char_traitsIcEENS6_9allocatorIcEEEEDpOT_:
  112|    201|    ) {
  113|    201|        FBX::Node c(name);
  114|    201|        c.AddProperties(std::forward<More>(more)...);
  115|    201|        children.push_back(std::move(c));
  116|    201|    }
_ZN6Assimp3FBX4Node13AddPropertiesIRA18_KcJEEEvOT_DpOT0_:
   98|    201|    void AddProperties(T&& value, More&&... more) {
   99|    201|        properties.emplace_back(std::forward<T>(value));
  100|    201|        AddProperties(std::forward<More>(more)...);
  101|    201|    }
_ZN6Assimp3FBX4Node8AddChildIJRA21_KcEEEvRKNSt3__112basic_stringIcNS6_11char_traitsIcEENS6_9allocatorIcEEEEDpOT_:
  112|  12.6k|    ) {
  113|  12.6k|        FBX::Node c(name);
  114|  12.6k|        c.AddProperties(std::forward<More>(more)...);
  115|  12.6k|        children.push_back(std::move(c));
  116|  12.6k|    }
_ZN6Assimp3FBX4Node13AddPropertiesIRA21_KcJEEEvOT_DpOT0_:
   98|  12.6k|    void AddProperties(T&& value, More&&... more) {
   99|  12.6k|        properties.emplace_back(std::forward<T>(value));
  100|  12.6k|        AddProperties(std::forward<More>(more)...);
  101|  12.6k|    }
_ZN6Assimp3FBX4Node8AddChildIJRA15_KcEEEvRKNSt3__112basic_stringIcNS6_11char_traitsIcEENS6_9allocatorIcEEEEDpOT_:
  112|  12.6k|    ) {
  113|  12.6k|        FBX::Node c(name);
  114|  12.6k|        c.AddProperties(std::forward<More>(more)...);
  115|  12.6k|        children.push_back(std::move(c));
  116|  12.6k|    }
_ZN6Assimp3FBX4Node11AddPropertyIRA1_KcEEvOT_:
   92|    246|    void AddProperty(T&& value) {
   93|    246|        properties.emplace_back(std::forward<T>(value));
   94|    246|    }
_ZN6Assimp3FBX4Node8AddChildIJRA6_KcEEEvRKNSt3__112basic_stringIcNS6_11char_traitsIcEENS6_9allocatorIcEEEEDpOT_:
  112|     92|    ) {
  113|     92|        FBX::Node c(name);
  114|     92|        c.AddProperties(std::forward<More>(more)...);
  115|     92|        children.push_back(std::move(c));
  116|     92|    }
_ZN6Assimp3FBX4Node13AddPropertiesIRKlJNSt3__112basic_stringIcNS5_11char_traitsIcEENS5_9allocatorIcEEEERA5_KcEEEvOT_DpOT0_:
   98|     92|    void AddProperties(T&& value, More&&... more) {
   99|     92|        properties.emplace_back(std::forward<T>(value));
  100|     92|        AddProperties(std::forward<More>(more)...);
  101|     92|    }
_ZN6Assimp3FBX4Node13AddPropertiesINSt3__112basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEEJRA5_KcEEEvOT_DpOT0_:
   98|    118|    void AddProperties(T&& value, More&&... more) {
   99|    118|        properties.emplace_back(std::forward<T>(value));
  100|    118|        AddProperties(std::forward<More>(more)...);
  101|    118|    }
_ZN6Assimp3FBX4Node8AddChildIJRA5_KcEEEvRKNSt3__112basic_stringIcNS6_11char_traitsIcEENS6_9allocatorIcEEEEDpOT_:
  112|    190|    ) {
  113|    190|        FBX::Node c(name);
  114|    190|        c.AddProperties(std::forward<More>(more)...);
  115|    190|        children.push_back(std::move(c));
  116|    190|    }
_ZN6Assimp3FBX4Node8AddChildIJRNSt3__16vectorIhNS3_9allocatorIhEEEEEEEvRKNS3_12basic_stringIcNS3_11char_traitsIcEENS5_IcEEEEDpOT_:
  112|      7|    ) {
  113|      7|        FBX::Node c(name);
  114|      7|        c.AddProperties(std::forward<More>(more)...);
  115|      7|        children.push_back(std::move(c));
  116|      7|    }
_ZN6Assimp3FBX4Node13AddPropertiesIRNSt3__16vectorIhNS3_9allocatorIhEEEEJEEEvOT_DpOT0_:
   98|      7|    void AddProperties(T&& value, More&&... more) {
   99|      7|        properties.emplace_back(std::forward<T>(value));
  100|      7|        AddProperties(std::forward<More>(more)...);
  101|      7|    }
_ZN6Assimp3FBX4Node8AddChildIJRNSt3__112basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEEEEEvRKS9_DpOT_:
  112|    380|    ) {
  113|    380|        FBX::Node c(name);
  114|    380|        c.AddProperties(std::forward<More>(more)...);
  115|    380|        children.push_back(std::move(c));
  116|    380|    }
_ZN6Assimp3FBX4Node13AddPropertiesIRNSt3__112basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEEJEEEvOT_DpOT0_:
   98|    472|    void AddProperties(T&& value, More&&... more) {
   99|    472|        properties.emplace_back(std::forward<T>(value));
  100|    472|        AddProperties(std::forward<More>(more)...);
  101|    472|    }
_ZN6Assimp3FBX4Node6AddP70IJRNSt3__112basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEEEEEvRKS9_SC_SC_SC_DpOT_:
  142|     92|    ) {
  143|     92|        Node n("P");
  144|     92|        n.AddProperties(name, type, type2, flags, std::forward<More>(more)...);
  145|     92|        AddChild(n);
  146|     92|    }
_ZN6Assimp3FBX4Node13AddPropertiesIRKNSt3__112basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEEJSB_SB_SB_RS9_EEEvOT_DpOT0_:
   98|     92|    void AddProperties(T&& value, More&&... more) {
   99|     92|        properties.emplace_back(std::forward<T>(value));
  100|     92|        AddProperties(std::forward<More>(more)...);
  101|     92|    }
_ZN6Assimp3FBX4Node13AddPropertiesIRKNSt3__112basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEEJSB_SB_RS9_EEEvOT_DpOT0_:
   98|     92|    void AddProperties(T&& value, More&&... more) {
   99|     92|        properties.emplace_back(std::forward<T>(value));
  100|     92|        AddProperties(std::forward<More>(more)...);
  101|     92|    }
_ZN6Assimp3FBX4Node13AddPropertiesIRKNSt3__112basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEEJSB_RS9_EEEvOT_DpOT0_:
   98|     92|    void AddProperties(T&& value, More&&... more) {
   99|     92|        properties.emplace_back(std::forward<T>(value));
  100|     92|        AddProperties(std::forward<More>(more)...);
  101|     92|    }
_ZN6Assimp3FBX4Node13AddPropertiesIRKNSt3__112basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEEJRS9_EEEvOT_DpOT0_:
   98|     92|    void AddProperties(T&& value, More&&... more) {
   99|     92|        properties.emplace_back(std::forward<T>(value));
  100|     92|        AddProperties(std::forward<More>(more)...);
  101|     92|    }
_ZN6Assimp3FBX4NodeC2IJRA3_KcRKlRlRKNSt3__112basic_stringIcNS9_11char_traitsIcEENS9_9allocatorIcEEEEEEESH_DpOT_:
   85|     98|    : name(n)
   86|     98|    , force_has_children(false) {
   87|     98|        AddProperties(std::forward<More>(more)...);
   88|     98|    }
_ZN6Assimp3FBX4Node13AddPropertiesIRA3_KcJRKlRlRKNSt3__112basic_stringIcNS9_11char_traitsIcEENS9_9allocatorIcEEEEEEEvOT_DpOT0_:
   98|     98|    void AddProperties(T&& value, More&&... more) {
   99|     98|        properties.emplace_back(std::forward<T>(value));
  100|     98|        AddProperties(std::forward<More>(more)...);
  101|     98|    }
_ZN6Assimp3FBX4Node13AddPropertiesIRKlJRlRKNSt3__112basic_stringIcNS6_11char_traitsIcEENS6_9allocatorIcEEEEEEEvOT_DpOT0_:
   98|     98|    void AddProperties(T&& value, More&&... more) {
   99|     98|        properties.emplace_back(std::forward<T>(value));
  100|     98|        AddProperties(std::forward<More>(more)...);
  101|     98|    }
_ZN6Assimp3FBX4Node13AddPropertiesIRlJRKNSt3__112basic_stringIcNS4_11char_traitsIcEENS4_9allocatorIcEEEEEEEvOT_DpOT0_:
   98|  7.40k|    void AddProperties(T&& value, More&&... more) {
   99|  7.40k|        properties.emplace_back(std::forward<T>(value));
  100|  7.40k|        AddProperties(std::forward<More>(more)...);
  101|  7.40k|    }
_ZN6Assimp3FBX4NodeC2IJRA3_KcRKlS7_EEERKNSt3__112basic_stringIcNS8_11char_traitsIcEENS8_9allocatorIcEEEEDpOT_:
   85|     98|    : name(n)
   86|     98|    , force_has_children(false) {
   87|     98|        AddProperties(std::forward<More>(more)...);
   88|     98|    }
_ZN6Assimp3FBX4Node13AddPropertiesIRA3_KcJRKlS7_EEEvOT_DpOT0_:
   98|     98|    void AddProperties(T&& value, More&&... more) {
   99|     98|        properties.emplace_back(std::forward<T>(value));
  100|     98|        AddProperties(std::forward<More>(more)...);
  101|     98|    }
_ZN6Assimp3FBX4Node13AddPropertiesIRKlJS4_EEEvOT_DpOT0_:
   98|     98|    void AddProperties(T&& value, More&&... more) {
   99|     98|        properties.emplace_back(std::forward<T>(value));
  100|     98|        AddProperties(std::forward<More>(more)...);
  101|     98|    }
_ZN6Assimp3FBX4Node13AddPropertiesIRKlJEEEvOT_DpOT0_:
   98|  3.18k|    void AddProperties(T&& value, More&&... more) {
   99|  3.18k|        properties.emplace_back(std::forward<T>(value));
  100|  3.18k|        AddProperties(std::forward<More>(more)...);
  101|  3.18k|    }
_ZN6Assimp3FBX4Node13AddPropertiesIRKlJRKNSt3__112basic_stringIcNS5_11char_traitsIcEENS5_9allocatorIcEEEERA1_KcEEEvOT_DpOT0_:
   98|     98|    void AddProperties(T&& value, More&&... more) {
   99|     98|        properties.emplace_back(std::forward<T>(value));
  100|     98|        AddProperties(std::forward<More>(more)...);
  101|     98|    }
_ZN6Assimp3FBX4Node8AddChildIJRA17_KcEEEvRKNSt3__112basic_stringIcNS6_11char_traitsIcEENS6_9allocatorIcEEEEDpOT_:
  112|     98|    ) {
  113|     98|        FBX::Node c(name);
  114|     98|        c.AddProperties(std::forward<More>(more)...);
  115|     98|        children.push_back(std::move(c));
  116|     98|    }
_ZN6Assimp3FBX4Node8AddChildIJRKNSt3__112basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEEEEEvSB_DpOT_:
  112|     98|    ) {
  113|     98|        FBX::Node c(name);
  114|     98|        c.AddProperties(std::forward<More>(more)...);
  115|     98|        children.push_back(std::move(c));
  116|     98|    }
_ZN6Assimp3FBX4Node8AddChildIJddEEEvRKNSt3__112basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEEDpOT_:
  112|    196|    ) {
  113|    196|        FBX::Node c(name);
  114|    196|        c.AddProperties(std::forward<More>(more)...);
  115|    196|        children.push_back(std::move(c));
  116|    196|    }
_ZN6Assimp3FBX4Node8AddChildIJiiiiEEEvRKNSt3__112basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEEDpOT_:
  112|     98|    ) {
  113|     98|        FBX::Node c(name);
  114|     98|        c.AddProperties(std::forward<More>(more)...);
  115|     98|        children.push_back(std::move(c));
  116|     98|    }
_ZN6Assimp3FBX4Node13AddPropertiesIiJiiiEEEvOT_DpOT0_:
   98|     98|    void AddProperties(T&& value, More&&... more) {
   99|     98|        properties.emplace_back(std::forward<T>(value));
  100|     98|        AddProperties(std::forward<More>(more)...);
  101|     98|    }
_ZN6Assimp3FBX4Node13AddPropertiesIiJiiEEEvOT_DpOT0_:
   98|     98|    void AddProperties(T&& value, More&&... more) {
   99|     98|        properties.emplace_back(std::forward<T>(value));
  100|     98|        AddProperties(std::forward<More>(more)...);
  101|     98|    }
_ZN6Assimp3FBX4Node13AddPropertiesIiJiEEEvOT_DpOT0_:
   98|     98|    void AddProperties(T&& value, More&&... more) {
   99|     98|        properties.emplace_back(std::forward<T>(value));
  100|     98|        AddProperties(std::forward<More>(more)...);
  101|     98|    }
_ZN6Assimp3FBX4NodeC2IJRA3_KcRlS6_EEERKNSt3__112basic_stringIcNS7_11char_traitsIcEENS7_9allocatorIcEEEEDpOT_:
   85|  68.4k|    : name(n)
   86|  68.4k|    , force_has_children(false) {
   87|  68.4k|        AddProperties(std::forward<More>(more)...);
   88|  68.4k|    }
_ZN6Assimp3FBX4Node13AddPropertiesIRA3_KcJRlS6_EEEvOT_DpOT0_:
   98|  68.4k|    void AddProperties(T&& value, More&&... more) {
   99|  68.4k|        properties.emplace_back(std::forward<T>(value));
  100|  68.4k|        AddProperties(std::forward<More>(more)...);
  101|  68.4k|    }
_ZN6Assimp3FBX4Node13AddPropertiesIRlJS3_EEEvOT_DpOT0_:
   98|  68.4k|    void AddProperties(T&& value, More&&... more) {
   99|  68.4k|        properties.emplace_back(std::forward<T>(value));
  100|  68.4k|        AddProperties(std::forward<More>(more)...);
  101|  68.4k|    }
_ZN6Assimp3FBX4Node13AddPropertiesIRlJEEEvOT_DpOT0_:
   98|  72.1k|    void AddProperties(T&& value, More&&... more) {
   99|  72.1k|        properties.emplace_back(std::forward<T>(value));
  100|  72.1k|        AddProperties(std::forward<More>(more)...);
  101|  72.1k|    }
_ZN6Assimp3FBX4Node8AddChildIJRNSt3__16vectorIdNS3_9allocatorIdEEEEEEEvRKNS3_12basic_stringIcNS3_11char_traitsIcEENS5_IcEEEEDpOT_:
  112|  3.08k|    ) {
  113|  3.08k|        FBX::Node c(name);
  114|  3.08k|        c.AddProperties(std::forward<More>(more)...);
  115|  3.08k|        children.push_back(std::move(c));
  116|  3.08k|    }
_ZN6Assimp3FBX4Node13AddPropertiesIRNSt3__16vectorIdNS3_9allocatorIdEEEEJEEEvOT_DpOT0_:
   98|  3.08k|    void AddProperties(T&& value, More&&... more) {
   99|  3.08k|        properties.emplace_back(std::forward<T>(value));
  100|  3.08k|        AddProperties(std::forward<More>(more)...);
  101|  3.08k|    }
_ZN6Assimp3FBX4NodeC2IJRA3_KcRKlRlEEERKNSt3__112basic_stringIcNS9_11char_traitsIcEENS9_9allocatorIcEEEEDpOT_:
   85|  3.08k|    : name(n)
   86|  3.08k|    , force_has_children(false) {
   87|  3.08k|        AddProperties(std::forward<More>(more)...);
   88|  3.08k|    }
_ZN6Assimp3FBX4Node13AddPropertiesIRA3_KcJRKlRlEEEvOT_DpOT0_:
   98|  3.08k|    void AddProperties(T&& value, More&&... more) {
   99|  3.08k|        properties.emplace_back(std::forward<T>(value));
  100|  3.08k|        AddProperties(std::forward<More>(more)...);
  101|  3.08k|    }
_ZN6Assimp3FBX4Node13AddPropertiesIRKlJRlEEEvOT_DpOT0_:
   98|  3.08k|    void AddProperties(T&& value, More&&... more) {
   99|  3.08k|        properties.emplace_back(std::forward<T>(value));
  100|  3.08k|        AddProperties(std::forward<More>(more)...);
  101|  3.08k|    }
_ZN6Assimp3FBX4NodeC2IJRA3_KcRlRKlEEERKNSt3__112basic_stringIcNS9_11char_traitsIcEENS9_9allocatorIcEEEEDpOT_:
   85|  3.08k|    : name(n)
   86|  3.08k|    , force_has_children(false) {
   87|  3.08k|        AddProperties(std::forward<More>(more)...);
   88|  3.08k|    }
_ZN6Assimp3FBX4Node13AddPropertiesIRA3_KcJRlRKlEEEvOT_DpOT0_:
   98|  3.08k|    void AddProperties(T&& value, More&&... more) {
   99|  3.08k|        properties.emplace_back(std::forward<T>(value));
  100|  3.08k|        AddProperties(std::forward<More>(more)...);
  101|  3.08k|    }
_ZN6Assimp3FBX4Node13AddPropertiesIRlJRKlEEEvOT_DpOT0_:
   98|  3.08k|    void AddProperties(T&& value, More&&... more) {
   99|  3.08k|        properties.emplace_back(std::forward<T>(value));
  100|  3.08k|        AddProperties(std::forward<More>(more)...);
  101|  3.08k|    }
_ZN6Assimp3FBX4Node13AddPropertiesIRlJNSt3__112basic_stringIcNS4_11char_traitsIcEENS4_9allocatorIcEEEERA5_KcEEEvOT_DpOT0_:
   98|     26|    void AddProperties(T&& value, More&&... more) {
   99|     26|        properties.emplace_back(std::forward<T>(value));
  100|     26|        AddProperties(std::forward<More>(more)...);
  101|     26|    }
_ZN6Assimp3FBX4Node8AddChildIJdEEEvRKNSt3__112basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEEDpOT_:
  112|     26|    ) {
  113|     26|        FBX::Node c(name);
  114|     26|        c.AddProperties(std::forward<More>(more)...);
  115|     26|        children.push_back(std::move(c));
  116|     26|    }
_ZN6Assimp3FBX4Node8AddChildIJRA7_KcEEEvRKNSt3__112basic_stringIcNS6_11char_traitsIcEENS6_9allocatorIcEEEEDpOT_:
  112|     26|    ) {
  113|     26|        FBX::Node c(name);
  114|     26|        c.AddProperties(std::forward<More>(more)...);
  115|     26|        children.push_back(std::move(c));
  116|     26|    }
_ZN6Assimp3FBX4Node13AddPropertiesIRA7_KcJEEEvOT_DpOT0_:
   98|     26|    void AddProperties(T&& value, More&&... more) {
   99|     26|        properties.emplace_back(std::forward<T>(value));
  100|     26|        AddProperties(std::forward<More>(more)...);
  101|     26|    }
_ZN6Assimp3FBX4Node13AddPropertiesIRKlJNSt3__112basic_stringIcNS5_11char_traitsIcEENS5_9allocatorIcEEEERA8_KcEEEvOT_DpOT0_:
   98|  3.08k|    void AddProperties(T&& value, More&&... more) {
   99|  3.08k|        properties.emplace_back(std::forward<T>(value));
  100|  3.08k|        AddProperties(std::forward<More>(more)...);
  101|  3.08k|    }
_ZN6Assimp3FBX4Node13AddPropertiesINSt3__112basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEEJRA8_KcEEEvOT_DpOT0_:
   98|  3.08k|    void AddProperties(T&& value, More&&... more) {
   99|  3.08k|        properties.emplace_back(std::forward<T>(value));
  100|  3.08k|        AddProperties(std::forward<More>(more)...);
  101|  3.08k|    }
_ZN6Assimp3FBX4Node8AddChildIJRA1_KcS5_EEEvRKNSt3__112basic_stringIcNS6_11char_traitsIcEENS6_9allocatorIcEEEEDpOT_:
  112|  3.08k|    ) {
  113|  3.08k|        FBX::Node c(name);
  114|  3.08k|        c.AddProperties(std::forward<More>(more)...);
  115|  3.08k|        children.push_back(std::move(c));
  116|  3.08k|    }
_ZN6Assimp3FBX4Node13AddPropertiesIRA1_KcJS5_EEEvOT_DpOT0_:
   98|  3.08k|    void AddProperties(T&& value, More&&... more) {
   99|  3.08k|        properties.emplace_back(std::forward<T>(value));
  100|  3.08k|        AddProperties(std::forward<More>(more)...);
  101|  3.08k|    }
_ZN6Assimp3FBX4Node8AddChildIJR12aiMatrix4x4tIfEEEEvRKNSt3__112basic_stringIcNS6_11char_traitsIcEENS6_9allocatorIcEEEEDpOT_:
  112|  6.17k|    ) {
  113|  6.17k|        FBX::Node c(name);
  114|  6.17k|        c.AddProperties(std::forward<More>(more)...);
  115|  6.17k|        children.push_back(std::move(c));
  116|  6.17k|    }
_ZN6Assimp3FBX4Node13AddPropertiesIR12aiMatrix4x4tIfEJEEEvOT_DpOT0_:
   98|  6.17k|    void AddProperties(T&& value, More&&... more) {
   99|  6.17k|        properties.emplace_back(std::forward<T>(value));
  100|  6.17k|        AddProperties(std::forward<More>(more)...);
  101|  6.17k|    }
_ZN6Assimp3FBX4Node13AddPropertiesIRlJRKNSt3__112basic_stringIcNS4_11char_traitsIcEENS4_9allocatorIcEEEERA6_KcEEEvOT_DpOT0_:
   98|     57|    void AddProperties(T&& value, More&&... more) {
   99|     57|        properties.emplace_back(std::forward<T>(value));
  100|     57|        AddProperties(std::forward<More>(more)...);
  101|     57|    }
_ZN6Assimp3FBX4Node13AddPropertiesIRKNSt3__112basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEEJRA6_KcEEEvOT_DpOT0_:
   98|     57|    void AddProperties(T&& value, More&&... more) {
   99|     57|        properties.emplace_back(std::forward<T>(value));
  100|     57|        AddProperties(std::forward<More>(more)...);
  101|     57|    }
_ZN6Assimp3FBX4Node8AddChildIJNS0_17FBXExportPropertyEEEEvRKNSt3__112basic_stringIcNS4_11char_traitsIcEENS4_9allocatorIcEEEEDpOT_:
  112|  77.4k|    ) {
  113|  77.4k|        FBX::Node c(name);
  114|  77.4k|        c.AddProperties(std::forward<More>(more)...);
  115|  77.4k|        children.push_back(std::move(c));
  116|  77.4k|    }
_ZN6Assimp3FBX4Node13AddPropertiesIRlJRNSt3__112basic_stringIcNS4_11char_traitsIcEENS4_9allocatorIcEEEERA1_KcEEEvOT_DpOT0_:
   98|     28|    void AddProperties(T&& value, More&&... more) {
   99|     28|        properties.emplace_back(std::forward<T>(value));
  100|     28|        AddProperties(std::forward<More>(more)...);
  101|     28|    }
_ZN6Assimp3FBX4Node13AddPropertiesIRNSt3__112basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEEJRA1_KcEEEvOT_DpOT0_:
   98|     28|    void AddProperties(T&& value, More&&... more) {
   99|     28|        properties.emplace_back(std::forward<T>(value));
  100|     28|        AddProperties(std::forward<More>(more)...);
  101|     28|    }
_ZN6Assimp3FBX4Node13AddPropertiesIRlJNSt3__112basic_stringIcNS4_11char_traitsIcEENS4_9allocatorIcEEEERA1_KcEEEvOT_DpOT0_:
   98|  7.33k|    void AddProperties(T&& value, More&&... more) {
   99|  7.33k|        properties.emplace_back(std::forward<T>(value));
  100|  7.33k|        AddProperties(std::forward<More>(more)...);
  101|  7.33k|    }
_ZN6Assimp3FBX4Node13AddPropertiesINSt3__112basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEEJRA1_KcEEEvOT_DpOT0_:
   98|  7.33k|    void AddProperties(T&& value, More&&... more) {
   99|  7.33k|        properties.emplace_back(std::forward<T>(value));
  100|  7.33k|        AddProperties(std::forward<More>(more)...);
  101|  7.33k|    }
_ZN6Assimp3FBX4Node13AddPropertiesIRlJNSt3__112basic_stringIcNS4_11char_traitsIcEENS4_9allocatorIcEEEERKSA_EEEvOT_DpOT0_:
   98|  37.1k|    void AddProperties(T&& value, More&&... more) {
   99|  37.1k|        properties.emplace_back(std::forward<T>(value));
  100|  37.1k|        AddProperties(std::forward<More>(more)...);
  101|  37.1k|    }
_ZN6Assimp3FBX4Node13AddPropertiesINSt3__112basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEEJRKS9_EEEvOT_DpOT0_:
   98|  37.1k|    void AddProperties(T&& value, More&&... more) {
   99|  37.1k|        properties.emplace_back(std::forward<T>(value));
  100|  37.1k|        AddProperties(std::forward<More>(more)...);
  101|  37.1k|    }
_ZN6Assimp3FBX4Node13AddPropertiesIRlJNSt3__112basic_stringIcNS4_11char_traitsIcEENS4_9allocatorIcEEEERA9_KcEEEvOT_DpOT0_:
   98|  3.07k|    void AddProperties(T&& value, More&&... more) {
   99|  3.07k|        properties.emplace_back(std::forward<T>(value));
  100|  3.07k|        AddProperties(std::forward<More>(more)...);
  101|  3.07k|    }
_ZN6Assimp3FBX4Node13AddPropertiesINSt3__112basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEEJRA9_KcEEEvOT_DpOT0_:
   98|  3.07k|    void AddProperties(T&& value, More&&... more) {
   99|  3.07k|        properties.emplace_back(std::forward<T>(value));
  100|  3.07k|        AddProperties(std::forward<More>(more)...);
  101|  3.07k|    }
_ZN6Assimp3FBX4NodeC2IJRA3_KcRlS6_RKNSt3__112basic_stringIcNS7_11char_traitsIcEENS7_9allocatorIcEEEEEEESF_DpOT_:
   85|  7.30k|    : name(n)
   86|  7.30k|    , force_has_children(false) {
   87|  7.30k|        AddProperties(std::forward<More>(more)...);
   88|  7.30k|    }
_ZN6Assimp3FBX4Node13AddPropertiesIRA3_KcJRlS6_RKNSt3__112basic_stringIcNS7_11char_traitsIcEENS7_9allocatorIcEEEEEEEvOT_DpOT0_:
   98|  7.30k|    void AddProperties(T&& value, More&&... more) {
   99|  7.30k|        properties.emplace_back(std::forward<T>(value));
  100|  7.30k|        AddProperties(std::forward<More>(more)...);
  101|  7.30k|    }
_ZN6Assimp3FBX4Node13AddPropertiesIRlJS3_RKNSt3__112basic_stringIcNS4_11char_traitsIcEENS4_9allocatorIcEEEEEEEvOT_DpOT0_:
   98|  7.30k|    void AddProperties(T&& value, More&&... more) {
   99|  7.30k|        properties.emplace_back(std::forward<T>(value));
  100|  7.30k|        AddProperties(std::forward<More>(more)...);
  101|  7.30k|    }
_ZN6Assimp3FBX4Node8AddChildIJRdEEEvRKNSt3__112basic_stringIcNS4_11char_traitsIcEENS4_9allocatorIcEEEEDpOT_:
  112|  5.48k|    ) {
  113|  5.48k|        FBX::Node c(name);
  114|  5.48k|        c.AddProperties(std::forward<More>(more)...);
  115|  5.48k|        children.push_back(std::move(c));
  116|  5.48k|    }
_ZN6Assimp3FBX4Node13AddPropertiesIRdJEEEvOT_DpOT0_:
   98|  25.6k|    void AddProperties(T&& value, More&&... more) {
   99|  25.6k|        properties.emplace_back(std::forward<T>(value));
  100|  25.6k|        AddProperties(std::forward<More>(more)...);
  101|  25.6k|    }
_ZN6Assimp3FBX4Node8AddChildIJRKNSt3__16vectorIlNS3_9allocatorIlEEEEEEEvRKNS3_12basic_stringIcNS3_11char_traitsIcEENS5_IcEEEEDpOT_:
  112|  5.48k|    ) {
  113|  5.48k|        FBX::Node c(name);
  114|  5.48k|        c.AddProperties(std::forward<More>(more)...);
  115|  5.48k|        children.push_back(std::move(c));
  116|  5.48k|    }
_ZN6Assimp3FBX4Node13AddPropertiesIRKNSt3__16vectorIlNS3_9allocatorIlEEEEJEEEvOT_DpOT0_:
   98|  5.48k|    void AddProperties(T&& value, More&&... more) {
   99|  5.48k|        properties.emplace_back(std::forward<T>(value));
  100|  5.48k|        AddProperties(std::forward<More>(more)...);
  101|  5.48k|    }
_ZN6Assimp3FBX4Node8AddChildIJRKNSt3__16vectorIfNS3_9allocatorIfEEEEEEEvRKNS3_12basic_stringIcNS3_11char_traitsIcEENS5_IcEEEEDpOT_:
  112|  5.48k|    ) {
  113|  5.48k|        FBX::Node c(name);
  114|  5.48k|        c.AddProperties(std::forward<More>(more)...);
  115|  5.48k|        children.push_back(std::move(c));
  116|  5.48k|    }
_ZN6Assimp3FBX4Node13AddPropertiesIRKNSt3__16vectorIfNS3_9allocatorIfEEEEJEEEvOT_DpOT0_:
   98|  5.48k|    void AddProperties(T&& value, More&&... more) {
   99|  5.48k|        properties.emplace_back(std::forward<T>(value));
  100|  5.48k|        AddProperties(std::forward<More>(more)...);
  101|  5.48k|    }
_ZN6Assimp3FBX4Node8AddChildIJNSt3__16vectorIiNS3_9allocatorIiEEEEEEEvRKNS3_12basic_stringIcNS3_11char_traitsIcEENS5_IcEEEEDpOT_:
  112|  10.9k|    ) {
  113|  10.9k|        FBX::Node c(name);
  114|  10.9k|        c.AddProperties(std::forward<More>(more)...);
  115|  10.9k|        children.push_back(std::move(c));
  116|  10.9k|    }
_ZN6Assimp3FBX4Node13AddPropertiesINSt3__16vectorIiNS3_9allocatorIiEEEEJEEEvOT_DpOT0_:
   98|  10.9k|    void AddProperties(T&& value, More&&... more) {
   99|  10.9k|        properties.emplace_back(std::forward<T>(value));
  100|  10.9k|        AddProperties(std::forward<More>(more)...);
  101|  10.9k|    }
_ZN6Assimp3FBX4Node8AddChildIJNSt3__16vectorIfNS3_9allocatorIfEEEEEEEvRKNS3_12basic_stringIcNS3_11char_traitsIcEENS5_IcEEEEDpOT_:
  112|  5.48k|    ) {
  113|  5.48k|        FBX::Node c(name);
  114|  5.48k|        c.AddProperties(std::forward<More>(more)...);
  115|  5.48k|        children.push_back(std::move(c));
  116|  5.48k|    }
_ZN6Assimp3FBX4Node13AddPropertiesINSt3__16vectorIfNS3_9allocatorIfEEEEJEEEvOT_DpOT0_:
   98|  5.48k|    void AddProperties(T&& value, More&&... more) {
   99|  5.48k|        properties.emplace_back(std::forward<T>(value));
  100|  5.48k|        AddProperties(std::forward<More>(more)...);
  101|  5.48k|    }
_ZN6Assimp3FBX4Node13AddPropertiesIRKNSt3__112basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEEJRA4_KcRA8_SC_RA1_SC_RiEEEvOT_DpOT0_:
   98|  39.5k|    void AddProperties(T&& value, More&&... more) {
   99|  39.5k|        properties.emplace_back(std::forward<T>(value));
  100|  39.5k|        AddProperties(std::forward<More>(more)...);
  101|  39.5k|    }
_ZN6Assimp3FBX4Node13AddPropertiesIRA4_KcJRA8_S3_RA1_S3_RiEEEvOT_DpOT0_:
   98|  39.5k|    void AddProperties(T&& value, More&&... more) {
   99|  39.5k|        properties.emplace_back(std::forward<T>(value));
  100|  39.5k|        AddProperties(std::forward<More>(more)...);
  101|  39.5k|    }
_ZN6Assimp3FBX4Node13AddPropertiesIRA8_KcJRA1_S3_RiEEEvOT_DpOT0_:
   98|  39.5k|    void AddProperties(T&& value, More&&... more) {
   99|  39.5k|        properties.emplace_back(std::forward<T>(value));
  100|  39.5k|        AddProperties(std::forward<More>(more)...);
  101|  39.5k|    }
_ZN6Assimp3FBX4Node13AddPropertiesIRA1_KcJRiEEEvOT_DpOT0_:
   98|  78.4k|    void AddProperties(T&& value, More&&... more) {
   99|  78.4k|        properties.emplace_back(std::forward<T>(value));
  100|  78.4k|        AddProperties(std::forward<More>(more)...);
  101|  78.4k|    }
_ZN6Assimp3FBX4Node13AddPropertiesIRKNSt3__112basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEEJRA5_KcRA1_SC_SG_iEEEvOT_DpOT0_:
   98|  43.7k|    void AddProperties(T&& value, More&&... more) {
   99|  43.7k|        properties.emplace_back(std::forward<T>(value));
  100|  43.7k|        AddProperties(std::forward<More>(more)...);
  101|  43.7k|    }
_ZN6Assimp3FBX4Node13AddPropertiesIRA5_KcJRA1_S3_S7_iEEEvOT_DpOT0_:
   98|  43.7k|    void AddProperties(T&& value, More&&... more) {
   99|  43.7k|        properties.emplace_back(std::forward<T>(value));
  100|  43.7k|        AddProperties(std::forward<More>(more)...);
  101|  43.7k|    }
_ZN6Assimp3FBX4Node13AddPropertiesIRA1_KcJS5_iEEEvOT_DpOT0_:
   98|  43.7k|    void AddProperties(T&& value, More&&... more) {
   99|  43.7k|        properties.emplace_back(std::forward<T>(value));
  100|  43.7k|        AddProperties(std::forward<More>(more)...);
  101|  43.7k|    }
_ZN6Assimp3FBX4Node13AddPropertiesIRA1_KcJiEEEvOT_DpOT0_:
   98|  43.7k|    void AddProperties(T&& value, More&&... more) {
   99|  43.7k|        properties.emplace_back(std::forward<T>(value));
  100|  43.7k|        AddProperties(std::forward<More>(more)...);
  101|  43.7k|    }
_ZN6Assimp3FBX4Node13AddPropertiesIRKNSt3__112basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEEJRA7_KcSE_RA1_SC_RdEEEvOT_DpOT0_:
   98|  5.83k|    void AddProperties(T&& value, More&&... more) {
   99|  5.83k|        properties.emplace_back(std::forward<T>(value));
  100|  5.83k|        AddProperties(std::forward<More>(more)...);
  101|  5.83k|    }
_ZN6Assimp3FBX4Node13AddPropertiesIRA7_KcJS5_RA1_S3_RdEEEvOT_DpOT0_:
   98|  5.83k|    void AddProperties(T&& value, More&&... more) {
   99|  5.83k|        properties.emplace_back(std::forward<T>(value));
  100|  5.83k|        AddProperties(std::forward<More>(more)...);
  101|  5.83k|    }
_ZN6Assimp3FBX4Node13AddPropertiesIRA7_KcJRA1_S3_RdEEEvOT_DpOT0_:
   98|  5.83k|    void AddProperties(T&& value, More&&... more) {
   99|  5.83k|        properties.emplace_back(std::forward<T>(value));
  100|  5.83k|        AddProperties(std::forward<More>(more)...);
  101|  5.83k|    }
_ZN6Assimp3FBX4Node13AddPropertiesIRA1_KcJRdEEEvOT_DpOT0_:
   98|  5.83k|    void AddProperties(T&& value, More&&... more) {
   99|  5.83k|        properties.emplace_back(std::forward<T>(value));
  100|  5.83k|        AddProperties(std::forward<More>(more)...);
  101|  5.83k|    }
_ZN6Assimp3FBX4Node13AddPropertiesIRKNSt3__112basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEEJRA7_KcRA1_SC_RA2_SC_RdEEEvOT_DpOT0_:
   98|  6.65k|    void AddProperties(T&& value, More&&... more) {
   99|  6.65k|        properties.emplace_back(std::forward<T>(value));
  100|  6.65k|        AddProperties(std::forward<More>(more)...);
  101|  6.65k|    }
_ZN6Assimp3FBX4Node13AddPropertiesIRA7_KcJRA1_S3_RA2_S3_RdEEEvOT_DpOT0_:
   98|  6.65k|    void AddProperties(T&& value, More&&... more) {
   99|  6.65k|        properties.emplace_back(std::forward<T>(value));
  100|  6.65k|        AddProperties(std::forward<More>(more)...);
  101|  6.65k|    }
_ZN6Assimp3FBX4Node13AddPropertiesIRA1_KcJRA2_S3_RdEEEvOT_DpOT0_:
   98|  6.65k|    void AddProperties(T&& value, More&&... more) {
   99|  6.65k|        properties.emplace_back(std::forward<T>(value));
  100|  6.65k|        AddProperties(std::forward<More>(more)...);
  101|  6.65k|    }
_ZN6Assimp3FBX4Node13AddPropertiesIRA2_KcJRdEEEvOT_DpOT0_:
   98|  6.65k|    void AddProperties(T&& value, More&&... more) {
   99|  6.65k|        properties.emplace_back(std::forward<T>(value));
  100|  6.65k|        AddProperties(std::forward<More>(more)...);
  101|  6.65k|    }
_ZN6Assimp3FBX4Node13AddPropertiesIRKNSt3__112basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEEJRA9_KcRA6_SC_RA1_SC_RdSJ_SJ_EEEvOT_DpOT0_:
   98|    964|    void AddProperties(T&& value, More&&... more) {
   99|    964|        properties.emplace_back(std::forward<T>(value));
  100|    964|        AddProperties(std::forward<More>(more)...);
  101|    964|    }
_ZN6Assimp3FBX4Node13AddPropertiesIRA9_KcJRA6_S3_RA1_S3_RdSA_SA_EEEvOT_DpOT0_:
   98|    964|    void AddProperties(T&& value, More&&... more) {
   99|    964|        properties.emplace_back(std::forward<T>(value));
  100|    964|        AddProperties(std::forward<More>(more)...);
  101|    964|    }
_ZN6Assimp3FBX4Node13AddPropertiesIRA6_KcJRA1_S3_RdS8_S8_EEEvOT_DpOT0_:
   98|    964|    void AddProperties(T&& value, More&&... more) {
   99|    964|        properties.emplace_back(std::forward<T>(value));
  100|    964|        AddProperties(std::forward<More>(more)...);
  101|    964|    }
_ZN6Assimp3FBX4Node13AddPropertiesIRA1_KcJRdS6_S6_EEEvOT_DpOT0_:
   98|  5.70k|    void AddProperties(T&& value, More&&... more) {
   99|  5.70k|        properties.emplace_back(std::forward<T>(value));
  100|  5.70k|        AddProperties(std::forward<More>(more)...);
  101|  5.70k|    }
_ZN6Assimp3FBX4Node13AddPropertiesIRdJS3_S3_EEEvOT_DpOT0_:
   98|  7.64k|    void AddProperties(T&& value, More&&... more) {
   99|  7.64k|        properties.emplace_back(std::forward<T>(value));
  100|  7.64k|        AddProperties(std::forward<More>(more)...);
  101|  7.64k|    }
_ZN6Assimp3FBX4Node13AddPropertiesIRdJS3_EEEvOT_DpOT0_:
   98|  7.64k|    void AddProperties(T&& value, More&&... more) {
   99|  7.64k|        properties.emplace_back(std::forward<T>(value));
  100|  7.64k|        AddProperties(std::forward<More>(more)...);
  101|  7.64k|    }
_ZN6Assimp3FBX4Node13AddPropertiesIRKNSt3__112basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEEJRA6_KcRA1_SC_RA2_SC_RdSJ_SJ_EEEvOT_DpOT0_:
   98|  1.50k|    void AddProperties(T&& value, More&&... more) {
   99|  1.50k|        properties.emplace_back(std::forward<T>(value));
  100|  1.50k|        AddProperties(std::forward<More>(more)...);
  101|  1.50k|    }
_ZN6Assimp3FBX4Node13AddPropertiesIRA6_KcJRA1_S3_RA2_S3_RdSA_SA_EEEvOT_DpOT0_:
   98|  1.50k|    void AddProperties(T&& value, More&&... more) {
   99|  1.50k|        properties.emplace_back(std::forward<T>(value));
  100|  1.50k|        AddProperties(std::forward<More>(more)...);
  101|  1.50k|    }
_ZN6Assimp3FBX4Node13AddPropertiesIRA1_KcJRA2_S3_RdS8_S8_EEEvOT_DpOT0_:
   98|  1.94k|    void AddProperties(T&& value, More&&... more) {
   99|  1.94k|        properties.emplace_back(std::forward<T>(value));
  100|  1.94k|        AddProperties(std::forward<More>(more)...);
  101|  1.94k|    }
_ZN6Assimp3FBX4Node13AddPropertiesIRA2_KcJRdS6_S6_EEEvOT_DpOT0_:
   98|  1.94k|    void AddProperties(T&& value, More&&... more) {
   99|  1.94k|        properties.emplace_back(std::forward<T>(value));
  100|  1.94k|        AddProperties(std::forward<More>(more)...);
  101|  1.94k|    }
_ZN6Assimp3FBX4Node13AddPropertiesIRKNSt3__112basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEEJRA9_KcRA7_SC_RA1_SC_RdSJ_SJ_EEEvOT_DpOT0_:
   98|  4.74k|    void AddProperties(T&& value, More&&... more) {
   99|  4.74k|        properties.emplace_back(std::forward<T>(value));
  100|  4.74k|        AddProperties(std::forward<More>(more)...);
  101|  4.74k|    }
_ZN6Assimp3FBX4Node13AddPropertiesIRA9_KcJRA7_S3_RA1_S3_RdSA_SA_EEEvOT_DpOT0_:
   98|  4.74k|    void AddProperties(T&& value, More&&... more) {
   99|  4.74k|        properties.emplace_back(std::forward<T>(value));
  100|  4.74k|        AddProperties(std::forward<More>(more)...);
  101|  4.74k|    }
_ZN6Assimp3FBX4Node13AddPropertiesIRA7_KcJRA1_S3_RdS8_S8_EEEvOT_DpOT0_:
   98|  4.74k|    void AddProperties(T&& value, More&&... more) {
   99|  4.74k|        properties.emplace_back(std::forward<T>(value));
  100|  4.74k|        AddProperties(std::forward<More>(more)...);
  101|  4.74k|    }
_ZN6Assimp3FBX4Node13AddPropertiesIRKNSt3__112basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEEJRA7_KcRA1_SC_RA2_SC_RdSJ_SJ_EEEvOT_DpOT0_:
   98|    438|    void AddProperties(T&& value, More&&... more) {
   99|    438|        properties.emplace_back(std::forward<T>(value));
  100|    438|        AddProperties(std::forward<More>(more)...);
  101|    438|    }
_ZN6Assimp3FBX4Node13AddPropertiesIRA7_KcJRA1_S3_RA2_S3_RdSA_SA_EEEvOT_DpOT0_:
   98|    438|    void AddProperties(T&& value, More&&... more) {
   99|    438|        properties.emplace_back(std::forward<T>(value));
  100|    438|        AddProperties(std::forward<More>(more)...);
  101|    438|    }
_ZN6Assimp3FBX4Node13AddPropertiesIRKNSt3__112basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEEJRA8_KcRA1_SC_SG_SB_EEEvOT_DpOT0_:
   98|    675|    void AddProperties(T&& value, More&&... more) {
   99|    675|        properties.emplace_back(std::forward<T>(value));
  100|    675|        AddProperties(std::forward<More>(more)...);
  101|    675|    }
_ZN6Assimp3FBX4Node13AddPropertiesIRA8_KcJRA1_S3_S7_RKNSt3__112basic_stringIcNS8_11char_traitsIcEENS8_9allocatorIcEEEEEEEvOT_DpOT0_:
   98|    675|    void AddProperties(T&& value, More&&... more) {
   99|    675|        properties.emplace_back(std::forward<T>(value));
  100|    675|        AddProperties(std::forward<More>(more)...);
  101|    675|    }
_ZN6Assimp3FBX4Node13AddPropertiesIRA1_KcJS5_RKNSt3__112basic_stringIcNS6_11char_traitsIcEENS6_9allocatorIcEEEEEEEvOT_DpOT0_:
   98|    675|    void AddProperties(T&& value, More&&... more) {
   99|    675|        properties.emplace_back(std::forward<T>(value));
  100|    675|        AddProperties(std::forward<More>(more)...);
  101|    675|    }
_ZN6Assimp3FBX4Node13AddPropertiesIRA1_KcJRKNSt3__112basic_stringIcNS6_11char_traitsIcEENS6_9allocatorIcEEEEEEEvOT_DpOT0_:
   98|    675|    void AddProperties(T&& value, More&&... more) {
   99|    675|        properties.emplace_back(std::forward<T>(value));
  100|    675|        AddProperties(std::forward<More>(more)...);
  101|    675|    }
_ZN6Assimp3FBX4Node13AddPropertiesIRKNSt3__112basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEEJRA5_KcRA1_SC_SG_RiEEEvOT_DpOT0_:
   98|  38.9k|    void AddProperties(T&& value, More&&... more) {
   99|  38.9k|        properties.emplace_back(std::forward<T>(value));
  100|  38.9k|        AddProperties(std::forward<More>(more)...);
  101|  38.9k|    }
_ZN6Assimp3FBX4Node13AddPropertiesIRA5_KcJRA1_S3_S7_RiEEEvOT_DpOT0_:
   98|  38.9k|    void AddProperties(T&& value, More&&... more) {
   99|  38.9k|        properties.emplace_back(std::forward<T>(value));
  100|  38.9k|        AddProperties(std::forward<More>(more)...);
  101|  38.9k|    }
_ZN6Assimp3FBX4Node13AddPropertiesIRA1_KcJS5_RiEEEvOT_DpOT0_:
   98|  38.9k|    void AddProperties(T&& value, More&&... more) {
   99|  38.9k|        properties.emplace_back(std::forward<T>(value));
  100|  38.9k|        AddProperties(std::forward<More>(more)...);
  101|  38.9k|    }
_ZN6Assimp3FBX4Node13AddPropertiesIRKNSt3__112basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEEJRA6_KcRA5_SC_RA1_SC_RlEEEvOT_DpOT0_:
   98|    680|    void AddProperties(T&& value, More&&... more) {
   99|    680|        properties.emplace_back(std::forward<T>(value));
  100|    680|        AddProperties(std::forward<More>(more)...);
  101|    680|    }
_ZN6Assimp3FBX4Node13AddPropertiesIRA6_KcJRA5_S3_RA1_S3_RlEEEvOT_DpOT0_:
   98|    680|    void AddProperties(T&& value, More&&... more) {
   99|    680|        properties.emplace_back(std::forward<T>(value));
  100|    680|        AddProperties(std::forward<More>(more)...);
  101|    680|    }
_ZN6Assimp3FBX4Node13AddPropertiesIRA5_KcJRA1_S3_RlEEEvOT_DpOT0_:
   98|    680|    void AddProperties(T&& value, More&&... more) {
   99|    680|        properties.emplace_back(std::forward<T>(value));
  100|    680|        AddProperties(std::forward<More>(more)...);
  101|    680|    }
_ZN6Assimp3FBX4Node13AddPropertiesIRA1_KcJRlEEEvOT_DpOT0_:
   98|    680|    void AddProperties(T&& value, More&&... more) {
   99|    680|        properties.emplace_back(std::forward<T>(value));
  100|    680|        AddProperties(std::forward<More>(more)...);
  101|    680|    }

_ZN6Assimp3FBX17FBXExportPropertyC2Eb:
   61|  37.1k|: type('C')
   62|  37.1k|, data(1, uint8_t(v)) {}
_ZN6Assimp3FBX17FBXExportPropertyC2Ei:
   72|   299k|: type('I')
   73|   299k|, data(4) {
   74|   299k|    uint8_t* d = data.data();
   75|   299k|    (reinterpret_cast<int32_t*>(d))[0] = v;
   76|   299k|}
_ZN6Assimp3FBX17FBXExportPropertyC2Ed:
   86|  47.2k|: type('D')
   87|  47.2k|, data(8) {
   88|  47.2k|    uint8_t* d = data.data();
   89|  47.2k|    (reinterpret_cast<double*>(d))[0] = v;
   90|  47.2k|}
_ZN6Assimp3FBX17FBXExportPropertyC2El:
   93|   229k|: type('L')
   94|   229k|, data(8) {
   95|   229k|    uint8_t* d = data.data();
   96|   229k|    (reinterpret_cast<int64_t*>(d))[0] = v;
   97|   229k|}
_ZN6Assimp3FBX17FBXExportPropertyC2EPKcb:
  102|   702k|: FBXExportProperty(std::string(c), raw) {
  103|       |    // empty
  104|   702k|}
_ZN6Assimp3FBX17FBXExportPropertyC2ERKNSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEEb:
  108|   970k|: type(raw ? 'R' : 'S')
  ------------------
  |  Branch (108:8): [True: 0, False: 970k]
  ------------------
  109|   970k|, data(s.size()) {
  110|  7.77M|    for (size_t i = 0; i < s.size(); ++i) {
  ------------------
  |  Branch (110:24): [True: 6.80M, False: 970k]
  ------------------
  111|  6.80M|        data[i] = uint8_t(s[i]);
  112|  6.80M|    }
  113|   970k|}
_ZN6Assimp3FBX17FBXExportPropertyC2ERKNSt3__16vectorIhNS2_9allocatorIhEEEE:
  116|    215|: type('R')
  117|    215|, data(r) {
  118|       |    // empty
  119|    215|}
_ZN6Assimp3FBX17FBXExportPropertyC2ERKNSt3__16vectorIiNS2_9allocatorIiEEEE:
  122|  26.6k|: type('i')
  123|  26.6k|, data(4 * va.size() ) {
  124|  26.6k|    int32_t* d = reinterpret_cast<int32_t*>(data.data());
  125|   292k|    for (size_t i = 0; i < va.size(); ++i) {
  ------------------
  |  Branch (125:24): [True: 266k, False: 26.6k]
  ------------------
  126|   266k|        d[i] = va[i];
  127|   266k|    }
  128|  26.6k|}
_ZN6Assimp3FBX17FBXExportPropertyC2ERKNSt3__16vectorIlNS2_9allocatorIlEEEE:
  131|  5.48k|: type('l')
  132|  5.48k|, data(8 * va.size()) {
  133|  5.48k|    int64_t* d = reinterpret_cast<int64_t*>(data.data());
  134|  43.8k|    for (size_t i = 0; i < va.size(); ++i) {
  ------------------
  |  Branch (134:24): [True: 38.4k, False: 5.48k]
  ------------------
  135|  38.4k|        d[i] = va[i];
  136|  38.4k|    }
  137|  5.48k|}
_ZN6Assimp3FBX17FBXExportPropertyC2ERKNSt3__16vectorIfNS2_9allocatorIfEEEE:
  140|  10.9k|: type('f')
  141|  10.9k|, data(4 * va.size()) {
  142|  10.9k|    float* d = reinterpret_cast<float*>(data.data());
  143|  71.2k|    for (size_t i = 0; i < va.size(); ++i) {
  ------------------
  |  Branch (143:24): [True: 60.3k, False: 10.9k]
  ------------------
  144|  60.3k|        d[i] = va[i];
  145|  60.3k|    }
  146|  10.9k|}
_ZN6Assimp3FBX17FBXExportPropertyC2ERKNSt3__16vectorIdNS2_9allocatorIdEEEE:
  149|  3.08k|: type('d')
  150|  3.08k|, data(8 * va.size()) {
  151|  3.08k|    double* d = reinterpret_cast<double*>(data.data());
  152|  19.7k|    for (size_t i = 0; i < va.size(); ++i) {
  ------------------
  |  Branch (152:24): [True: 16.6k, False: 3.08k]
  ------------------
  153|  16.6k|        d[i] = va[i];
  154|  16.6k|    }
  155|  3.08k|}
_ZN6Assimp3FBX17FBXExportPropertyC2ERK12aiMatrix4x4tIfE:
  158|  6.17k|: type('d')
  159|  6.17k|, data(8 * 16) {
  160|  6.17k|    double* d = reinterpret_cast<double*>(data.data());
  161|  30.8k|    for (unsigned int c = 0; c < 4; ++c) {
  ------------------
  |  Branch (161:30): [True: 24.6k, False: 6.17k]
  ------------------
  162|   123k|        for (unsigned int r = 0; r < 4; ++r) {
  ------------------
  |  Branch (162:34): [True: 98.7k, False: 24.6k]
  ------------------
  163|  98.7k|            d[4 * c + r] = vm[r][c];
  164|  98.7k|        }
  165|  24.6k|    }
  166|  6.17k|}
_ZN6Assimp3FBX17FBXExportProperty10DumpBinaryERNS_12StreamWriterILb0ELb0EEE:
  190|  1.63M|void FBXExportProperty::DumpBinary(Assimp::StreamWriterLE& s) {
  191|  1.63M|    s.PutU1(type);
  192|  1.63M|    uint8_t* d = data.data();
  193|  1.63M|    size_t N;
  194|  1.63M|    switch (type) {
  195|  37.1k|        case 'C': s.PutU1(*(reinterpret_cast<uint8_t*>(d))); return;
  ------------------
  |  Branch (195:9): [True: 37.1k, False: 1.59M]
  ------------------
  196|      0|        case 'Y': s.PutI2(*(reinterpret_cast<int16_t*>(d))); return;
  ------------------
  |  Branch (196:9): [True: 0, False: 1.63M]
  ------------------
  197|   299k|        case 'I': s.PutI4(*(reinterpret_cast<int32_t*>(d))); return;
  ------------------
  |  Branch (197:9): [True: 299k, False: 1.33M]
  ------------------
  198|      0|        case 'F': s.PutF4(*(reinterpret_cast<float*>(d))); return;
  ------------------
  |  Branch (198:9): [True: 0, False: 1.63M]
  ------------------
  199|  47.2k|        case 'D': s.PutF8(*(reinterpret_cast<double*>(d))); return;
  ------------------
  |  Branch (199:9): [True: 47.2k, False: 1.58M]
  ------------------
  200|   229k|        case 'L': s.PutI8(*(reinterpret_cast<int64_t*>(d))); return;
  ------------------
  |  Branch (200:9): [True: 229k, False: 1.40M]
  ------------------
  201|   970k|        case 'S':
  ------------------
  |  Branch (201:9): [True: 970k, False: 665k]
  ------------------
  202|   970k|        case 'R':
  ------------------
  |  Branch (202:9): [True: 215, False: 1.63M]
  ------------------
  203|   970k|            s.PutU4(uint32_t(data.size()));
  204|  8.13M|            for (size_t i = 0; i < data.size(); ++i) { s.PutU1(data[i]); }
  ------------------
  |  Branch (204:32): [True: 7.16M, False: 970k]
  ------------------
  205|   970k|            return;
  206|  26.6k|        case 'i':
  ------------------
  |  Branch (206:9): [True: 26.6k, False: 1.60M]
  ------------------
  207|  26.6k|            N = data.size() / 4;
  208|  26.6k|            s.PutU4(uint32_t(N)); // number of elements
  209|  26.6k|            s.PutU4(0); // no encoding (1 would be zip-compressed)
  210|       |            // TODO: compress if large?
  211|  26.6k|            s.PutU4(uint32_t(data.size())); // data size
  212|   292k|            for (size_t i = 0; i < N; ++i) {
  ------------------
  |  Branch (212:32): [True: 266k, False: 26.6k]
  ------------------
  213|   266k|                s.PutI4((reinterpret_cast<int32_t*>(d))[i]);
  214|   266k|            }
  215|  26.6k|            return;
  216|  5.48k|        case 'l':
  ------------------
  |  Branch (216:9): [True: 5.48k, False: 1.63M]
  ------------------
  217|  5.48k|            N = data.size() / 8;
  218|  5.48k|            s.PutU4(uint32_t(N)); // number of elements
  219|  5.48k|            s.PutU4(0); // no encoding (1 would be zip-compressed)
  220|       |            // TODO: compress if large?
  221|  5.48k|            s.PutU4(uint32_t(data.size())); // data size
  222|  43.8k|            for (size_t i = 0; i < N; ++i) {
  ------------------
  |  Branch (222:32): [True: 38.4k, False: 5.48k]
  ------------------
  223|  38.4k|                s.PutI8((reinterpret_cast<int64_t*>(d))[i]);
  224|  38.4k|            }
  225|  5.48k|            return;
  226|  10.9k|        case 'f':
  ------------------
  |  Branch (226:9): [True: 10.9k, False: 1.62M]
  ------------------
  227|  10.9k|            N = data.size() / 4;
  228|  10.9k|            s.PutU4(uint32_t(N)); // number of elements
  229|  10.9k|            s.PutU4(0); // no encoding (1 would be zip-compressed)
  230|       |            // TODO: compress if large?
  231|  10.9k|            s.PutU4(uint32_t(data.size())); // data size
  232|  71.2k|            for (size_t i = 0; i < N; ++i) {
  ------------------
  |  Branch (232:32): [True: 60.3k, False: 10.9k]
  ------------------
  233|  60.3k|                s.PutF4((reinterpret_cast<float*>(d))[i]);
  234|  60.3k|            }
  235|  10.9k|            return;
  236|  9.25k|        case 'd':
  ------------------
  |  Branch (236:9): [True: 9.25k, False: 1.62M]
  ------------------
  237|  9.25k|            N = data.size() / 8;
  238|  9.25k|            s.PutU4(uint32_t(N)); // number of elements
  239|  9.25k|            s.PutU4(0); // no encoding (1 would be zip-compressed)
  240|       |            // TODO: compress if large?
  241|  9.25k|            s.PutU4(uint32_t(data.size())); // data size
  242|   124k|            for (size_t i = 0; i < N; ++i) {
  ------------------
  |  Branch (242:32): [True: 115k, False: 9.25k]
  ------------------
  243|   115k|                s.PutF8((reinterpret_cast<double*>(d))[i]);
  244|   115k|            }
  245|  9.25k|            return;
  246|      0|        default:
  ------------------
  |  Branch (246:9): [True: 0, False: 1.63M]
  ------------------
  247|      0|            std::ostringstream err;
  248|      0|            err << "Tried to dump property with invalid type '";
  249|      0|            err << type << "'!";
  250|      0|            throw DeadlyExportError(err.str());
  251|  1.63M|    }
  252|  1.63M|}

_ZN6Assimp14ExportSceneFBXEPKcPNS_8IOSystemEPK7aiScenePKNS_16ExportPropertiesE:
  110|    208|    ){
  111|       |        // initialize the exporter
  112|    208|        FBXExporter exporter(pScene, pProperties);
  113|       |
  114|       |        // perform binary export
  115|    208|        exporter.ExportBinary(pFile, pIOSystem);
  116|    208|    }
_ZN6Assimp11FBXExporterC2EPK7aiScenePKNS_16ExportPropertiesE:
  138|    208|: binary(false)
  139|    208|, mScene(pScene)
  140|    208|, mProperties(pProperties)
  141|    208|, outfile()
  142|    208|, connections()
  143|    208|, mesh_uids()
  144|    208|, material_uids()
  145|    208|, node_uids() {
  146|       |    // will probably need to determine UIDs, connections, etc here.
  147|       |    // basically anything that needs to be known
  148|       |    // before we start writing sections to the stream.
  149|    208|}
_ZN6Assimp11FBXExporter12ExportBinaryEPKcPNS_8IOSystemE:
  154|    208|){
  155|       |    // remember that we're exporting in binary mode
  156|    208|    binary = true;
  157|       |
  158|       |    // we're not currently using these preferences,
  159|       |    // but clang will cry about it if we never touch it.
  160|       |    // TODO: some of these might be relevant to export
  161|    208|    (void)mProperties;
  162|       |
  163|       |    // open the indicated file for writing (in binary mode)
  164|    208|    outfile.reset(pIOSystem->Open(pFile,"wb"));
  165|    208|    if (!outfile) {
  ------------------
  |  Branch (165:9): [True: 0, False: 208]
  ------------------
  166|      0|        throw DeadlyExportError(
  167|      0|            "could not open output .fbx file: " + std::string(pFile)
  168|      0|        );
  169|      0|    }
  170|       |
  171|       |    // first a binary-specific file header
  172|    208|    WriteBinaryHeader();
  173|       |
  174|       |    // the rest of the file is in node entries.
  175|       |    // we have to serialize each entry before we write to the output,
  176|       |    // as the first thing we write is the byte offset of the _next_ entry.
  177|       |    // Either that or we can skip back to write the offset when we finish.
  178|    208|    WriteAllNodes();
  179|       |
  180|       |    // finally we have a binary footer to the file
  181|    208|    WriteBinaryFooter();
  182|       |
  183|       |    // explicitly release file pointer,
  184|       |    // so we don't have to rely on class destruction.
  185|    208|    outfile.reset();
  186|    208|}
_ZN6Assimp11FBXExporter17WriteBinaryHeaderEv:
  241|    208|{
  242|       |    // first a specific sequence of 23 bytes, always the same
  243|    208|    const char binary_header[24] = "Kaydara FBX Binary\x20\x20\x00\x1a\x00";
  244|    208|    outfile->Write(binary_header, 1, 23);
  245|       |
  246|       |    // then FBX version number, "multiplied" by 1000, as little-endian uint32.
  247|       |    // so 7.3 becomes 7300 == 0x841C0000, 7.4 becomes 7400 == 0xE81C0000, etc
  248|    208|    {
  249|    208|        StreamWriterLE outstream(outfile);
  250|    208|        outstream.PutU4(EXPORT_VERSION_INT);
  251|    208|    } // StreamWriter destructor writes the data to the file
  252|       |
  253|       |    // after this the node data starts immediately
  254|       |    // (probably with the FBXHEaderExtension node)
  255|    208|}
_ZN6Assimp11FBXExporter17WriteBinaryFooterEv:
  258|    207|{
  259|    207|    outfile->Write(NULL_RECORD, NumNullRecords, 1);
  260|       |
  261|    207|    outfile->Write(GENERIC_FOOTID.c_str(), GENERIC_FOOTID.size(), 1);
  262|       |
  263|       |    // here some padding is added for alignment to 16 bytes.
  264|       |    // if already aligned, the full 16 bytes is added.
  265|    207|    size_t pos = outfile->Tell();
  266|    207|    size_t pad = 16 - (pos % 16);
  267|  1.92k|    for (size_t i = 0; i < pad; ++i) {
  ------------------
  |  Branch (267:24): [True: 1.71k, False: 207]
  ------------------
  268|  1.71k|        outfile->Write("\x00", 1, 1);
  269|  1.71k|    }
  270|       |
  271|       |    // not sure what this is, but it seems to always be 0 in modern files
  272|  1.03k|    for (size_t i = 0; i < 4; ++i) {
  ------------------
  |  Branch (272:24): [True: 828, False: 207]
  ------------------
  273|    828|        outfile->Write("\x00", 1, 1);
  274|    828|    }
  275|       |
  276|       |    // now the file version again
  277|    207|    {
  278|    207|        StreamWriterLE outstream(outfile);
  279|    207|        outstream.PutU4(EXPORT_VERSION_INT);
  280|    207|    } // StreamWriter destructor writes the data to the file
  281|       |
  282|       |    // and finally some binary footer added to all files
  283|  25.0k|    for (size_t i = 0; i < 120; ++i) {
  ------------------
  |  Branch (283:24): [True: 24.8k, False: 207]
  ------------------
  284|  24.8k|        outfile->Write("\x00", 1, 1);
  285|  24.8k|    }
  286|    207|    outfile->Write(FOOT_MAGIC.c_str(), FOOT_MAGIC.size(), 1);
  287|    207|}
_ZN6Assimp11FBXExporter13WriteAllNodesEv:
  290|    208|{
  291|       |    // header
  292|       |    // (and fileid, creation time, creator, if binary)
  293|    208|    WriteHeaderExtension();
  294|       |
  295|       |    // global settings
  296|    208|    WriteGlobalSettings();
  297|       |
  298|       |    // documents
  299|    208|    WriteDocuments();
  300|       |
  301|       |    // references
  302|    208|    WriteReferences();
  303|       |
  304|       |    // definitions
  305|    208|    WriteDefinitions();
  306|       |
  307|       |    // objects
  308|    208|    WriteObjects();
  309|       |
  310|       |    // connections
  311|    208|    WriteConnections();
  312|       |
  313|       |    // WriteTakes? (deprecated since at least 2015 (fbx 7.4))
  314|    208|}
_ZN6Assimp11FBXExporter20WriteHeaderExtensionEv:
  318|    208|{
  319|    208|    if (!binary) {
  ------------------
  |  Branch (319:9): [True: 0, False: 208]
  ------------------
  320|       |        // no title, follows directly from the top comment
  321|      0|    }
  322|    208|    FBX::Node n("FBXHeaderExtension");
  323|    208|    StreamWriterLE outstream(outfile);
  324|    208|    int indent = 0;
  325|       |
  326|       |    // begin node
  327|    208|    n.Begin(outstream, binary, indent);
  328|       |
  329|       |    // write properties
  330|       |    // (none)
  331|       |
  332|       |    // finish properties
  333|    208|    n.EndProperties(outstream, binary, indent, 0);
  334|       |
  335|       |    // begin children
  336|    208|    n.BeginChildren(outstream, binary, indent);
  337|       |
  338|    208|    indent = 1;
  339|       |
  340|       |    // write child nodes
  341|    208|    FBX::Node::WritePropertyNode(
  342|    208|        "FBXHeaderVersion", int32_t(1003), outstream, binary, indent
  343|    208|    );
  344|    208|    FBX::Node::WritePropertyNode(
  345|    208|        "FBXVersion", int32_t(EXPORT_VERSION_INT), outstream, binary, indent
  346|    208|    );
  347|    208|    if (binary) {
  ------------------
  |  Branch (347:9): [True: 208, False: 0]
  ------------------
  348|    208|        FBX::Node::WritePropertyNode(
  349|    208|            "EncryptionType", int32_t(0), outstream, binary, indent
  350|    208|        );
  351|    208|    }
  352|       |
  353|    208|    FBX::Node CreationTimeStamp("CreationTimeStamp");
  354|    208|    time_t rawtime;
  355|    208|    time(&rawtime);
  356|    208|    struct tm * now = localtime(&rawtime);
  357|    208|    CreationTimeStamp.AddChild("Version", int32_t(1000));
  358|    208|    CreationTimeStamp.AddChild("Year", int32_t(now->tm_year + 1900));
  359|    208|    CreationTimeStamp.AddChild("Month", int32_t(now->tm_mon + 1));
  360|    208|    CreationTimeStamp.AddChild("Day", int32_t(now->tm_mday));
  361|    208|    CreationTimeStamp.AddChild("Hour", int32_t(now->tm_hour));
  362|    208|    CreationTimeStamp.AddChild("Minute", int32_t(now->tm_min));
  363|    208|    CreationTimeStamp.AddChild("Second", int32_t(now->tm_sec));
  364|    208|    CreationTimeStamp.AddChild("Millisecond", int32_t(0));
  365|    208|    CreationTimeStamp.Dump(outstream, binary, indent);
  366|       |
  367|    208|    std::stringstream creator;
  368|    208|    creator << "Open Asset Import Library (Assimp) " << aiGetVersionMajor()
  369|    208|            << "." << aiGetVersionMinor() << "." << aiGetVersionRevision();
  370|    208|    FBX::Node::WritePropertyNode(
  371|    208|        "Creator", creator.str(), outstream, binary, indent
  372|    208|    );
  373|       |
  374|    208|    indent = 0;
  375|       |
  376|       |    // finish node
  377|    208|    n.End(outstream, binary, indent, true);
  378|       |
  379|       |    // that's it for FBXHeaderExtension...
  380|    208|    if (!binary) { return; }
  ------------------
  |  Branch (380:9): [True: 0, False: 208]
  ------------------
  381|       |
  382|       |    // but binary files also need top-level FileID, CreationTime, Creator:
  383|    208|    std::vector<uint8_t> raw(GENERIC_FILEID.size());
  384|  3.53k|    for (size_t i = 0; i < GENERIC_FILEID.size(); ++i) {
  ------------------
  |  Branch (384:24): [True: 3.32k, False: 208]
  ------------------
  385|  3.32k|        raw[i] = uint8_t(GENERIC_FILEID[i]);
  386|  3.32k|    }
  387|    208|    FBX::Node::WritePropertyNode(
  388|    208|        "FileId", std::move(raw), outstream, binary, indent
  389|    208|    );
  390|    208|    FBX::Node::WritePropertyNode(
  391|    208|        "CreationTime", GENERIC_CTIME, outstream, binary, indent
  392|    208|    );
  393|    208|    FBX::Node::WritePropertyNode(
  394|    208|        "Creator", creator.str(), outstream, binary, indent
  395|    208|    );
  396|    208|}
_Z12WritePropIntPK7aiSceneRN6Assimp3FBX4NodeERKNSt3__112basic_stringIcNS6_11char_traitsIcEENS6_9allocatorIcEEEEi:
  401|  1.87k|{
  402|  1.87k|    int value;
  403|  1.87k|    if (scene->mMetaData != nullptr && scene->mMetaData->Get(key, value)) {
  ------------------
  |  Branch (403:9): [True: 1.87k, False: 0]
  |  Branch (403:40): [True: 0, False: 1.87k]
  ------------------
  404|      0|        p.AddP70int(key, value);
  405|  1.87k|    } else {
  406|  1.87k|        p.AddP70int(key, defaultValue);
  407|  1.87k|    }
  408|  1.87k|}
_Z15WritePropDoublePK7aiSceneRN6Assimp3FBX4NodeERKNSt3__112basic_stringIcNS6_11char_traitsIcEENS6_9allocatorIcEEEEd:
  411|    624|{
  412|    624|    double value;
  413|    624|    if (scene->mMetaData != nullptr && scene->mMetaData->Get(key, value)) {
  ------------------
  |  Branch (413:9): [True: 624, False: 0]
  |  Branch (413:40): [True: 0, False: 624]
  ------------------
  414|      0|        p.AddP70double(key, value);
  415|    624|    } else {
  416|       |        // fallback lookup float instead
  417|    624|        float floatValue;
  418|    624|        if (scene->mMetaData != nullptr && scene->mMetaData->Get(key, floatValue)) {
  ------------------
  |  Branch (418:13): [True: 624, False: 0]
  |  Branch (418:44): [True: 0, False: 624]
  ------------------
  419|      0|            p.AddP70double(key, (double)floatValue);
  420|    624|        } else {
  421|    624|            p.AddP70double(key, defaultValue);
  422|    624|        }
  423|    624|    }
  424|    624|}
_Z13WritePropEnumPK7aiSceneRN6Assimp3FBX4NodeERKNSt3__112basic_stringIcNS6_11char_traitsIcEENS6_9allocatorIcEEEEi:
  427|    624|{
  428|    624|    int value;
  429|    624|    if (scene->mMetaData != nullptr && scene->mMetaData->Get(key, value)) {
  ------------------
  |  Branch (429:9): [True: 624, False: 0]
  |  Branch (429:40): [True: 0, False: 624]
  ------------------
  430|      0|        p.AddP70enum(key, value);
  431|    624|    } else {
  432|    624|        p.AddP70enum(key, defaultValue);
  433|    624|    }
  434|    624|}
_Z14WritePropColorPK7aiSceneRN6Assimp3FBX4NodeERKNSt3__112basic_stringIcNS6_11char_traitsIcEENS6_9allocatorIcEEEERK10aiVector3tIfE:
  437|    208|{
  438|    208|    aiVector3D value;
  439|    208|    if (scene->mMetaData != nullptr && scene->mMetaData->Get(key, value)) {
  ------------------
  |  Branch (439:9): [True: 208, False: 0]
  |  Branch (439:40): [True: 0, False: 208]
  ------------------
  440|       |        // ai_real can be float or double, cast to avoid warnings
  441|      0|        p.AddP70color(key, (double)value.x, (double)value.y, (double)value.z);
  442|    208|    } else {
  443|    208|        p.AddP70color(key, (double)defaultValue.x, (double)defaultValue.y, (double)defaultValue.z);
  444|    208|    }
  445|    208|}
_Z15WritePropStringPK7aiSceneRN6Assimp3FBX4NodeERKNSt3__112basic_stringIcNS6_11char_traitsIcEENS6_9allocatorIcEEEESE_:
  448|    208|{
  449|    208|    aiString value; // MetaData doesn't hold std::string
  450|    208|    if (scene->mMetaData != nullptr && scene->mMetaData->Get(key, value)) {
  ------------------
  |  Branch (450:9): [True: 208, False: 0]
  |  Branch (450:40): [True: 0, False: 208]
  ------------------
  451|      0|        p.AddP70string(key, value.C_Str());
  452|    208|    } else {
  453|    208|        p.AddP70string(key, defaultValue);
  454|    208|    }
  455|    208|}
_ZN6Assimp11FBXExporter19WriteGlobalSettingsEv:
  457|    208|void FBXExporter::WriteGlobalSettings () {
  458|    208|    FBX::Node gs("GlobalSettings");
  459|    208|    gs.AddChild("Version", int32_t(1000));
  460|       |
  461|    208|    FBX::Node p("Properties70");
  462|    208|    WritePropInt(mScene, p, "UpAxis", 1);
  463|    208|    WritePropInt(mScene, p, "UpAxisSign", 1);
  464|    208|    WritePropInt(mScene, p, "FrontAxis", 2);
  465|    208|    WritePropInt(mScene, p, "FrontAxisSign", 1);
  466|    208|    WritePropInt(mScene, p, "CoordAxis", 0);
  467|    208|    WritePropInt(mScene, p, "CoordAxisSign", 1);
  468|    208|    WritePropInt(mScene, p, "OriginalUpAxis", 1);
  469|    208|    WritePropInt(mScene, p, "OriginalUpAxisSign", 1);
  470|    208|    WritePropDouble(mScene, p, "UnitScaleFactor", 1.0);
  471|    208|    WritePropDouble(mScene, p, "OriginalUnitScaleFactor", 1.0);
  472|    208|    WritePropColor(mScene, p, "AmbientColor", aiVector3D((ai_real)0.0, (ai_real)0.0, (ai_real)0.0));
  473|    208|    WritePropString(mScene, p,"DefaultCamera", "Producer Perspective");
  474|    208|    WritePropEnum(mScene, p, "TimeMode", 11);
  475|    208|    WritePropEnum(mScene, p, "TimeProtocol", 2);
  476|    208|    WritePropEnum(mScene, p, "SnapOnFrameMode", 0);
  477|    208|    p.AddP70time("TimeSpanStart", 0); // TODO: animation support
  478|    208|    p.AddP70time("TimeSpanStop", FBX::SECOND); // TODO: animation support
  479|    208|    WritePropDouble(mScene, p, "CustomFrameRate", -1.0);
  480|    208|    p.AddP70("TimeMarker", "Compound", "", ""); // not sure what this is
  481|    208|    WritePropInt(mScene, p, "CurrentTimeMarker", -1);
  482|    208|    gs.AddChild(p);
  483|       |
  484|    208|    gs.Dump(outfile, binary, 0);
  485|    208|}
_ZN6Assimp11FBXExporter14WriteDocumentsEv:
  487|    208|void FBXExporter::WriteDocuments() {
  488|    208|    if (!binary) {
  ------------------
  |  Branch (488:9): [True: 0, False: 208]
  ------------------
  489|      0|        WriteAsciiSectionHeader("Documents Description");
  490|      0|    }
  491|       |
  492|       |    // not sure what the use of multiple documents would be,
  493|       |    // or whether any end-application supports it
  494|    208|    FBX::Node docs("Documents");
  495|    208|    docs.AddChild("Count", int32_t(1));
  496|    208|    FBX::Node doc("Document");
  497|       |
  498|       |    // generate uid
  499|    208|    int64_t uid = generate_uid();
  500|    208|    doc.AddProperties(uid, "", "Scene");
  501|    208|    FBX::Node p("Properties70");
  502|    208|    p.AddP70("SourceObject", "object", "", ""); // what is this even for?
  503|    208|    p.AddP70string("ActiveAnimStackName", ""); // should do this properly?
  504|    208|    doc.AddChild(p);
  505|       |
  506|       |    // UID for root node in scene hierarchy.
  507|       |    // always set to 0 in the case of a single document.
  508|       |    // not sure what happens if more than one document exists,
  509|       |    // but that won't matter to us as we're exporting a single scene.
  510|    208|    doc.AddChild("RootNode", int64_t(0));
  511|       |
  512|    208|    docs.AddChild(doc);
  513|    208|    docs.Dump(outfile, binary, 0);
  514|    208|}
_ZN6Assimp11FBXExporter15WriteReferencesEv:
  516|    208|void FBXExporter::WriteReferences() {
  517|    208|    if (!binary) {
  ------------------
  |  Branch (517:9): [True: 0, False: 208]
  ------------------
  518|      0|        WriteAsciiSectionHeader("Document References");
  519|      0|    }
  520|       |    // always empty for now.
  521|       |    // not really sure what this is for.
  522|    208|    FBX::Node n("References");
  523|    208|    n.force_has_children = true;
  524|    208|    n.Dump(outfile, binary, 0);
  525|    208|}
_Z11count_nodesPK6aiNodeS1_:
  532|  37.2k|size_t count_nodes(const aiNode* n, const aiNode* root) {
  533|  37.2k|    size_t count;
  534|  37.2k|    if (n == root) {
  ------------------
  |  Branch (534:9): [True: 208, False: 37.0k]
  ------------------
  535|    208|        count = n->mNumMeshes; // (not counting root node)
  536|  37.0k|    } else if (n->mNumMeshes > 1) {
  ------------------
  |  Branch (536:16): [True: 267, False: 36.8k]
  ------------------
  537|    267|        count = n->mNumMeshes + 1;
  538|  36.8k|    } else {
  539|  36.8k|        count = 1;
  540|  36.8k|    }
  541|  74.3k|    for (size_t i = 0; i < n->mNumChildren; ++i) {
  ------------------
  |  Branch (541:24): [True: 37.0k, False: 37.2k]
  ------------------
  542|  37.0k|        count += count_nodes(n->mChildren[i], root);
  543|  37.0k|    }
  544|  37.2k|    return count;
  545|  37.2k|}
_ZN6Assimp11FBXExporter16WriteDefinitionsEv:
  608|    208|void FBXExporter::WriteDefinitions () {
  609|       |    // basically this is just bookkeeping:
  610|       |    // determining how many of each type of object there are
  611|       |    // and specifying the base properties to use when otherwise unspecified.
  612|       |
  613|       |    // ascii section header
  614|    208|    if (!binary) {
  ------------------
  |  Branch (614:9): [True: 0, False: 208]
  ------------------
  615|      0|        WriteAsciiSectionHeader("Object definitions");
  616|      0|    }
  617|       |
  618|       |    // we need to count the objects
  619|    208|    int32_t count;
  620|    208|    int32_t total_count = 0;
  621|       |
  622|       |    // and store them
  623|    208|    std::vector<FBX::Node> object_nodes;
  624|    208|    FBX::Node n, pt, p;
  625|       |
  626|       |    // GlobalSettings
  627|       |    // this seems to always be here in Maya exports
  628|    208|    n = FBX::Node("ObjectType", "GlobalSettings");
  629|    208|    count = 1;
  630|    208|    n.AddChild("Count", count);
  631|    208|    object_nodes.push_back(n);
  632|    208|    total_count += count;
  633|       |
  634|       |    // AnimationStack / FbxAnimStack
  635|       |    // this seems to always be here in Maya exports,
  636|       |    // but no harm seems to come of leaving it out.
  637|    208|    count = mScene->mNumAnimations;
  638|    208|    if (count) {
  ------------------
  |  Branch (638:9): [True: 26, False: 182]
  ------------------
  639|     26|        n = FBX::Node("ObjectType", "AnimationStack");
  640|     26|        n.AddChild("Count", count);
  641|     26|        pt = FBX::Node("PropertyTemplate", "FbxAnimStack");
  642|     26|        p = FBX::Node("Properties70");
  643|     26|        p.AddP70string("Description", "");
  644|     26|        p.AddP70time("LocalStart", 0);
  645|     26|        p.AddP70time("LocalStop", 0);
  646|     26|        p.AddP70time("ReferenceStart", 0);
  647|     26|        p.AddP70time("ReferenceStop", 0);
  648|     26|        pt.AddChild(p);
  649|     26|        n.AddChild(pt);
  650|     26|        object_nodes.push_back(n);
  651|     26|        total_count += count;
  652|     26|    }
  653|       |
  654|       |    // AnimationLayer / FbxAnimLayer
  655|       |    // this seems to always be here in Maya exports,
  656|       |    // but no harm seems to come of leaving it out.
  657|       |    // Assimp doesn't support animation layers,
  658|       |    // so there will be one per aiAnimation
  659|    208|    count = mScene->mNumAnimations;
  660|    208|    if (count) {
  ------------------
  |  Branch (660:9): [True: 26, False: 182]
  ------------------
  661|     26|        n = FBX::Node("ObjectType", "AnimationLayer");
  662|     26|        n.AddChild("Count", count);
  663|     26|        pt = FBX::Node("PropertyTemplate", "FBXAnimLayer");
  664|     26|        p = FBX::Node("Properties70");
  665|     26|        p.AddP70("Weight", "Number", "", "A", double(100));
  666|     26|        p.AddP70bool("Mute", false);
  667|     26|        p.AddP70bool("Solo", false);
  668|     26|        p.AddP70bool("Lock", false);
  669|     26|        p.AddP70color("Color", 0.8, 0.8, 0.8);
  670|     26|        p.AddP70("BlendMode", "enum", "", "", int32_t(0));
  671|     26|        p.AddP70("RotationAccumulationMode", "enum", "", "", int32_t(0));
  672|     26|        p.AddP70("ScaleAccumulationMode", "enum", "", "", int32_t(0));
  673|     26|        p.AddP70("BlendModeBypass", "ULongLong", "", "", int64_t(0));
  674|     26|        pt.AddChild(p);
  675|     26|        n.AddChild(pt);
  676|     26|        object_nodes.push_back(n);
  677|     26|        total_count += count;
  678|     26|    }
  679|       |
  680|       |    // NodeAttribute
  681|       |    // this is completely absurd.
  682|       |    // there can only be one "NodeAttribute" template,
  683|       |    // but FbxSkeleton, FbxCamera, FbxLight all are "NodeAttributes".
  684|       |    // so if only one exists we should set the template for that,
  685|       |    // otherwise... we just pick one :/.
  686|       |    // the others have to set all their properties every instance,
  687|       |    // because there's no template.
  688|    208|    count = 1; // TODO: select properly
  689|    208|    if (count) {
  ------------------
  |  Branch (689:9): [True: 208, False: 0]
  ------------------
  690|       |        // FbxSkeleton
  691|    208|        n = FBX::Node("ObjectType", "NodeAttribute");
  692|    208|        n.AddChild("Count", count);
  693|    208|        pt = FBX::Node("PropertyTemplate", "FbxSkeleton");
  694|    208|        p = FBX::Node("Properties70");
  695|    208|        p.AddP70color("Color", 0.8, 0.8, 0.8);
  696|    208|        p.AddP70double("Size", 33.333333333333);
  697|    208|        p.AddP70("LimbLength", "double", "Number", "H", double(1));
  698|       |        // note: not sure what the "H" flag is for - hidden?
  699|    208|        pt.AddChild(p);
  700|    208|        n.AddChild(pt);
  701|    208|        object_nodes.push_back(n);
  702|    208|        total_count += count;
  703|    208|    }
  704|       |
  705|       |    // Model / FbxNode
  706|       |    // <~~ node hierarchy
  707|    208|    count = int32_t(count_nodes(mScene->mRootNode, mScene->mRootNode));
  708|    208|    if (count) {
  ------------------
  |  Branch (708:9): [True: 208, False: 0]
  ------------------
  709|    208|        n = FBX::Node("ObjectType", "Model");
  710|    208|        n.AddChild("Count", count);
  711|    208|        pt = FBX::Node("PropertyTemplate", "FbxNode");
  712|    208|        p = FBX::Node("Properties70");
  713|    208|        p.AddP70enum("QuaternionInterpolate", 0);
  714|    208|        p.AddP70vector("RotationOffset", 0.0, 0.0, 0.0);
  715|    208|        p.AddP70vector("RotationPivot", 0.0, 0.0, 0.0);
  716|    208|        p.AddP70vector("ScalingOffset", 0.0, 0.0, 0.0);
  717|    208|        p.AddP70vector("ScalingPivot", 0.0, 0.0, 0.0);
  718|    208|        p.AddP70bool("TranslationActive", false);
  719|    208|        p.AddP70vector("TranslationMin", 0.0, 0.0, 0.0);
  720|    208|        p.AddP70vector("TranslationMax", 0.0, 0.0, 0.0);
  721|    208|        p.AddP70bool("TranslationMinX", false);
  722|    208|        p.AddP70bool("TranslationMinY", false);
  723|    208|        p.AddP70bool("TranslationMinZ", false);
  724|    208|        p.AddP70bool("TranslationMaxX", false);
  725|    208|        p.AddP70bool("TranslationMaxY", false);
  726|    208|        p.AddP70bool("TranslationMaxZ", false);
  727|    208|        p.AddP70enum("RotationOrder", 0);
  728|    208|        p.AddP70bool("RotationSpaceForLimitOnly", false);
  729|    208|        p.AddP70double("RotationStiffnessX", 0.0);
  730|    208|        p.AddP70double("RotationStiffnessY", 0.0);
  731|    208|        p.AddP70double("RotationStiffnessZ", 0.0);
  732|    208|        p.AddP70double("AxisLen", 10.0);
  733|    208|        p.AddP70vector("PreRotation", 0.0, 0.0, 0.0);
  734|    208|        p.AddP70vector("PostRotation", 0.0, 0.0, 0.0);
  735|    208|        p.AddP70bool("RotationActive", false);
  736|    208|        p.AddP70vector("RotationMin", 0.0, 0.0, 0.0);
  737|    208|        p.AddP70vector("RotationMax", 0.0, 0.0, 0.0);
  738|    208|        p.AddP70bool("RotationMinX", false);
  739|    208|        p.AddP70bool("RotationMinY", false);
  740|    208|        p.AddP70bool("RotationMinZ", false);
  741|    208|        p.AddP70bool("RotationMaxX", false);
  742|    208|        p.AddP70bool("RotationMaxY", false);
  743|    208|        p.AddP70bool("RotationMaxZ", false);
  744|    208|        p.AddP70enum("InheritType", 0);
  745|    208|        p.AddP70bool("ScalingActive", false);
  746|    208|        p.AddP70vector("ScalingMin", 0.0, 0.0, 0.0);
  747|    208|        p.AddP70vector("ScalingMax", 1.0, 1.0, 1.0);
  748|    208|        p.AddP70bool("ScalingMinX", false);
  749|    208|        p.AddP70bool("ScalingMinY", false);
  750|    208|        p.AddP70bool("ScalingMinZ", false);
  751|    208|        p.AddP70bool("ScalingMaxX", false);
  752|    208|        p.AddP70bool("ScalingMaxY", false);
  753|    208|        p.AddP70bool("ScalingMaxZ", false);
  754|    208|        p.AddP70vector("GeometricTranslation", 0.0, 0.0, 0.0);
  755|    208|        p.AddP70vector("GeometricRotation", 0.0, 0.0, 0.0);
  756|    208|        p.AddP70vector("GeometricScaling", 1.0, 1.0, 1.0);
  757|    208|        p.AddP70double("MinDampRangeX", 0.0);
  758|    208|        p.AddP70double("MinDampRangeY", 0.0);
  759|    208|        p.AddP70double("MinDampRangeZ", 0.0);
  760|    208|        p.AddP70double("MaxDampRangeX", 0.0);
  761|    208|        p.AddP70double("MaxDampRangeY", 0.0);
  762|    208|        p.AddP70double("MaxDampRangeZ", 0.0);
  763|    208|        p.AddP70double("MinDampStrengthX", 0.0);
  764|    208|        p.AddP70double("MinDampStrengthY", 0.0);
  765|    208|        p.AddP70double("MinDampStrengthZ", 0.0);
  766|    208|        p.AddP70double("MaxDampStrengthX", 0.0);
  767|    208|        p.AddP70double("MaxDampStrengthY", 0.0);
  768|    208|        p.AddP70double("MaxDampStrengthZ", 0.0);
  769|    208|        p.AddP70double("PreferedAngleX", 0.0);
  770|    208|        p.AddP70double("PreferedAngleY", 0.0);
  771|    208|        p.AddP70double("PreferedAngleZ", 0.0);
  772|    208|        p.AddP70("LookAtProperty", "object", "", "");
  773|    208|        p.AddP70("UpVectorProperty", "object", "", "");
  774|    208|        p.AddP70bool("Show", true);
  775|    208|        p.AddP70bool("NegativePercentShapeSupport", true);
  776|    208|        p.AddP70int("DefaultAttributeIndex", -1);
  777|    208|        p.AddP70bool("Freeze", false);
  778|    208|        p.AddP70bool("LODBox", false);
  779|    208|        p.AddP70(
  780|    208|            "Lcl Translation", "Lcl Translation", "", "A",
  781|    208|            double(0), double(0), double(0)
  782|    208|        );
  783|    208|        p.AddP70(
  784|    208|            "Lcl Rotation", "Lcl Rotation", "", "A",
  785|    208|            double(0), double(0), double(0)
  786|    208|        );
  787|    208|        p.AddP70(
  788|    208|            "Lcl Scaling", "Lcl Scaling", "", "A",
  789|    208|            double(1), double(1), double(1)
  790|    208|        );
  791|    208|        p.AddP70("Visibility", "Visibility", "", "A", double(1));
  792|    208|        p.AddP70(
  793|    208|            "Visibility Inheritance", "Visibility Inheritance", "", "",
  794|    208|            int32_t(1)
  795|    208|        );
  796|    208|        pt.AddChild(p);
  797|    208|        n.AddChild(pt);
  798|    208|        object_nodes.push_back(n);
  799|    208|        total_count += count;
  800|    208|    }
  801|       |
  802|       |    // Geometry / FbxMesh
  803|       |    // <~~ aiMesh
  804|    208|    count = mScene->mNumMeshes;
  805|       |
  806|       |    // Blendshapes are considered Geometry
  807|    208|    int32_t bsDeformerCount=0;
  808|  3.78k|    for (size_t mi = 0; mi < mScene->mNumMeshes; ++mi) {
  ------------------
  |  Branch (808:25): [True: 3.57k, False: 208]
  ------------------
  809|  3.57k|        aiMesh* m = mScene->mMeshes[mi];
  810|  3.57k|        if (m->mNumAnimMeshes > 0) {
  ------------------
  |  Branch (810:13): [True: 0, False: 3.57k]
  ------------------
  811|      0|          count+=m->mNumAnimMeshes;
  812|      0|          bsDeformerCount+=m->mNumAnimMeshes; // One deformer per blendshape
  813|      0|          bsDeformerCount++;                  // Plus one master blendshape deformer
  814|      0|        }
  815|  3.57k|    }
  816|       |
  817|    208|    if (count) {
  ------------------
  |  Branch (817:9): [True: 174, False: 34]
  ------------------
  818|    174|        n = FBX::Node("ObjectType", "Geometry");
  819|    174|        n.AddChild("Count", count);
  820|    174|        pt = FBX::Node("PropertyTemplate", "FbxMesh");
  821|    174|        p = FBX::Node("Properties70");
  822|    174|        p.AddP70color("Color", 0, 0, 0);
  823|    174|        p.AddP70vector("BBoxMin", 0, 0, 0);
  824|    174|        p.AddP70vector("BBoxMax", 0, 0, 0);
  825|    174|        p.AddP70bool("Primary Visibility", true);
  826|    174|        p.AddP70bool("Casts Shadows", true);
  827|    174|        p.AddP70bool("Receive Shadows", true);
  828|    174|        pt.AddChild(p);
  829|    174|        n.AddChild(pt);
  830|    174|        object_nodes.push_back(n);
  831|    174|        total_count += count;
  832|    174|    }
  833|       |
  834|       |    // Material / FbxSurfacePhong, FbxSurfaceLambert, FbxSurfaceMaterial
  835|       |    // <~~ aiMaterial
  836|       |    // basically if there's any phong material this is defined as phong,
  837|       |    // and otherwise lambert.
  838|       |    // More complex materials cause a bare-bones FbxSurfaceMaterial definition
  839|       |    // and are treated specially, as they're not really supported by FBX.
  840|       |    // TODO: support Maya's Stingray PBS material
  841|    208|    count = mScene->mNumMaterials;
  842|    208|    if (count) {
  ------------------
  |  Branch (842:9): [True: 174, False: 34]
  ------------------
  843|    174|        bool has_phong = has_phong_mat(mScene);
  844|    174|        n = FBX::Node("ObjectType", "Material");
  845|    174|        n.AddChild("Count", count);
  846|    174|        pt = FBX::Node("PropertyTemplate");
  847|    174|        if (has_phong) {
  ------------------
  |  Branch (847:13): [True: 57, False: 117]
  ------------------
  848|     57|            pt.AddProperty("FbxSurfacePhong");
  849|    117|        } else {
  850|    117|            pt.AddProperty("FbxSurfaceLambert");
  851|    117|        }
  852|    174|        p = FBX::Node("Properties70");
  853|    174|        if (has_phong) {
  ------------------
  |  Branch (853:13): [True: 57, False: 117]
  ------------------
  854|     57|            p.AddP70string("ShadingModel", "Phong");
  855|    117|        } else {
  856|    117|            p.AddP70string("ShadingModel", "Lambert");
  857|    117|        }
  858|    174|        p.AddP70bool("MultiLayer", false);
  859|    174|        p.AddP70colorA("EmissiveColor", 0.0, 0.0, 0.0);
  860|    174|        p.AddP70numberA("EmissiveFactor", 1.0);
  861|    174|        p.AddP70colorA("AmbientColor", 0.2, 0.2, 0.2);
  862|    174|        p.AddP70numberA("AmbientFactor", 1.0);
  863|    174|        p.AddP70colorA("DiffuseColor", 0.8, 0.8, 0.8);
  864|    174|        p.AddP70numberA("DiffuseFactor", 1.0);
  865|    174|        p.AddP70vector("Bump", 0.0, 0.0, 0.0);
  866|    174|        p.AddP70vector("NormalMap", 0.0, 0.0, 0.0);
  867|    174|        p.AddP70double("BumpFactor", 1.0);
  868|    174|        p.AddP70colorA("TransparentColor", 0.0, 0.0, 0.0);
  869|    174|        p.AddP70numberA("TransparencyFactor", 0.0);
  870|    174|        p.AddP70color("DisplacementColor", 0.0, 0.0, 0.0);
  871|    174|        p.AddP70double("DisplacementFactor", 1.0);
  872|    174|        p.AddP70color("VectorDisplacementColor", 0.0, 0.0, 0.0);
  873|    174|        p.AddP70double("VectorDisplacementFactor", 1.0);
  874|    174|        if (has_phong) {
  ------------------
  |  Branch (874:13): [True: 57, False: 117]
  ------------------
  875|     57|            p.AddP70colorA("SpecularColor", 0.2, 0.2, 0.2);
  876|     57|            p.AddP70numberA("SpecularFactor", 1.0);
  877|     57|            p.AddP70numberA("ShininessExponent", 20.0);
  878|     57|            p.AddP70colorA("ReflectionColor", 0.0, 0.0, 0.0);
  879|     57|            p.AddP70numberA("ReflectionFactor", 1.0);
  880|     57|        }
  881|    174|        pt.AddChild(p);
  882|    174|        n.AddChild(pt);
  883|    174|        object_nodes.push_back(n);
  884|    174|        total_count += count;
  885|    174|    }
  886|       |
  887|       |    // Video / FbxVideo
  888|       |    // one for each image file.
  889|    208|    count = int32_t(count_images(mScene));
  890|    208|    if (count) {
  ------------------
  |  Branch (890:9): [True: 48, False: 160]
  ------------------
  891|     48|        n = FBX::Node("ObjectType", "Video");
  892|     48|        n.AddChild("Count", count);
  893|     48|        pt = FBX::Node("PropertyTemplate", "FbxVideo");
  894|     48|        p = FBX::Node("Properties70");
  895|     48|        p.AddP70bool("ImageSequence", false);
  896|     48|        p.AddP70int("ImageSequenceOffset", 0);
  897|     48|        p.AddP70double("FrameRate", 0.0);
  898|     48|        p.AddP70int("LastFrame", 0);
  899|     48|        p.AddP70int("Width", 0);
  900|     48|        p.AddP70int("Height", 0);
  901|     48|        p.AddP70("Path", "KString", "XRefUrl", "", "");
  902|     48|        p.AddP70int("StartFrame", 0);
  903|     48|        p.AddP70int("StopFrame", 0);
  904|     48|        p.AddP70double("PlaySpeed", 0.0);
  905|     48|        p.AddP70time("Offset", 0);
  906|     48|        p.AddP70enum("InterlaceMode", 0);
  907|     48|        p.AddP70bool("FreeRunning", false);
  908|     48|        p.AddP70bool("Loop", false);
  909|     48|        p.AddP70enum("AccessMode", 0);
  910|     48|        pt.AddChild(p);
  911|     48|        n.AddChild(pt);
  912|     48|        object_nodes.push_back(n);
  913|     48|        total_count += count;
  914|     48|    }
  915|       |
  916|       |    // Texture / FbxFileTexture
  917|       |    // <~~ aiTexture
  918|    208|    count = int32_t(count_textures(mScene));
  919|    208|    if (count) {
  ------------------
  |  Branch (919:9): [True: 48, False: 160]
  ------------------
  920|     48|        n = FBX::Node("ObjectType", "Texture");
  921|     48|        n.AddChild("Count", count);
  922|     48|        pt = FBX::Node("PropertyTemplate", "FbxFileTexture");
  923|     48|        p = FBX::Node("Properties70");
  924|     48|        p.AddP70enum("TextureTypeUse", 0);
  925|     48|        p.AddP70numberA("Texture alpha", 1.0);
  926|     48|        p.AddP70enum("CurrentMappingType", 0);
  927|     48|        p.AddP70enum("WrapModeU", 0);
  928|     48|        p.AddP70enum("WrapModeV", 0);
  929|     48|        p.AddP70bool("UVSwap", false);
  930|     48|        p.AddP70bool("PremultiplyAlpha", true);
  931|     48|        p.AddP70vectorA("Translation", 0.0, 0.0, 0.0);
  932|     48|        p.AddP70vectorA("Rotation", 0.0, 0.0, 0.0);
  933|     48|        p.AddP70vectorA("Scaling", 1.0, 1.0, 1.0);
  934|     48|        p.AddP70vector("TextureRotationPivot", 0.0, 0.0, 0.0);
  935|     48|        p.AddP70vector("TextureScalingPivot", 0.0, 0.0, 0.0);
  936|     48|        p.AddP70enum("CurrentTextureBlendMode", 1);
  937|     48|        p.AddP70string("UVSet", "default");
  938|     48|        p.AddP70bool("UseMaterial", false);
  939|     48|        p.AddP70bool("UseMipMap", false);
  940|     48|        pt.AddChild(p);
  941|     48|        n.AddChild(pt);
  942|     48|        object_nodes.push_back(n);
  943|     48|        total_count += count;
  944|     48|    }
  945|       |
  946|       |    // AnimationCurveNode / FbxAnimCurveNode
  947|    208|    count = mScene->mNumAnimations * 3;
  948|    208|    if (count) {
  ------------------
  |  Branch (948:9): [True: 26, False: 182]
  ------------------
  949|     26|        n = FBX::Node("ObjectType", "AnimationCurveNode");
  950|     26|        n.AddChild("Count", count);
  951|     26|        pt = FBX::Node("PropertyTemplate", "FbxAnimCurveNode");
  952|     26|        p = FBX::Node("Properties70");
  953|     26|        p.AddP70("d", "Compound", "", "");
  954|     26|        pt.AddChild(p);
  955|     26|        n.AddChild(pt);
  956|     26|        object_nodes.push_back(n);
  957|     26|        total_count += count;
  958|     26|    }
  959|       |
  960|       |    // AnimationCurve / FbxAnimCurve
  961|    208|    count = mScene->mNumAnimations * 9;
  962|    208|    if (count) {
  ------------------
  |  Branch (962:9): [True: 26, False: 182]
  ------------------
  963|     26|        n = FBX::Node("ObjectType", "AnimationCurve");
  964|     26|        n.AddChild("Count", count);
  965|     26|        object_nodes.push_back(n);
  966|     26|        total_count += count;
  967|     26|    }
  968|       |
  969|       |    // Pose
  970|    208|    count = 0;
  971|  3.78k|    for (size_t i = 0; i < mScene->mNumMeshes; ++i) {
  ------------------
  |  Branch (971:24): [True: 3.57k, False: 208]
  ------------------
  972|  3.57k|        aiMesh* mesh = mScene->mMeshes[i];
  973|  3.57k|        if (mesh->HasBones()) { ++count; }
  ------------------
  |  Branch (973:13): [True: 27, False: 3.54k]
  ------------------
  974|  3.57k|    }
  975|    208|    if (count) {
  ------------------
  |  Branch (975:9): [True: 19, False: 189]
  ------------------
  976|     19|        n = FBX::Node("ObjectType", "Pose");
  977|     19|        n.AddChild("Count", count);
  978|     19|        object_nodes.push_back(n);
  979|     19|        total_count += count;
  980|     19|    }
  981|       |
  982|       |    // Deformer
  983|    208|    count = int32_t(count_deformers(mScene))+bsDeformerCount;
  984|    208|    if (count) {
  ------------------
  |  Branch (984:9): [True: 19, False: 189]
  ------------------
  985|     19|        n = FBX::Node("ObjectType", "Deformer");
  986|     19|        n.AddChild("Count", count);
  987|     19|        object_nodes.push_back(n);
  988|     19|        total_count += count;
  989|     19|    }
  990|       |
  991|       |    // (template)
  992|    208|    count = 0;
  993|    208|    if (count) {
  ------------------
  |  Branch (993:9): [True: 0, False: 208]
  ------------------
  994|      0|        n = FBX::Node("ObjectType", "");
  995|      0|        n.AddChild("Count", count);
  996|      0|        pt = FBX::Node("PropertyTemplate", "");
  997|      0|        p = FBX::Node("Properties70");
  998|      0|        pt.AddChild(p);
  999|      0|        n.AddChild(pt);
 1000|      0|        object_nodes.push_back(n);
 1001|      0|        total_count += count;
 1002|      0|    }
 1003|       |
 1004|       |    // now write it all
 1005|    208|    FBX::Node defs("Definitions");
 1006|    208|    defs.AddChild("Version", int32_t(100));
 1007|    208|    defs.AddChild("Count", int32_t(total_count));
 1008|  1.21k|    for (auto &on : object_nodes) {
  ------------------
  |  Branch (1008:19): [True: 1.21k, False: 208]
  ------------------
 1009|  1.21k|        defs.AddChild(on);
 1010|  1.21k|    }
 1011|    208|    defs.Dump(outfile, binary, 0);
 1012|    208|}
_Z19get_world_transformPK6aiNodePK7aiScene:
 1032|  4.32k|aiMatrix4x4 get_world_transform(const aiNode* node, const aiScene* scene) {
 1033|  4.32k|    std::vector<const aiNode*> node_chain;
 1034|  19.2k|    while (node != scene->mRootNode && node != nullptr) {
  ------------------
  |  Branch (1034:12): [True: 14.9k, False: 4.32k]
  |  Branch (1034:40): [True: 14.9k, False: 0]
  ------------------
 1035|  14.9k|        node_chain.push_back(node);
 1036|  14.9k|        node = node->mParent;
 1037|  14.9k|    }
 1038|  4.32k|    aiMatrix4x4 transform;
 1039|  19.2k|    for (auto n = node_chain.rbegin(); n != node_chain.rend(); ++n) {
  ------------------
  |  Branch (1039:40): [True: 14.9k, False: 4.32k]
  ------------------
 1040|  14.9k|        transform *= (*n)->mTransformation;
 1041|  14.9k|    }
 1042|  4.32k|    return transform;
 1043|  4.32k|}
_ZN6Assimp11FBXExporter12WriteObjectsEv:
 1086|    208|void FBXExporter::WriteObjects () {
 1087|    208|    if (!binary) {
  ------------------
  |  Branch (1087:9): [True: 0, False: 208]
  ------------------
 1088|      0|        WriteAsciiSectionHeader("Object properties");
 1089|      0|    }
 1090|       |    // numbers should match those given in definitions! make sure to check
 1091|    208|    StreamWriterLE outstream(outfile);
 1092|    208|    FBX::Node object_node("Objects");
 1093|    208|    int indent = 0;
 1094|    208|    object_node.Begin(outstream, binary, indent);
 1095|    208|    object_node.EndProperties(outstream, binary, indent);
 1096|    208|    object_node.BeginChildren(outstream, binary, indent);
 1097|       |
 1098|    208|    bool bJoinIdenticalVertices = mProperties->GetPropertyBool("bJoinIdenticalVertices", true);
 1099|       |    // save vertex_indices as it is needed later
 1100|    208|    std::vector<std::vector<int32_t>> vVertexIndice(mScene->mNumMeshes);
 1101|    208|    std::vector<uint32_t> uniq_v_before_mi;
 1102|       |
 1103|    208|    const auto bTransparencyFactorReferencedToOpacity = mProperties->GetPropertyBool(AI_CONFIG_EXPORT_FBX_TRANSPARENCY_FACTOR_REFER_TO_OPACITY, false);
 1104|       |
 1105|       |    // geometry (aiMesh)
 1106|    208|    mesh_uids.clear();
 1107|    208|    indent = 1;
 1108|    208|    std::function<void(const aiNode*)> visit_node_geo = [&](const aiNode *node) {
 1109|    208|        if (node->mNumMeshes == 0) {
 1110|    208|          for (uint32_t ni = 0; ni < node->mNumChildren; ni++) {
 1111|    208|            visit_node_geo(node->mChildren[ni]);
 1112|    208|          }
 1113|    208|          return;
 1114|    208|        }
 1115|       |
 1116|       |        // start the node record
 1117|    208|        FBX::Node n("Geometry");
 1118|    208|        int64_t uid = generate_uid();
 1119|    208|        mesh_uids[node] = uid;
 1120|    208|        n.AddProperty(uid);
 1121|    208|        n.AddProperty(FBX::SEPARATOR + "Geometry");
 1122|    208|        n.AddProperty("Mesh");
 1123|    208|        n.Begin(outstream, binary, indent);
 1124|    208|        n.DumpProperties(outstream, binary, indent);
 1125|    208|        n.EndProperties(outstream, binary, indent);
 1126|    208|        n.BeginChildren(outstream, binary, indent);
 1127|       |
 1128|       |        // output vertex data - each vertex should be unique (probably)
 1129|    208|        std::vector<double> flattened_vertices;
 1130|       |        // index of original vertex in vertex data vector
 1131|    208|        std::vector<int32_t> vertex_indices;
 1132|       |
 1133|    208|        std::vector<double> normal_data;
 1134|    208|        std::vector<double> color_data;
 1135|       |
 1136|    208|        std::vector<int32_t> polygon_data;
 1137|       |
 1138|    208|        std::vector<std::vector<double>> uv_data;
 1139|    208|        std::vector<std::vector<int32_t>> uv_indices;
 1140|       |
 1141|    208|        indent = 2;
 1142|       |
 1143|    208|        for (uint32_t n_mi = 0; n_mi < node->mNumMeshes; n_mi++) {
 1144|    208|          const auto mi = node->mMeshes[n_mi];
 1145|    208|          const aiMesh *m = mScene->mMeshes[mi];
 1146|       |
 1147|    208|          size_t v_offset = vertex_indices.size();
 1148|    208|          size_t uniq_v_before = flattened_vertices.size() / 3;
 1149|       |
 1150|       |          // map of vertex value to its index in the data vector
 1151|    208|          std::map<aiVector3D,size_t> index_by_vertex_value;
 1152|    208|          if (bJoinIdenticalVertices) {
 1153|    208|              int32_t index = 0;
 1154|    208|              for (size_t vi = 0; vi < m->mNumVertices; ++vi) {
 1155|    208|                  aiVector3D vtx = m->mVertices[vi];
 1156|    208|                  auto elem = index_by_vertex_value.find(vtx);
 1157|    208|                  if (elem == index_by_vertex_value.end()) {
 1158|    208|                      vertex_indices.push_back(index);
 1159|    208|                      index_by_vertex_value[vtx] = index;
 1160|    208|                      flattened_vertices.insert(flattened_vertices.end(), { vtx.x, vtx.y, vtx.z });
 1161|    208|                      ++index;
 1162|    208|                  } else {
 1163|    208|                      vertex_indices.push_back(int32_t(elem->second));
 1164|    208|                  }
 1165|    208|              }
 1166|    208|          } else { // do not join vertex, respect the export flag
 1167|    208|              vertex_indices.resize(v_offset + m->mNumVertices);
 1168|    208|              std::iota(vertex_indices.begin() + v_offset, vertex_indices.end(), 0);
 1169|    208|              for(unsigned int v = 0; v < m->mNumVertices; ++ v) {
 1170|    208|                  aiVector3D vtx = m->mVertices[v];
 1171|    208|                  flattened_vertices.insert(flattened_vertices.end(), {vtx.x, vtx.y, vtx.z});
 1172|    208|              }
 1173|    208|          }
 1174|    208|          vVertexIndice[mi].insert(
 1175|       |            // TODO test whether this can be end or not
 1176|    208|            vVertexIndice[mi].end(),
 1177|    208|            vertex_indices.begin() + v_offset,
 1178|    208|            vertex_indices.end()
 1179|    208|          );
 1180|       |
 1181|       |          // here could be edges but they're insane.
 1182|       |          // it's optional anyway, so let's ignore it.
 1183|       |
 1184|       |        // output polygon data as a flattened array of vertex indices.
 1185|       |        // the last vertex index of each polygon is negated and - 1
 1186|    208|          for (size_t fi = 0; fi < m->mNumFaces; fi++) {
 1187|    208|            const aiFace &f = m->mFaces[fi];
 1188|    208|            if (f.mNumIndices == 0) continue;
 1189|    208|            size_t pvi = 0;
 1190|    208|            for (; pvi < f.mNumIndices - 1; pvi++) {
 1191|    208|              polygon_data.push_back(
 1192|    208|                static_cast<int32_t>(uniq_v_before + vertex_indices[v_offset + f.mIndices[pvi]])
 1193|    208|              );
 1194|    208|            }
 1195|    208|            polygon_data.push_back(
 1196|    208|              static_cast<int32_t>(-1 ^ (uniq_v_before + vertex_indices[v_offset+f.mIndices[pvi]]))
 1197|    208|            );
 1198|    208|          }
 1199|       |
 1200|    208|          uniq_v_before_mi.push_back(static_cast<uint32_t>(uniq_v_before));
 1201|       |
 1202|    208|          if (m->HasNormals()) {
 1203|    208|            normal_data.reserve(3 * polygon_data.size());
 1204|    208|            for (size_t fi = 0; fi < m->mNumFaces; fi++) {
 1205|    208|              const aiFace & f = m->mFaces[fi];
 1206|    208|              for (size_t pvi = 0; pvi < f.mNumIndices; pvi++) {
 1207|    208|                const aiVector3D &curN = m->mNormals[f.mIndices[pvi]];
 1208|    208|                normal_data.insert(normal_data.end(), { curN.x, curN.y, curN.z });
 1209|    208|              }
 1210|    208|            }
 1211|    208|          }
 1212|       |
 1213|    208|          const int32_t colorChannelIndex = 0;
 1214|    208|          if (m->HasVertexColors(colorChannelIndex)) {
 1215|    208|            color_data.reserve(4 * polygon_data.size());
 1216|    208|            for (size_t fi = 0; fi < m->mNumFaces; fi++) {
 1217|    208|              const aiFace &f = m->mFaces[fi];
 1218|    208|              for (size_t pvi = 0; pvi < f.mNumIndices; pvi++) {
 1219|    208|                const aiColor4D &c = m->mColors[colorChannelIndex][f.mIndices[pvi]];
 1220|    208|                color_data.insert(color_data.end(), { c.r, c.g, c.b, c.a });
 1221|    208|              }
 1222|    208|            }
 1223|    208|          }
 1224|       |
 1225|    208|          const auto num_uv = static_cast<size_t>(m->GetNumUVChannels());
 1226|    208|          uv_indices.resize(std::max(num_uv, uv_indices.size()));
 1227|    208|          uv_data.resize(std::max(num_uv, uv_data.size()));
 1228|    208|          std::map<aiVector3D, int32_t> index_by_uv;
 1229|       |
 1230|       |          // uvs, if any
 1231|    208|          for (size_t uvi = 0; uvi < m->GetNumUVChannels(); uvi++) {
 1232|    208|            const auto nc = m->mNumUVComponents[uvi];
 1233|    208|            if (nc > 2) {
 1234|       |                // FBX only supports 2-channel UV maps...
 1235|       |                // or at least i'm not sure how to indicate a different number
 1236|    208|                std::stringstream err;
 1237|    208|                err << "Only 2-channel UV maps supported by FBX,";
 1238|    208|                err << " but mesh " << mi;
 1239|    208|                if (m->mName.length) {
 1240|    208|                    err << " (" << m->mName.C_Str() << ")";
 1241|    208|                }
 1242|    208|                err << " UV map " << uvi;
 1243|    208|                err << " has " << m->mNumUVComponents[uvi];
 1244|    208|                err << " components! Data will be preserved,";
 1245|    208|                err << " but may be incorrectly interpreted on load.";
 1246|    208|                ASSIMP_LOG_WARN(err.str());
 1247|    208|            }
 1248|       |
 1249|    208|            int32_t index = static_cast<int32_t>(uv_data[uvi].size()) / nc;
 1250|    208|            for (size_t fi = 0; fi < m->mNumFaces; fi++) {
 1251|    208|              const aiFace &f = m->mFaces[fi];
 1252|    208|              for (size_t pvi = 0; pvi < f.mNumIndices; pvi++) {
 1253|    208|                const aiVector3D &curUv = m->mTextureCoords[uvi][f.mIndices[pvi]];
 1254|    208|                auto elem = index_by_uv.find(curUv);
 1255|    208|                if (elem == index_by_uv.end()) {
 1256|    208|                  index_by_uv[curUv] = index;
 1257|    208|                  uv_indices[uvi].push_back(index);
 1258|    208|                  for (uint32_t x = 0; x < nc; ++x) {
 1259|    208|                    uv_data[uvi].push_back(curUv[x]);
 1260|    208|                  }
 1261|    208|                  ++index;
 1262|    208|                } else {
 1263|    208|                  uv_indices[uvi].push_back(elem->second);
 1264|    208|                }
 1265|    208|              }
 1266|    208|            }
 1267|    208|          }
 1268|    208|        }
 1269|       |
 1270|       |
 1271|    208|        FBX::Node::WritePropertyNode("Vertices", flattened_vertices, outstream, binary, indent);
 1272|    208|        FBX::Node::WritePropertyNode("PolygonVertexIndex", polygon_data, outstream, binary, indent);
 1273|    208|        FBX::Node::WritePropertyNode("GeometryVersion", int32_t(124), outstream, binary, indent);
 1274|       |
 1275|    208|	if (!normal_data.empty()) {
 1276|    208|	    FBX::Node normals("LayerElementNormal", int32_t(0));
 1277|    208|	    normals.Begin(outstream, binary, indent);
 1278|    208|	    normals.DumpProperties(outstream, binary, indent);
 1279|    208|	    normals.EndProperties(outstream, binary, indent);
 1280|    208|	    normals.BeginChildren(outstream, binary, indent);
 1281|    208|	    indent = 3;
 1282|    208|	    FBX::Node::WritePropertyNode("Version", int32_t(101), outstream, binary, indent);
 1283|    208|	    FBX::Node::WritePropertyNode("Name", "", outstream, binary, indent);
 1284|    208|	    FBX::Node::WritePropertyNode("MappingInformationType", "ByPolygonVertex", outstream, binary, indent);
 1285|    208|	    FBX::Node::WritePropertyNode("ReferenceInformationType", "Direct", outstream, binary, indent);
 1286|    208|	    FBX::Node::WritePropertyNode("Normals", normal_data, outstream, binary, indent);
 1287|       |	    // note: version 102 has a NormalsW also... not sure what it is,
 1288|       |	    // so stick with version 101 for now.
 1289|    208|	    indent = 2;
 1290|    208|	    normals.End(outstream, binary, indent, true);
 1291|    208|        }
 1292|       |
 1293|    208|	if (!color_data.empty()) {
 1294|    208|	    const auto colorChannelIndex = 0;
 1295|    208|	    FBX::Node vertexcolors("LayerElementColor", int32_t(colorChannelIndex));
 1296|    208|	    vertexcolors.Begin(outstream, binary, indent);
 1297|    208|	    vertexcolors.DumpProperties(outstream, binary, indent);
 1298|    208|	    vertexcolors.EndProperties(outstream, binary, indent);
 1299|    208|	    vertexcolors.BeginChildren(outstream, binary, indent);
 1300|    208|	    indent = 3;
 1301|    208|	    FBX::Node::WritePropertyNode("Version", int32_t(101), outstream, binary, indent);
 1302|    208|	    char layerName[8];
 1303|    208|	    snprintf(layerName, sizeof(layerName), "COLOR_%d", colorChannelIndex);
 1304|    208|	    FBX::Node::WritePropertyNode("Name", (const char *)layerName, outstream, binary, indent);
 1305|    208|	    FBX::Node::WritePropertyNode("MappingInformationType", "ByPolygonVertex", outstream, binary, indent);
 1306|    208|	    FBX::Node::WritePropertyNode("ReferenceInformationType", "Direct", outstream, binary, indent);
 1307|    208|	    FBX::Node::WritePropertyNode("Colors", color_data, outstream, binary, indent);
 1308|    208|	    indent = 2;
 1309|    208|	    vertexcolors.End(outstream, binary, indent, true);
 1310|    208|        }
 1311|       |
 1312|    208|        for (uint32_t uvi = 0; uvi < uv_data.size(); uvi++) {
 1313|    208|          FBX::Node uv("LayerElementUV", int32_t(uvi));
 1314|    208|          uv.Begin(outstream, binary, indent);
 1315|    208|          uv.DumpProperties(outstream, binary, indent);
 1316|    208|          uv.EndProperties(outstream, binary, indent);
 1317|    208|          uv.BeginChildren(outstream, binary, indent);
 1318|    208|          indent = 3;
 1319|    208|          FBX::Node::WritePropertyNode("Version", int32_t(101), outstream, binary, indent);
 1320|    208|          FBX::Node::WritePropertyNode("Name", "", outstream, binary, indent);
 1321|    208|          FBX::Node::WritePropertyNode("MappingInformationType", "ByPolygonVertex", outstream, binary, indent);
 1322|    208|          FBX::Node::WritePropertyNode("ReferenceInformationType", "IndexToDirect", outstream, binary, indent);
 1323|    208|          FBX::Node::WritePropertyNode("UV", uv_data[uvi], outstream, binary, indent);
 1324|    208|          FBX::Node::WritePropertyNode("UVIndex", uv_indices[uvi], outstream, binary, indent);
 1325|    208|          indent = 2;
 1326|    208|          uv.End(outstream, binary, indent, true);
 1327|    208|        }
 1328|       |
 1329|       |
 1330|       |        // When merging multiple meshes, we instead use by polygon so the correct material is
 1331|       |        // assigned to each face. Previously, this LayerElementMaterial always had 0 since it
 1332|       |        // assumed there was 1 material for each node for all meshes.
 1333|    208|        FBX::Node mat("LayerElementMaterial", int32_t(0));
 1334|    208|        mat.AddChild("Version", int32_t(101));
 1335|    208|        mat.AddChild("Name", "");
 1336|    208|        if (node->mNumMeshes == 1) {
 1337|    208|          mat.AddChild("MappingInformationType", "AllSame");
 1338|    208|          mat.AddChild("ReferenceInformationType", "IndexToDirect");
 1339|    208|          std::vector<int32_t> mat_indices = {0};
 1340|    208|          mat.AddChild("Materials", mat_indices);
 1341|    208|        } else {
 1342|    208|          mat.AddChild("MappingInformationType", "ByPolygon");
 1343|    208|          mat.AddChild("ReferenceInformationType", "IndexToDirect");
 1344|    208|          std::vector<int32_t> mat_indices;
 1345|    208|          for (uint32_t n_mi = 0; n_mi < node->mNumMeshes; n_mi++) {
 1346|    208|            const auto mi = node->mMeshes[n_mi];
 1347|    208|            const auto *const m = mScene->mMeshes[mi];
 1348|    208|            for (size_t fi = 0; fi < m->mNumFaces; fi++) {
 1349|    208|              mat_indices.push_back(n_mi);
 1350|    208|            }
 1351|    208|          }
 1352|    208|          mat.AddChild("Materials", mat_indices);
 1353|    208|        }
 1354|    208|        mat.Dump(outstream, binary, indent);
 1355|       |
 1356|       |        // finally we have the layer specifications,
 1357|       |        // which select the normals / UV set / etc to use.
 1358|       |        // TODO: handle multiple uv sets correctly?
 1359|    208|        FBX::Node layer("Layer", int32_t(0));
 1360|    208|        layer.AddChild("Version", int32_t(100));
 1361|    208|        FBX::Node le;
 1362|       |
 1363|    208|		if (!normal_data.empty()) {
 1364|    208|		  le = FBX::Node("LayerElement");
 1365|    208|		  le.AddChild("Type", "LayerElementNormal");
 1366|    208|		  le.AddChild("TypedIndex", int32_t(0));
 1367|    208|		  layer.AddChild(le);
 1368|    208|        }
 1369|       |
 1370|    208|		if (!color_data.empty()) {
 1371|    208|		  le = FBX::Node("LayerElement");
 1372|    208|		  le.AddChild("Type", "LayerElementColor");
 1373|    208|		  le.AddChild("TypedIndex", int32_t(0));
 1374|    208|		  layer.AddChild(le);
 1375|    208|        }
 1376|       |
 1377|    208|        le = FBX::Node("LayerElement");
 1378|    208|        le.AddChild("Type", "LayerElementMaterial");
 1379|    208|        le.AddChild("TypedIndex", int32_t(0));
 1380|    208|        layer.AddChild(le);
 1381|    208|        le = FBX::Node("LayerElement");
 1382|    208|        le.AddChild("Type", "LayerElementUV");
 1383|    208|        le.AddChild("TypedIndex", int32_t(0));
 1384|    208|        layer.AddChild(le);
 1385|    208|        layer.Dump(outstream, binary, indent);
 1386|       |
 1387|    208|        for(unsigned int lr = 1; lr < uv_data.size(); ++ lr) {
 1388|    208|            FBX::Node layerExtra("Layer", int32_t(lr));
 1389|    208|            layerExtra.AddChild("Version", int32_t(100));
 1390|    208|            FBX::Node leExtra("LayerElement");
 1391|    208|            leExtra.AddChild("Type", "LayerElementUV");
 1392|    208|            leExtra.AddChild("TypedIndex", int32_t(lr));
 1393|    208|            layerExtra.AddChild(leExtra);
 1394|    208|            layerExtra.Dump(outstream, binary, indent);
 1395|    208|        }
 1396|       |        // finish the node record
 1397|    208|        indent = 1;
 1398|    208|        n.End(outstream, binary, indent, true);
 1399|       |
 1400|    208|        for (uint32_t ni = 0; ni < node->mNumChildren; ni++) {
 1401|    208|          visit_node_geo(node->mChildren[ni]);
 1402|    208|        }
 1403|    208|        return;
 1404|    208|    };
 1405|       |
 1406|    208|    visit_node_geo(mScene->mRootNode);
 1407|       |
 1408|       |
 1409|       |    // aiMaterial
 1410|    208|    material_uids.clear();
 1411|    454|    for (size_t i = 0; i < mScene->mNumMaterials; ++i) {
  ------------------
  |  Branch (1411:24): [True: 246, False: 208]
  ------------------
 1412|       |        // it's all about this material
 1413|    246|        aiMaterial* m = mScene->mMaterials[i];
 1414|       |
 1415|       |        // these are used to receive material data
 1416|    246|        ai_real f; aiColor3D c;
 1417|       |
 1418|       |        // start the node record
 1419|    246|        FBX::Node n("Material");
 1420|       |
 1421|    246|        int64_t uid = generate_uid();
 1422|    246|        material_uids.push_back(uid);
 1423|    246|        n.AddProperty(uid);
 1424|       |
 1425|    246|        aiString name;
 1426|    246|        m->Get(AI_MATKEY_NAME, name);
 1427|    246|        n.AddProperty(name.C_Str() + FBX::SEPARATOR + "Material");
 1428|       |
 1429|    246|        n.AddProperty("");
 1430|       |
 1431|    246|        n.AddChild("Version", int32_t(102));
 1432|    246|        f = 0;
 1433|    246|        m->Get(AI_MATKEY_SHININESS, f);
 1434|    246|        bool phong = (f > 0);
 1435|    246|        if (phong) {
  ------------------
  |  Branch (1435:13): [True: 92, False: 154]
  ------------------
 1436|     92|            n.AddChild("ShadingModel", "phong");
 1437|    154|        } else {
 1438|    154|            n.AddChild("ShadingModel", "lambert");
 1439|    154|        }
 1440|    246|        n.AddChild("MultiLayer", int32_t(0));
 1441|       |
 1442|    246|        FBX::Node p("Properties70");
 1443|       |
 1444|       |        // materials exported using the FBX SDK have two sets of fields.
 1445|       |        // there are the properties specified in the PropertyTemplate,
 1446|       |        // which are those supported by the modernFBX SDK,
 1447|       |        // and an extra set of properties with simpler names.
 1448|       |        // The extra properties are a legacy material system from pre-2009.
 1449|       |        //
 1450|       |        // In the modern system, each property has "color" and "factor".
 1451|       |        // Generally the interpretation of these seems to be
 1452|       |        // that the colour is multiplied by the factor before use,
 1453|       |        // but this is not always clear-cut.
 1454|       |        //
 1455|       |        // Usually assimp only stores the colour,
 1456|       |        // so we can just leave the factors at the default "1.0".
 1457|       |
 1458|       |        // first we can export the "standard" properties
 1459|    246|        if (m->Get(AI_MATKEY_COLOR_AMBIENT, c) == aiReturn_SUCCESS) {
  ------------------
  |  Branch (1459:13): [True: 204, False: 42]
  ------------------
 1460|    204|            p.AddP70colorA("AmbientColor", c.r, c.g, c.b);
 1461|       |            //p.AddP70numberA("AmbientFactor", 1.0);
 1462|    204|        }
 1463|    246|        if (m->Get(AI_MATKEY_COLOR_DIFFUSE, c) == aiReturn_SUCCESS) {
  ------------------
  |  Branch (1463:13): [True: 232, False: 14]
  ------------------
 1464|    232|            p.AddP70colorA("DiffuseColor", c.r, c.g, c.b);
 1465|       |            //p.AddP70numberA("DiffuseFactor", 1.0);
 1466|    232|        }
 1467|    246|        if (m->Get(AI_MATKEY_COLOR_TRANSPARENT, c) == aiReturn_SUCCESS) {
  ------------------
  |  Branch (1467:13): [True: 54, False: 192]
  ------------------
 1468|       |            // "TransparentColor" / "TransparencyFactor"...
 1469|       |            // thanks FBX, for your insightful interpretation of consistency
 1470|     54|            p.AddP70colorA("TransparentColor", c.r, c.g, c.b);
 1471|       |
 1472|     54|            if (!bTransparencyFactorReferencedToOpacity) {
  ------------------
  |  Branch (1472:17): [True: 54, False: 0]
  ------------------
 1473|       |                // TransparencyFactor defaults to 0.0, so set it to 1.0.
 1474|       |                // note: Maya always sets this to 1.0,
 1475|       |                // so we can't use it sensibly as "Opacity".
 1476|       |                // In stead we rely on the legacy "Opacity" value, below.
 1477|       |                // Blender also relies on "Opacity" not "TransparencyFactor",
 1478|       |                // probably for a similar reason.
 1479|     54|                p.AddP70numberA("TransparencyFactor", 1.0);
 1480|     54|            }
 1481|     54|        }
 1482|    246|        if (bTransparencyFactorReferencedToOpacity) {
  ------------------
  |  Branch (1482:13): [True: 0, False: 246]
  ------------------
 1483|      0|            if (m->Get(AI_MATKEY_OPACITY, f) == aiReturn_SUCCESS) {
  ------------------
  |  Branch (1483:17): [True: 0, False: 0]
  ------------------
 1484|      0|                p.AddP70numberA("TransparencyFactor", 1.0 - f);
 1485|      0|            }
 1486|      0|        }
 1487|    246|        if (m->Get(AI_MATKEY_COLOR_REFLECTIVE, c) == aiReturn_SUCCESS) {
  ------------------
  |  Branch (1487:13): [True: 54, False: 192]
  ------------------
 1488|     54|            p.AddP70colorA("ReflectionColor", c.r, c.g, c.b);
 1489|     54|        }
 1490|    246|        if (m->Get(AI_MATKEY_REFLECTIVITY, f) == aiReturn_SUCCESS) {
  ------------------
  |  Branch (1490:13): [True: 24, False: 222]
  ------------------
 1491|     24|            p.AddP70numberA("ReflectionFactor", f);
 1492|     24|        }
 1493|    246|        if (phong) {
  ------------------
  |  Branch (1493:13): [True: 92, False: 154]
  ------------------
 1494|     92|            if (m->Get(AI_MATKEY_COLOR_SPECULAR, c) == aiReturn_SUCCESS) {
  ------------------
  |  Branch (1494:17): [True: 92, False: 0]
  ------------------
 1495|     92|                p.AddP70colorA("SpecularColor", c.r, c.g, c.b);
 1496|     92|            }
 1497|     92|            if (m->Get(AI_MATKEY_SHININESS_STRENGTH, f) == aiReturn_SUCCESS) {
  ------------------
  |  Branch (1497:17): [True: 7, False: 85]
  ------------------
 1498|      7|                p.AddP70numberA("ShininessFactor", f);
 1499|      7|            }
 1500|     92|            if (m->Get(AI_MATKEY_SHININESS, f) == aiReturn_SUCCESS) {
  ------------------
  |  Branch (1500:17): [True: 92, False: 0]
  ------------------
 1501|     92|                p.AddP70numberA("ShininessExponent", f);
 1502|     92|            }
 1503|     92|            if (m->Get(AI_MATKEY_REFLECTIVITY, f) == aiReturn_SUCCESS) {
  ------------------
  |  Branch (1503:17): [True: 24, False: 68]
  ------------------
 1504|     24|                p.AddP70numberA("ReflectionFactor", f);
 1505|     24|            }
 1506|     92|        }
 1507|       |
 1508|       |        // Now the legacy system.
 1509|       |        // For safety let's include it.
 1510|       |        // thrse values don't exist in the property template,
 1511|       |        // and usually are completely ignored when loading.
 1512|       |        // One notable exception is the "Opacity" property,
 1513|       |        // which Blender uses as (1.0 - alpha).
 1514|    246|        c.r = 0.0f; c.g = 0.0f; c.b = 0.0f;
 1515|    246|        m->Get(AI_MATKEY_COLOR_EMISSIVE, c);
 1516|    246|        p.AddP70vector("Emissive", c.r, c.g, c.b);
 1517|    246|        c.r = 0.2f; c.g = 0.2f; c.b = 0.2f;
 1518|    246|        m->Get(AI_MATKEY_COLOR_AMBIENT, c);
 1519|    246|        p.AddP70vector("Ambient", c.r, c.g, c.b);
 1520|    246|        c.r = 0.8f; c.g = 0.8f; c.b = 0.8f;
 1521|    246|        m->Get(AI_MATKEY_COLOR_DIFFUSE, c);
 1522|    246|        p.AddP70vector("Diffuse", c.r, c.g, c.b);
 1523|       |        // The FBX SDK determines "Opacity" from transparency colour (RGB)
 1524|       |        // and factor (F) as: O = (1.0 - F * ((R + G + B) / 3)).
 1525|       |        // However we actually have an opacity value,
 1526|       |        // so we should take it from AI_MATKEY_OPACITY if possible.
 1527|       |        // It might make more sense to use TransparencyFactor,
 1528|       |        // but Blender actually loads "Opacity" correctly, so let's use it.
 1529|    246|        f = 1.0f;
 1530|    246|        if (m->Get(AI_MATKEY_COLOR_TRANSPARENT, c) == aiReturn_SUCCESS) {
  ------------------
  |  Branch (1530:13): [True: 54, False: 192]
  ------------------
 1531|     54|            f = 1.0f - ((c.r + c.g + c.b) / 3.0f);
 1532|     54|        }
 1533|    246|        m->Get(AI_MATKEY_OPACITY, f);
 1534|    246|        p.AddP70double("Opacity", f);
 1535|    246|        if (phong) {
  ------------------
  |  Branch (1535:13): [True: 92, False: 154]
  ------------------
 1536|       |            // specular color is multiplied by shininess_strength
 1537|     92|            c.r = 0.2f; c.g = 0.2f; c.b = 0.2f;
 1538|     92|            m->Get(AI_MATKEY_COLOR_SPECULAR, c);
 1539|     92|            f = 1.0f;
 1540|     92|            m->Get(AI_MATKEY_SHININESS_STRENGTH, f);
 1541|     92|            p.AddP70vector("Specular", f*c.r, f*c.g, f*c.b);
 1542|     92|            f = 20.0f;
 1543|     92|            m->Get(AI_MATKEY_SHININESS, f);
 1544|     92|            p.AddP70double("Shininess", f);
 1545|       |            // Legacy "Reflectivity" is F*F*((R+G+B)/3),
 1546|       |            // where F is the proportion of light reflected (AKA reflectivity),
 1547|       |            // and RGB is the reflective colour of the material.
 1548|       |            // No idea why, but we might as well set it the same way.
 1549|     92|            f = 0.0f;
 1550|     92|            m->Get(AI_MATKEY_REFLECTIVITY, f);
 1551|     92|            c.r = 1.0f, c.g = 1.0f, c.b = 1.0f;
 1552|     92|            m->Get(AI_MATKEY_COLOR_REFLECTIVE, c);
 1553|     92|            p.AddP70double("Reflectivity", f*f*((c.r+c.g+c.b)/3.0));
 1554|     92|        }
 1555|       |
 1556|    246|        n.AddChild(p);
 1557|       |
 1558|    246|        n.Dump(outstream, binary, indent);
 1559|    246|    }
 1560|       |
 1561|       |    // we need to look up all the images we're using,
 1562|       |    // so we can generate uids, and eliminate duplicates.
 1563|    208|    std::map<std::string, int64_t> uid_by_image;
 1564|    454|    for (size_t i = 0; i < mScene->mNumMaterials; ++i) {
  ------------------
  |  Branch (1564:24): [True: 246, False: 208]
  ------------------
 1565|    246|        aiString texpath;
 1566|    246|        aiMaterial* mat = mScene->mMaterials[i];
 1567|    246|        for (
 1568|    246|            size_t tt = aiTextureType_DIFFUSE;
 1569|  4.42k|            tt < aiTextureType_UNKNOWN;
  ------------------
  |  Branch (1569:13): [True: 4.18k, False: 246]
  ------------------
 1570|  4.18k|            ++tt
 1571|  4.18k|        ){
 1572|  4.18k|            const aiTextureType textype = static_cast<aiTextureType>(tt);
 1573|  4.18k|            const size_t texcount = mat->GetTextureCount(textype);
 1574|  4.29k|            for (size_t j = 0; j < texcount; ++j) {
  ------------------
  |  Branch (1574:32): [True: 116, False: 4.18k]
  ------------------
 1575|    116|                mat->GetTexture(textype, (unsigned int)j, &texpath);
 1576|    116|                const std::string texstring = texpath.C_Str();
 1577|    116|                auto elem = uid_by_image.find(texstring);
 1578|    116|                if (elem == uid_by_image.end()) {
  ------------------
  |  Branch (1578:21): [True: 92, False: 24]
  ------------------
 1579|     92|                    uid_by_image[texstring] = generate_uid();
 1580|     92|                }
 1581|    116|            }
 1582|  4.18k|        }
 1583|    246|    }
 1584|       |
 1585|    208|    std::map<std::string, std::string> tpath_by_image;
 1586|       |    // FbxVideo - stores images used by textures.
 1587|    208|    for (const auto &it : uid_by_image) {
  ------------------
  |  Branch (1587:25): [True: 92, False: 208]
  ------------------
 1588|     92|        FBX::Node n("Video");
 1589|     92|        const int64_t& uid = it.second;
 1590|     92|        const std::string name = ""; // TODO: ... name???
 1591|     92|        n.AddProperties(uid, name + FBX::SEPARATOR + "Video", "Clip");
 1592|     92|        n.AddChild("Type", "Clip");
 1593|     92|        FBX::Node p("Properties70");
 1594|       |        // TODO: get full path... relative path... etc... ugh...
 1595|       |        // for now just use the same path for everything,
 1596|       |        // and hopefully one of them will work out.
 1597|     92|        std::string path = it.first;
 1598|       |        // try get embedded texture
 1599|     92|        const aiTexture* embedded_texture = mScene->GetEmbeddedTexture(it.first.c_str());
 1600|     92|        if (embedded_texture != nullptr) {
  ------------------
  |  Branch (1600:13): [True: 7, False: 85]
  ------------------
 1601|       |            // change the path (use original filename, if available. If name is empty, concatenate texture index with file extension)
 1602|      7|            std::stringstream newPath;
 1603|      7|            if (embedded_texture->mFilename.length > 0) {
  ------------------
  |  Branch (1603:17): [True: 6, False: 1]
  ------------------
 1604|      6|                newPath << embedded_texture->mFilename.C_Str();
 1605|       |                // If newPath doesn't end in an extension, add extension from embedded_texture->achFormatHint
 1606|      6|                std::string np = newPath.str();
 1607|      6|                size_t dot_pos = np.find_last_of('.');
 1608|      6|                if (dot_pos == std::string::npos || dot_pos < np.find_last_of("/\\")) {
  ------------------
  |  Branch (1608:21): [True: 1, False: 5]
  |  Branch (1608:53): [True: 3, False: 2]
  ------------------
 1609|       |                    // No extension found, add one
 1610|      4|                    newPath << "." << embedded_texture->achFormatHint;
 1611|      4|                }
 1612|      6|            } else if (embedded_texture->achFormatHint[0]) {
  ------------------
  |  Branch (1612:24): [True: 1, False: 0]
  ------------------
 1613|      1|                int texture_index = std::stoi(path.substr(1, path.size() - 1));
 1614|      1|                newPath << texture_index << "." << embedded_texture->achFormatHint;
 1615|      1|            }
 1616|      7|            auto elem = tpath_by_image.find(path);
 1617|      7|            if (elem == tpath_by_image.end()) {
  ------------------
  |  Branch (1617:17): [True: 7, False: 0]
  ------------------
 1618|      7|                tpath_by_image[path] = newPath.str();
 1619|      7|            }
 1620|      7|            path = newPath.str();
 1621|       |            // embed the texture
 1622|      7|            size_t texture_size = static_cast<size_t>(embedded_texture->mWidth * std::max(embedded_texture->mHeight, 1u));
 1623|      7|            if (binary) {
  ------------------
  |  Branch (1623:17): [True: 7, False: 0]
  ------------------
 1624|       |                // embed texture as binary data
 1625|      7|                std::vector<uint8_t> tex_data;
 1626|      7|                tex_data.resize(texture_size);
 1627|      7|                memcpy(&tex_data[0], (char*)embedded_texture->pcData, texture_size);
 1628|      7|                n.AddChild("Content", tex_data);
 1629|      7|            } else {
 1630|       |                // embed texture in base64 encoding
 1631|      0|                std::string encoded_texture = FBX::Util::EncodeBase64((char*)embedded_texture->pcData, texture_size);
 1632|      0|                n.AddChild("Content", encoded_texture);
 1633|      0|            }
 1634|      7|        }
 1635|     92|        p.AddP70("Path", "KString", "XRefUrl", "", path);
 1636|     92|        n.AddChild(p);
 1637|     92|        n.AddChild("UseMipMap", int32_t(0));
 1638|     92|        n.AddChild("Filename", path);
 1639|     92|        n.AddChild("RelativeFilename", path);
 1640|     92|        n.Dump(outstream, binary, indent);
 1641|     92|    }
 1642|       |
 1643|       |    // Textures
 1644|       |    // referenced by material_index/texture_type pairs.
 1645|    208|    std::map<std::pair<size_t,size_t>,int64_t> texture_uids;
 1646|    208|    const std::map<aiTextureType,std::string> prop_name_by_tt = {
 1647|    208|        {aiTextureType_DIFFUSE,      "DiffuseColor"},
 1648|    208|        {aiTextureType_SPECULAR,     "SpecularColor"},
 1649|    208|        {aiTextureType_AMBIENT,      "AmbientColor"},
 1650|    208|        {aiTextureType_EMISSIVE,     "EmissiveColor"},
 1651|    208|        {aiTextureType_HEIGHT,       "Bump"},
 1652|    208|        {aiTextureType_NORMALS,      "NormalMap"},
 1653|    208|        {aiTextureType_SHININESS,    "ShininessExponent"},
 1654|    208|        {aiTextureType_OPACITY,      "TransparentColor"},
 1655|    208|        {aiTextureType_DISPLACEMENT, "DisplacementColor"},
 1656|       |        //{aiTextureType_LIGHTMAP, "???"},
 1657|    208|        {aiTextureType_REFLECTION,   "ReflectionColor"}
 1658|       |        //{aiTextureType_UNKNOWN, ""}
 1659|    208|    };
 1660|    454|    for (size_t i = 0; i < mScene->mNumMaterials; ++i) {
  ------------------
  |  Branch (1660:24): [True: 246, False: 208]
  ------------------
 1661|       |        // textures are attached to materials
 1662|    246|        aiMaterial* mat = mScene->mMaterials[i];
 1663|    246|        int64_t material_uid = material_uids[i];
 1664|       |
 1665|    246|        for (
 1666|    246|            size_t j = aiTextureType_DIFFUSE;
 1667|  4.42k|            j < aiTextureType_UNKNOWN;
  ------------------
  |  Branch (1667:13): [True: 4.18k, False: 246]
  ------------------
 1668|  4.18k|            ++j
 1669|  4.18k|        ) {
 1670|  4.18k|            const aiTextureType tt = static_cast<aiTextureType>(j);
 1671|  4.18k|            size_t n = mat->GetTextureCount(tt);
 1672|       |
 1673|  4.18k|            if (n < 1) { // no texture of this type
  ------------------
  |  Branch (1673:17): [True: 4.07k, False: 105]
  ------------------
 1674|  4.07k|                continue;
 1675|  4.07k|            }
 1676|       |
 1677|    105|            if (n > 1) {
  ------------------
  |  Branch (1677:17): [True: 3, False: 102]
  ------------------
 1678|       |                // TODO: multilayer textures
 1679|      3|                std::stringstream err;
 1680|      3|                err << "Multilayer textures not supported (for now),";
 1681|      3|                err << " skipping texture type " << j;
 1682|      3|                err << " of material " << i;
 1683|      3|                ASSIMP_LOG_WARN(err.str());
 1684|      3|            }
 1685|       |
 1686|       |            // get image path for this (single-image) texture
 1687|    105|            aiString tpath;
 1688|    105|            if (mat->GetTexture(tt, 0, &tpath) != aiReturn_SUCCESS) {
  ------------------
  |  Branch (1688:17): [True: 0, False: 105]
  ------------------
 1689|      0|                std::stringstream err;
 1690|      0|                err << "Failed to get texture 0 for texture of type " << tt;
 1691|      0|                err << " on material " << i;
 1692|      0|                err << ", however GetTextureCount returned 1.";
 1693|      0|                throw DeadlyExportError(err.str());
 1694|      0|            }
 1695|    105|            const std::string texture_path(tpath.C_Str());
 1696|       |
 1697|       |            // get connected image uid
 1698|    105|            auto elem = uid_by_image.find(texture_path);
 1699|    105|            if (elem == uid_by_image.end()) {
  ------------------
  |  Branch (1699:17): [True: 0, False: 105]
  ------------------
 1700|       |                // this should never happen
 1701|      0|                std::stringstream err;
 1702|      0|                err << "Failed to find video element for texture with path";
 1703|      0|                err << " \"" << texture_path << "\"";
 1704|      0|                err << ", type " << j << ", material " << i;
 1705|      0|                throw DeadlyExportError(err.str());
 1706|      0|            }
 1707|    105|            const int64_t image_uid = elem->second;
 1708|       |
 1709|       |            // get the name of the material property to connect to
 1710|    105|            auto elem2 = prop_name_by_tt.find(tt);
 1711|    105|            if (elem2 == prop_name_by_tt.end()) {
  ------------------
  |  Branch (1711:17): [True: 7, False: 98]
  ------------------
 1712|       |                // don't know how to handle this type of texture,
 1713|       |                // so skip it.
 1714|      7|                std::stringstream err;
 1715|      7|                err << "Not sure how to handle texture of type " << j;
 1716|      7|                err << " on material " << i;
 1717|      7|                err << ", skipping...";
 1718|      7|                ASSIMP_LOG_WARN(err.str());
 1719|      7|                continue;
 1720|      7|            }
 1721|     98|            const std::string& prop_name = elem2->second;
 1722|       |
 1723|       |            // generate a uid for this texture
 1724|     98|            const int64_t texture_uid = generate_uid();
 1725|       |
 1726|       |            // link the texture to the material
 1727|     98|            connections.emplace_back(
 1728|     98|                "C", "OP", texture_uid, material_uid, prop_name
 1729|     98|            );
 1730|       |
 1731|       |            // link the image data to the texture
 1732|     98|            connections.emplace_back("C", "OO", image_uid, texture_uid);
 1733|       |
 1734|     98|            aiUVTransform trafo;
 1735|     98|            unsigned int max = sizeof(aiUVTransform);
 1736|     98|            aiGetMaterialFloatArray(mat, AI_MATKEY_UVTRANSFORM(aiTextureType_DIFFUSE, 0), (ai_real *)&trafo, &max);
 1737|       |
 1738|     98|            auto tp_elem = tpath_by_image.find(texture_path);
 1739|     98|            std::string tfile_path = texture_path;
 1740|     98|            if (tp_elem != tpath_by_image.end()) {
  ------------------
  |  Branch (1740:17): [True: 7, False: 91]
  ------------------
 1741|      7|                tfile_path = tp_elem->second;
 1742|     91|            } else {
 1743|     91|                std::stringstream err;
 1744|     91|                err << "Texture path not found for texure " << texture_path;
 1745|     91|                err << " on material " << i;
 1746|     91|                ASSIMP_LOG_WARN(err.str());
 1747|     91|            }
 1748|       |
 1749|       |            // now write the actual texture node
 1750|     98|            FBX::Node tnode("Texture");
 1751|       |            // TODO: some way to determine texture name?
 1752|     98|            const std::string texture_name = "" + FBX::SEPARATOR + "Texture";
 1753|     98|            tnode.AddProperties(texture_uid, texture_name, "");
 1754|       |            // there really doesn't seem to be a better type than this:
 1755|     98|            tnode.AddChild("Type", "TextureVideoClip");
 1756|     98|            tnode.AddChild("Version", int32_t(202));
 1757|     98|            tnode.AddChild("TextureName", texture_name);
 1758|     98|            FBX::Node p("Properties70");
 1759|     98|            p.AddP70vectorA("Translation", trafo.mTranslation[0], trafo.mTranslation[1], 0.0);
 1760|     98|            p.AddP70vectorA("Rotation", 0, 0, trafo.mRotation);
 1761|     98|            p.AddP70vectorA("Scaling", trafo.mScaling[0], trafo.mScaling[1], 0.0);
 1762|     98|            p.AddP70enum("CurrentTextureBlendMode", 0); // TODO: verify
 1763|       |            //p.AddP70string("UVSet", ""); // TODO: how should this work?
 1764|     98|            p.AddP70bool("UseMaterial", true);
 1765|     98|            tnode.AddChild(p);
 1766|       |            // can't easily determine which texture path will be correct,
 1767|       |            // so just store what we have in every field.
 1768|       |            // these being incorrect is a common problem with FBX anyway.
 1769|     98|            tnode.AddChild("FileName", tfile_path);
 1770|     98|            tnode.AddChild("RelativeFilename", tfile_path);
 1771|     98|            tnode.AddChild("ModelUVTranslation", double(0.0), double(0.0));
 1772|     98|            tnode.AddChild("ModelUVScaling", double(1.0), double(1.0));
 1773|     98|            tnode.AddChild("Texture_Alpha_Source", "None");
 1774|     98|            tnode.AddChild(
 1775|     98|                "Cropping", int32_t(0), int32_t(0), int32_t(0), int32_t(0)
 1776|     98|            );
 1777|     98|            tnode.Dump(outstream, binary, indent);
 1778|     98|        }
 1779|    246|    }
 1780|       |
 1781|       |    // Blendshapes, if any
 1782|  3.78k|    for (size_t mi = 0; mi < mScene->mNumMeshes; ++mi) {
  ------------------
  |  Branch (1782:25): [True: 3.57k, False: 208]
  ------------------
 1783|  3.57k|      const aiMesh* m = mScene->mMeshes[mi];
 1784|  3.57k|      if (m->mNumAnimMeshes == 0) {
  ------------------
  |  Branch (1784:11): [True: 3.57k, False: 0]
  ------------------
 1785|  3.57k|        continue;
 1786|  3.57k|      }
 1787|       |      // make a deformer for this mesh
 1788|      0|      int64_t deformer_uid = generate_uid();
 1789|      0|      FBX::Node dnode("Deformer");
 1790|      0|      dnode.AddProperties(deformer_uid, m->mName.data + FBX::SEPARATOR + "Blendshapes", "BlendShape");
 1791|      0|      dnode.AddChild("Version", int32_t(101));
 1792|      0|      dnode.Dump(outstream, binary, indent);
 1793|       |      // connect it
 1794|      0|      const auto node = get_node_for_mesh((unsigned int)mi, mScene->mRootNode);
 1795|      0|      connections.emplace_back("C", "OO", deformer_uid, mesh_uids[node]);
 1796|      0|      std::vector<int32_t> vertex_indices = vVertexIndice[mi];
 1797|       |
 1798|      0|      for (unsigned int am = 0; am < m->mNumAnimMeshes; ++am) {
  ------------------
  |  Branch (1798:33): [True: 0, False: 0]
  ------------------
 1799|      0|        aiAnimMesh *pAnimMesh = m->mAnimMeshes[am];
 1800|      0|        std::string blendshape_name = pAnimMesh->mName.data;
 1801|       |
 1802|       |        // start the node record
 1803|      0|        FBX::Node bsnode("Geometry");
 1804|      0|        int64_t blendshape_uid = generate_uid();
 1805|      0|        blendshape_uids.push_back(blendshape_uid);
 1806|      0|        bsnode.AddProperty(blendshape_uid);
 1807|      0|        bsnode.AddProperty(blendshape_name + FBX::SEPARATOR + "Geometry");
 1808|      0|        bsnode.AddProperty("Shape");
 1809|      0|        bsnode.AddChild("Version", int32_t(100));
 1810|      0|        bsnode.Begin(outstream, binary, indent);
 1811|      0|        bsnode.DumpProperties(outstream, binary, indent);
 1812|      0|        bsnode.EndProperties(outstream, binary, indent);
 1813|      0|        bsnode.BeginChildren(outstream, binary, indent);
 1814|      0|        indent++;
 1815|      0|        if (pAnimMesh->HasPositions()) {
  ------------------
  |  Branch (1815:13): [True: 0, False: 0]
  ------------------
 1816|      0|          std::vector<int32_t>shape_indices;
 1817|      0|          std::vector<float>pPositionDiff;
 1818|      0|          std::vector<float>pNormalDiff;
 1819|       |
 1820|      0|          for (unsigned int vt = 0; vt < vertex_indices.size(); ++vt) {
  ------------------
  |  Branch (1820:37): [True: 0, False: 0]
  ------------------
 1821|      0|              aiVector3D pDiff = (pAnimMesh->mVertices[vertex_indices[vt]] - m->mVertices[vertex_indices[vt]]);
 1822|      0|              shape_indices.push_back(vertex_indices[vt]);
 1823|      0|              pPositionDiff.push_back(pDiff[0]);
 1824|      0|              pPositionDiff.push_back(pDiff[1]);
 1825|      0|              pPositionDiff.push_back(pDiff[2]);
 1826|       |
 1827|      0|              if (pAnimMesh->HasNormals()) {
  ------------------
  |  Branch (1827:19): [True: 0, False: 0]
  ------------------
 1828|      0|                  aiVector3D nDiff = (pAnimMesh->mNormals[vertex_indices[vt]] - m->mNormals[vertex_indices[vt]]);
 1829|      0|                  pNormalDiff.push_back(nDiff[0]);
 1830|      0|                  pNormalDiff.push_back(nDiff[1]);
 1831|      0|                  pNormalDiff.push_back(nDiff[2]);
 1832|      0|              } else {
 1833|      0|                  pNormalDiff.push_back(0.0);
 1834|      0|                  pNormalDiff.push_back(0.0);
 1835|      0|                  pNormalDiff.push_back(0.0);
 1836|      0|              }
 1837|      0|          }
 1838|       |
 1839|      0|          FBX::Node::WritePropertyNode(
 1840|      0|              "Indexes", shape_indices, outstream, binary, indent
 1841|      0|          );
 1842|       |
 1843|      0|          FBX::Node::WritePropertyNode(
 1844|      0|              "Vertices", pPositionDiff, outstream, binary, indent
 1845|      0|          );
 1846|       |
 1847|      0|          if (pNormalDiff.size()>0) {
  ------------------
  |  Branch (1847:15): [True: 0, False: 0]
  ------------------
 1848|      0|            FBX::Node::WritePropertyNode(
 1849|      0|                "Normals", pNormalDiff, outstream, binary, indent
 1850|      0|            );
 1851|      0|          }
 1852|      0|        }
 1853|      0|        indent--;
 1854|      0|        bsnode.End(outstream, binary, indent, true);
 1855|       |
 1856|       |        // Add blendshape Channel Deformer
 1857|      0|        FBX::Node sdnode("Deformer");
 1858|      0|        const int64_t blendchannel_uid = generate_uid();
 1859|      0|        sdnode.AddProperties(
 1860|      0|            blendchannel_uid, blendshape_name + FBX::SEPARATOR + "SubDeformer", "BlendShapeChannel"
 1861|      0|        );
 1862|      0|        sdnode.AddChild("Version", int32_t(100));
 1863|      0|        sdnode.AddChild("DeformPercent", float(0.0));
 1864|      0|        FBX::Node p("Properties70");
 1865|      0|        p.AddP70numberA("DeformPercent", 0.0);
 1866|      0|        sdnode.AddChild(p);
 1867|       |        // TODO: Normally just one weight per channel, adding stub for later development
 1868|      0|        std::vector<double>fFullWeights;
 1869|      0|        fFullWeights.push_back(100.);
 1870|      0|        sdnode.AddChild("FullWeights", fFullWeights);
 1871|      0|        sdnode.Dump(outstream, binary, indent);
 1872|       |
 1873|      0|        connections.emplace_back("C", "OO", blendchannel_uid, deformer_uid);
 1874|      0|        connections.emplace_back("C", "OO", blendshape_uid, blendchannel_uid);
 1875|      0|      }
 1876|      0|    }
 1877|       |
 1878|       |    // bones.
 1879|       |    //
 1880|       |    // output structure:
 1881|       |    // subset of node hierarchy that are "skeleton",
 1882|       |    // i.e. do not have meshes but only bones.
 1883|       |    // but.. i'm not sure how anyone could guarantee that...
 1884|       |    //
 1885|       |    // input...
 1886|       |    // well, for each mesh it has "bones",
 1887|       |    // and the bone names correspond to nodes.
 1888|       |    // of course we also need the parent nodes,
 1889|       |    // as they give some of the transform........
 1890|       |    //
 1891|       |    // well. we can assume a sane input, i suppose.
 1892|       |    //
 1893|       |    // so input is the bone node hierarchy,
 1894|       |    // with an extra thing for the transformation of the MESH in BONE space.
 1895|       |    //
 1896|       |    // output is a set of bone nodes,
 1897|       |    // a "bindpose" which indicates the default local transform of all bones,
 1898|       |    // and a set of "deformers".
 1899|       |    // each deformer is parented to a mesh geometry,
 1900|       |    // and has one or more "subdeformer"s as children.
 1901|       |    // each subdeformer has one bone node as a child,
 1902|       |    // and represents the influence of that bone on the grandparent mesh.
 1903|       |    // the subdeformer has a list of indices, and weights,
 1904|       |    // with indices specifying vertex indices,
 1905|       |    // and weights specifying the corresponding influence of this bone.
 1906|       |    // it also has Transform and TransformLink elements,
 1907|       |    // specifying the transform of the MESH in BONE space,
 1908|       |    // and the transformation of the BONE in WORLD space,
 1909|       |    // likely in the bindpose.
 1910|       |    //
 1911|       |    // the input bone structure is different but similar,
 1912|       |    // storing the number of weights for this bone,
 1913|       |    // and an array of (vertex index, weight) pairs.
 1914|       |    //
 1915|       |    // one sticky point is that the number of vertices may not match,
 1916|       |    // because assimp splits vertices by normal, uv, etc.
 1917|       |
 1918|       |
 1919|       |    // first we should mark the skeleton for each mesh.
 1920|       |    // the skeleton must include not only the aiBones,
 1921|       |    // but also all their parent nodes.
 1922|       |    // anything that affects the position of any bone node must be included.
 1923|       |
 1924|       |    // note that we want to preserve input order as much as possible here.
 1925|       |    // previously, sorting by name lead to consistent output across systems, but was not
 1926|       |    // suitable for downstream consumption by some applications.
 1927|    208|    std::vector<std::vector<const aiNode*>> skeleton_by_mesh(mScene->mNumMeshes);
 1928|       |    // at the same time we can build a list of all the skeleton nodes,
 1929|       |    // which will be used later to mark them as type "limbNode".
 1930|    208|    std::unordered_set<const aiNode*> limbnodes;
 1931|       |
 1932|       |    //actual bone nodes in fbx, without parenting-up
 1933|    208|    std::vector<std::string> allBoneNames;
 1934|  3.78k|    for(unsigned int m = 0; m < mScene->mNumMeshes; ++ m) {
  ------------------
  |  Branch (1934:29): [True: 3.57k, False: 208]
  ------------------
 1935|  3.57k|        aiMesh* pMesh = mScene->mMeshes[m];
 1936|  6.66k|        for(unsigned int b = 0; b < pMesh->mNumBones; ++ b)
  ------------------
  |  Branch (1936:33): [True: 3.08k, False: 3.57k]
  ------------------
 1937|  3.08k|            allBoneNames.push_back(pMesh->mBones[b]->mName.data);
 1938|  3.57k|    }
 1939|    208|    aiMatrix4x4 mxTransIdentity;
 1940|       |
 1941|       |    // and a map of nodes by bone name, as finding them is annoying.
 1942|    208|    std::map<std::string,aiNode*> node_by_bone;
 1943|  3.77k|    for (size_t mi = 0; mi < mScene->mNumMeshes; ++mi) {
  ------------------
  |  Branch (1943:25): [True: 3.57k, False: 207]
  ------------------
 1944|  3.57k|        const aiMesh* m = mScene->mMeshes[mi];
 1945|  3.57k|        std::vector<const aiNode*> skeleton;
 1946|  6.65k|        for (size_t bi =0; bi < m->mNumBones; ++bi) {
  ------------------
  |  Branch (1946:28): [True: 3.08k, False: 3.57k]
  ------------------
 1947|  3.08k|            const aiBone* b = m->mBones[bi];
 1948|  3.08k|            const std::string name(b->mName.C_Str());
 1949|  3.08k|            auto elem = node_by_bone.find(name);
 1950|  3.08k|            aiNode* n;
 1951|  3.08k|            if (elem != node_by_bone.end()) {
  ------------------
  |  Branch (1951:17): [True: 0, False: 3.08k]
  ------------------
 1952|      0|                n = elem->second;
 1953|  3.08k|            } else {
 1954|  3.08k|                n = mScene->mRootNode->FindNode(b->mName);
 1955|  3.08k|                if (!n) {
  ------------------
  |  Branch (1955:21): [True: 1, False: 3.08k]
  ------------------
 1956|       |                    // this should never happen
 1957|      1|                    std::stringstream err;
 1958|      1|                    err << "Failed to find node for bone: \"" << name << "\"";
 1959|      1|                    throw DeadlyExportError(err.str());
 1960|      1|                }
 1961|  3.08k|                node_by_bone[name] = n;
 1962|  3.08k|                limbnodes.insert(n);
 1963|  3.08k|            }
 1964|  3.08k|            skeleton.push_back(n);
 1965|       |            // mark all parent nodes as skeleton as well,
 1966|       |            // up until we find the root node,
 1967|       |            // or else the node containing the mesh,
 1968|       |            // or else the parent of a node containing the mesh.
 1969|  3.08k|            for (
 1970|  3.08k|                const aiNode* parent = n->mParent;
 1971|  6.45k|                parent && parent != mScene->mRootNode;
  ------------------
  |  Branch (1971:17): [True: 6.44k, False: 6]
  |  Branch (1971:27): [True: 3.46k, False: 2.98k]
  ------------------
 1972|  3.36k|                parent = parent->mParent
 1973|  3.46k|            ) {
 1974|       |                // if we've already done this node we can skip it all
 1975|  3.46k|                if (std::find(skeleton.begin(), skeleton.end(), parent) != skeleton.end()) {
  ------------------
  |  Branch (1975:21): [True: 96, False: 3.36k]
  ------------------
 1976|     96|                    break;
 1977|     96|                }
 1978|       |                // ignore fbx transform nodes as these will be collapsed later
 1979|       |                // TODO: cache this by aiNode*
 1980|  3.36k|                const std::string node_name(parent->mName.C_Str());
 1981|  3.36k|                if (node_name.find(MAGIC_NODE_TAG) != std::string::npos) {
  ------------------
  |  Branch (1981:21): [True: 0, False: 3.36k]
  ------------------
 1982|      0|                    continue;
 1983|      0|                }
 1984|       |                //not a bone in scene && no effect in transform
 1985|  3.36k|                if (std::find(allBoneNames.begin(), allBoneNames.end(), node_name) == allBoneNames.end()
  ------------------
  |  Branch (1985:21): [True: 2.93k, False: 430]
  |  Branch (1985:21): [True: 2.63k, False: 727]
  ------------------
 1986|  2.93k|                   && parent->mTransformation == mxTransIdentity) {
  ------------------
  |  Branch (1986:23): [True: 2.63k, False: 297]
  ------------------
 1987|  2.63k|                        continue;
 1988|  2.63k|                }
 1989|       |                // otherwise check if this is the root of the skeleton
 1990|    727|                bool end = false;
 1991|       |                // is the mesh part of this node?
 1992|    727|                for (size_t i = 0; i < parent->mNumMeshes && !end; ++i) {
  ------------------
  |  Branch (1992:36): [True: 0, False: 727]
  |  Branch (1992:62): [True: 0, False: 0]
  ------------------
 1993|      0|                    end |= parent->mMeshes[i] == mi;
 1994|      0|                }
 1995|       |                // is the mesh in one of the children of this node?
 1996|  1.87k|                for (size_t j = 0; j < parent->mNumChildren && !end; ++j) {
  ------------------
  |  Branch (1996:36): [True: 1.14k, False: 727]
  |  Branch (1996:64): [True: 1.14k, False: 0]
  ------------------
 1997|  1.14k|                    aiNode* child = parent->mChildren[j];
 1998|  1.14k|                    for (size_t i = 0; i < child->mNumMeshes && !end; ++i) {
  ------------------
  |  Branch (1998:40): [True: 0, False: 1.14k]
  |  Branch (1998:65): [True: 0, False: 0]
  ------------------
 1999|      0|                        end |= child->mMeshes[i] == mi;
 2000|      0|                    }
 2001|  1.14k|                }
 2002|       |
 2003|       |                // if it was the skeleton root we can finish here
 2004|    727|                if (end) { break; }
  ------------------
  |  Branch (2004:21): [True: 0, False: 727]
  ------------------
 2005|    727|            }
 2006|  3.08k|        }
 2007|  3.57k|        skeleton_by_mesh[mi] = skeleton;
 2008|  3.57k|    }
 2009|       |
 2010|       |    // we'll need the uids for the bone nodes, so generate them now
 2011|  3.77k|    for (size_t i = 0; i < mScene->mNumMeshes; ++i) {
  ------------------
  |  Branch (2011:24): [True: 3.57k, False: 207]
  ------------------
 2012|  3.57k|        auto &s = skeleton_by_mesh[i];
 2013|  3.57k|        for (const aiNode* n : s) {
  ------------------
  |  Branch (2013:30): [True: 3.08k, False: 3.57k]
  ------------------
 2014|  3.08k|            if (node_uids.find(n) == node_uids.end()) {
  ------------------
  |  Branch (2014:17): [True: 3.08k, False: 0]
  ------------------
 2015|  3.08k|                node_uids[n] = generate_uid();
 2016|  3.08k|            }
 2017|  3.08k|        }
 2018|  3.57k|    }
 2019|       |
 2020|       |    // now, for each aiMesh, we need to export a deformer,
 2021|       |    // and for each aiBone a subdeformer,
 2022|       |    // which should have all the skinning info.
 2023|       |    // these will need to be connected properly to the mesh,
 2024|       |    // and we can do that all now.
 2025|  3.77k|    for (size_t mi = 0; mi < mScene->mNumMeshes; ++mi) {
  ------------------
  |  Branch (2025:25): [True: 3.57k, False: 207]
  ------------------
 2026|  3.57k|        const aiMesh* m = mScene->mMeshes[mi];
 2027|  3.57k|        if (!m->HasBones()) {
  ------------------
  |  Branch (2027:13): [True: 3.54k, False: 26]
  ------------------
 2028|  3.54k|            continue;
 2029|  3.54k|        }
 2030|       |
 2031|     26|        const aiNode *mesh_node = get_node_for_mesh((uint32_t)mi, mScene->mRootNode);
 2032|       |        // make a deformer for this mesh
 2033|     26|        int64_t deformer_uid = generate_uid();
 2034|     26|        FBX::Node dnode("Deformer");
 2035|     26|        dnode.AddProperties(deformer_uid, FBX::SEPARATOR + "Deformer", "Skin");
 2036|     26|        dnode.AddChild("Version", int32_t(101));
 2037|       |        // "acuracy"... this is not a typo....
 2038|     26|        dnode.AddChild("Link_DeformAcuracy", double(50));
 2039|     26|        dnode.AddChild("SkinningType", "Linear"); // TODO: other modes?
 2040|     26|        dnode.Dump(outstream, binary, indent);
 2041|       |
 2042|       |        // connect it
 2043|     26|        connections.emplace_back("C", "OO", deformer_uid, mesh_uids[mesh_node]);
 2044|       |
 2045|       |        // TODO, FIXME: this won't work if anything is not in the bind pose.
 2046|       |        // for now if such a situation is detected, we throw an exception.
 2047|     26|        std::set<const aiBone*> not_in_bind_pose;
 2048|     26|        std::set<const aiNode*> no_offset_matrix;
 2049|       |
 2050|       |        // first get this mesh's position in world space,
 2051|       |        // as we'll need it for each subdeformer.
 2052|       |        //
 2053|       |        // ...of course taking the position of the MESH doesn't make sense,
 2054|       |        // as it can be instanced to many nodes.
 2055|       |        // All we can do is assume no instancing,
 2056|       |        // and take the first node we find that contains the mesh.
 2057|     26|        aiMatrix4x4 mesh_xform = get_world_transform(mesh_node, mScene);
 2058|       |
 2059|       |        // now make a subdeformer for each bone in the skeleton
 2060|     26|        const auto & skeleton= skeleton_by_mesh[mi];
 2061|  3.08k|        for (const aiNode* bone_node : skeleton) {
  ------------------
  |  Branch (2061:38): [True: 3.08k, False: 26]
  ------------------
 2062|       |            // if there's a bone for this node, find it
 2063|  3.08k|            const aiBone* b = nullptr;
 2064|   970k|            for (size_t bi = 0; bi < m->mNumBones; ++bi) {
  ------------------
  |  Branch (2064:33): [True: 970k, False: 0]
  ------------------
 2065|       |                // TODO: this probably should index by something else
 2066|   970k|                const std::string name(m->mBones[bi]->mName.C_Str());
 2067|   970k|                if (node_by_bone[name] == bone_node) {
  ------------------
  |  Branch (2067:21): [True: 3.08k, False: 967k]
  ------------------
 2068|  3.08k|                    b = m->mBones[bi];
 2069|  3.08k|                    break;
 2070|  3.08k|                }
 2071|   970k|            }
 2072|  3.08k|            if (!b) {
  ------------------
  |  Branch (2072:17): [True: 0, False: 3.08k]
  ------------------
 2073|      0|                no_offset_matrix.insert(bone_node);
 2074|      0|            }
 2075|       |
 2076|       |            // start the subdeformer node
 2077|  3.08k|            const int64_t subdeformer_uid = generate_uid();
 2078|  3.08k|            FBX::Node sdnode("Deformer");
 2079|  3.08k|            sdnode.AddProperties(
 2080|  3.08k|                subdeformer_uid, FBX::SEPARATOR + "SubDeformer", "Cluster"
 2081|  3.08k|            );
 2082|  3.08k|            sdnode.AddChild("Version", int32_t(100));
 2083|  3.08k|            sdnode.AddChild("UserData", "", "");
 2084|       |
 2085|       |            // add indices and weights, if any
 2086|  3.08k|            if (b) {
  ------------------
  |  Branch (2086:17): [True: 3.08k, False: 0]
  ------------------
 2087|  3.08k|                std::set<int32_t> setWeightedVertex;
 2088|  3.08k|                std::vector<int32_t> subdef_indices;
 2089|  3.08k|                std::vector<double> subdef_weights;
 2090|  3.08k|                int32_t last_index = -1;
 2091|  42.8k|                for (size_t wi = 0; wi < b->mNumWeights; ++wi) {
  ------------------
  |  Branch (2091:37): [True: 39.8k, False: 3.08k]
  ------------------
 2092|  39.8k|                    if (b->mWeights[wi].mVertexId >= vVertexIndice[mi].size()) {
  ------------------
  |  Branch (2092:25): [True: 23.1k, False: 16.6k]
  ------------------
 2093|  23.1k|                  			ASSIMP_LOG_ERROR("UNREAL: Skipping vertex index to prevent buffer overflow.");
 2094|  23.1k|                        continue;
 2095|  23.1k|                    }
 2096|  16.6k|                    int32_t vi = vVertexIndice[mi][b->mWeights[wi].mVertexId]
 2097|  16.6k|                      + uniq_v_before_mi[mi];
 2098|  16.6k|                    bool bIsWeightedAlready = (setWeightedVertex.find(vi) != setWeightedVertex.end());
 2099|  16.6k|                    if (vi == last_index || bIsWeightedAlready) {
  ------------------
  |  Branch (2099:25): [True: 0, False: 16.6k]
  |  Branch (2099:45): [True: 0, False: 16.6k]
  ------------------
 2100|       |                        // only for vertices we exported to fbx
 2101|       |                        // TODO, FIXME: this assumes identically-located vertices
 2102|       |                        // will always deform in the same way.
 2103|       |                        // as assimp doesn't store a separate list of "positions",
 2104|       |                        // there's not much that can be done about this
 2105|       |                        // other than assuming that identical position means
 2106|       |                        // identical vertex.
 2107|      0|                        continue;
 2108|      0|                    }
 2109|  16.6k|                    setWeightedVertex.insert(vi);
 2110|  16.6k|                    subdef_indices.push_back(vi);
 2111|  16.6k|                    subdef_weights.push_back(b->mWeights[wi].mWeight);
 2112|  16.6k|                    last_index = vi;
 2113|  16.6k|                }
 2114|       |                // yes, "indexes"
 2115|  3.08k|                sdnode.AddChild("Indexes", subdef_indices);
 2116|  3.08k|                sdnode.AddChild("Weights", subdef_weights);
 2117|  3.08k|            }
 2118|       |
 2119|       |            // transform is the transform of the mesh, but in bone space.
 2120|       |            // if the skeleton is in the bind pose,
 2121|       |            // we can take the inverse of the world-space bone transform
 2122|       |            // and multiply by the world-space transform of the mesh.
 2123|  3.08k|            aiMatrix4x4 bone_xform = get_world_transform(bone_node, mScene);
 2124|  3.08k|            aiMatrix4x4 inverse_bone_xform = bone_xform;
 2125|  3.08k|            inverse_bone_xform.Inverse();
 2126|  3.08k|            aiMatrix4x4 tr = inverse_bone_xform * mesh_xform;
 2127|       |
 2128|  3.08k|            sdnode.AddChild("Transform", tr);
 2129|       |
 2130|       |
 2131|  3.08k|            sdnode.AddChild("TransformLink", bone_xform);
 2132|       |            // note: this means we ALWAYS rely on the mesh node transform
 2133|       |            // being unchanged from the time the skeleton was bound.
 2134|       |            // there's not really any way around this at the moment.
 2135|       |
 2136|       |            // done
 2137|  3.08k|            sdnode.Dump(outstream, binary, indent);
 2138|       |
 2139|       |            // lastly, connect to the parent deformer
 2140|  3.08k|            connections.emplace_back(
 2141|  3.08k|                "C", "OO", subdeformer_uid, deformer_uid
 2142|  3.08k|            );
 2143|       |
 2144|       |            // we also need to connect the limb node to the subdeformer.
 2145|  3.08k|            connections.emplace_back(
 2146|  3.08k|                "C", "OO", node_uids[bone_node], subdeformer_uid
 2147|  3.08k|            );
 2148|  3.08k|        }
 2149|       |
 2150|       |        // if we cannot create a valid FBX file, simply die.
 2151|       |        // this will both prevent unnecessary bug reports,
 2152|       |        // and tell the user what they can do to fix the situation
 2153|       |        // (i.e. export their model in the bind pose).
 2154|     26|        if (no_offset_matrix.size() && not_in_bind_pose.size()) {
  ------------------
  |  Branch (2154:13): [True: 0, False: 26]
  |  Branch (2154:40): [True: 0, False: 0]
  ------------------
 2155|      0|            std::stringstream err;
 2156|      0|            err << "Not enough information to construct bind pose";
 2157|      0|            err << " for mesh " << mi << "!";
 2158|      0|            err << " Transform matrix for bone \"";
 2159|      0|            err << (*not_in_bind_pose.begin())->mName.C_Str() << "\"";
 2160|      0|            if (not_in_bind_pose.size() > 1) {
  ------------------
  |  Branch (2160:17): [True: 0, False: 0]
  ------------------
 2161|      0|                err << " (and " << not_in_bind_pose.size() - 1 << " more)";
 2162|      0|            }
 2163|      0|            err << " does not match mOffsetMatrix,";
 2164|      0|            err << " and node \"";
 2165|      0|            err << (*no_offset_matrix.begin())->mName.C_Str() << "\"";
 2166|      0|            if (no_offset_matrix.size() > 1) {
  ------------------
  |  Branch (2166:17): [True: 0, False: 0]
  ------------------
 2167|      0|                err << " (and " << no_offset_matrix.size() - 1 << " more)";
 2168|      0|            }
 2169|      0|            err << " has no offset matrix to rely on.";
 2170|      0|            err << " Please ensure bones are in the bind pose to export.";
 2171|      0|            throw DeadlyExportError(err.str());
 2172|      0|        }
 2173|       |
 2174|     26|    }
 2175|       |
 2176|       |    // BindPose
 2177|       |    //
 2178|       |    // This is a legacy system, which should be unnecessary.
 2179|       |    //
 2180|       |    // Somehow including it slows file loading by the official FBX SDK,
 2181|       |    // and as it can reconstruct it from the deformers anyway,
 2182|       |    // this is not currently included.
 2183|       |    //
 2184|       |    // The code is kept here in case it's useful in the future,
 2185|       |    // but it's pretty much a hack anyway,
 2186|       |    // as assimp doesn't store bindpose information for full skeletons.
 2187|       |    //
 2188|       |    /*for (size_t mi = 0; mi < mScene->mNumMeshes; ++mi) {
 2189|       |        aiMesh* mesh = mScene->mMeshes[mi];
 2190|       |        if (! mesh->HasBones()) { continue; }
 2191|       |        int64_t bindpose_uid = generate_uid();
 2192|       |        FBX::Node bpnode("Pose");
 2193|       |        bpnode.AddProperty(bindpose_uid);
 2194|       |        // note: this uid is never linked or connected to anything.
 2195|       |        bpnode.AddProperty(FBX::SEPARATOR + "Pose"); // blank name
 2196|       |        bpnode.AddProperty("BindPose");
 2197|       |
 2198|       |        bpnode.AddChild("Type", "BindPose");
 2199|       |        bpnode.AddChild("Version", int32_t(100));
 2200|       |
 2201|       |        aiNode* mesh_node = get_node_for_mesh(mi, mScene->mRootNode);
 2202|       |
 2203|       |        // next get the whole skeleton for this mesh.
 2204|       |        // we need it all to define the bindpose section.
 2205|       |        // the FBX SDK will complain if it's missing,
 2206|       |        // and also if parents of used bones don't have a subdeformer.
 2207|       |        // order shouldn't matter.
 2208|       |        std::set<aiNode*> skeleton;
 2209|       |        for (size_t bi = 0; bi < mesh->mNumBones; ++bi) {
 2210|       |            // bone node should have already been indexed
 2211|       |            const aiBone* b = mesh->mBones[bi];
 2212|       |            const std::string bone_name(b->mName.C_Str());
 2213|       |            aiNode* parent = node_by_bone[bone_name];
 2214|       |            // insert all nodes down to the root or mesh node
 2215|       |            while (
 2216|       |                parent
 2217|       |                && parent != mScene->mRootNode
 2218|       |                && parent != mesh_node
 2219|       |            ) {
 2220|       |                skeleton.insert(parent);
 2221|       |                parent = parent->mParent;
 2222|       |            }
 2223|       |        }
 2224|       |
 2225|       |        // number of pose nodes. includes one for the mesh itself.
 2226|       |        bpnode.AddChild("NbPoseNodes", int32_t(1 + skeleton.size()));
 2227|       |
 2228|       |        // the first pose node is always the mesh itself
 2229|       |        FBX::Node pose("PoseNode");
 2230|       |        pose.AddChild("Node", mesh_uids[mi]);
 2231|       |        aiMatrix4x4 mesh_node_xform = get_world_transform(mesh_node, mScene);
 2232|       |        pose.AddChild("Matrix", mesh_node_xform);
 2233|       |        bpnode.AddChild(pose);
 2234|       |
 2235|       |        for (aiNode* bonenode : skeleton) {
 2236|       |            // does this node have a uid yet?
 2237|       |            int64_t node_uid;
 2238|       |            auto node_uid_iter = node_uids.find(bonenode);
 2239|       |            if (node_uid_iter != node_uids.end()) {
 2240|       |                node_uid = node_uid_iter->second;
 2241|       |            } else {
 2242|       |                node_uid = generate_uid();
 2243|       |                node_uids[bonenode] = node_uid;
 2244|       |            }
 2245|       |
 2246|       |            // make a pose thingy
 2247|       |            pose = FBX::Node("PoseNode");
 2248|       |            pose.AddChild("Node", node_uid);
 2249|       |            aiMatrix4x4 node_xform = get_world_transform(bonenode, mScene);
 2250|       |            pose.AddChild("Matrix", node_xform);
 2251|       |            bpnode.AddChild(pose);
 2252|       |        }
 2253|       |
 2254|       |        // now write it
 2255|       |        bpnode.Dump(outstream, binary, indent);
 2256|       |    }*/
 2257|       |
 2258|       |    // lights
 2259|    207|    indent = 1;
 2260|    207|    lights_uids.clear();
 2261|    264|    for (size_t li = 0; li < mScene->mNumLights; ++li) {
  ------------------
  |  Branch (2261:25): [True: 57, False: 207]
  ------------------
 2262|     57|        aiLight* l = mScene->mLights[li];
 2263|       |
 2264|     57|        int64_t uid = generate_uid();
 2265|     57|        const std::string lightNodeAttributeName = l->mName.C_Str() + FBX::SEPARATOR + "NodeAttribute";
 2266|       |
 2267|     57|        FBX::Node lna("NodeAttribute");
 2268|     57|        lna.AddProperties(uid, lightNodeAttributeName, "Light");
 2269|     57|        FBX::Node lnap("Properties70");
 2270|       |
 2271|       |        // Light color.
 2272|     57|        lnap.AddP70colorA("Color", l->mColorDiffuse.r, l->mColorDiffuse.g, l->mColorDiffuse.b);
 2273|       |
 2274|       |        // TODO Assimp light description is quite concise and do not handle light intensity.
 2275|       |        // Default value to 1000W.
 2276|     57|        lnap.AddP70numberA("Intensity", 1000);
 2277|       |
 2278|       |        // FBXLight::EType conversion
 2279|     57|        switch (l->mType) {
 2280|     45|        case aiLightSource_POINT:
  ------------------
  |  Branch (2280:9): [True: 45, False: 12]
  ------------------
 2281|     45|            lnap.AddP70enum("LightType", 0);
 2282|     45|            break;
 2283|      7|        case aiLightSource_DIRECTIONAL:
  ------------------
  |  Branch (2283:9): [True: 7, False: 50]
  ------------------
 2284|      7|            lnap.AddP70enum("LightType", 1);
 2285|      7|            break;
 2286|      2|        case aiLightSource_SPOT:
  ------------------
  |  Branch (2286:9): [True: 2, False: 55]
  ------------------
 2287|      2|            lnap.AddP70enum("LightType", 2);
 2288|      2|            lnap.AddP70numberA("InnerAngle", AI_RAD_TO_DEG(l->mAngleInnerCone));
 2289|      2|            lnap.AddP70numberA("OuterAngle", AI_RAD_TO_DEG(l->mAngleOuterCone));
 2290|      2|            break;
 2291|       |        // TODO Assimp do not handle 'area' nor 'volume' lights, but FBX does.
 2292|       |        /*case aiLightSource_AREA:
 2293|       |            lnap.AddP70enum("LightType", 3);
 2294|       |            lnap.AddP70enum("AreaLightShape", 0); // 0=Rectangle, 1=Sphere
 2295|       |            break;
 2296|       |        case aiLightSource_VOLUME:
 2297|       |            lnap.AddP70enum("LightType", 4);
 2298|       |            break;*/
 2299|      3|        default:
  ------------------
  |  Branch (2299:9): [True: 3, False: 54]
  ------------------
 2300|      3|            break;
 2301|     57|        }
 2302|       |
 2303|       |        // Did not understood how to configure the decay so disabling attenuation.
 2304|     57|        lnap.AddP70enum("DecayType", 0);
 2305|       |
 2306|       |        // Dump to FBX stream
 2307|     57|        lna.AddChild(lnap);
 2308|     57|        lna.AddChild("TypeFlags", FBX::FBXExportProperty("Light"));
 2309|     57|        lna.AddChild("GeometryVersion", FBX::FBXExportProperty(int32_t(124)));
 2310|     57|        lna.Dump(outstream, binary, indent);
 2311|       |
 2312|       |        // Store name and uid (will be used later when parsing scene nodes)
 2313|     57|        lights_uids[l->mName.C_Str()] = uid;
 2314|     57|    }
 2315|       |
 2316|       |    // TODO: cameras
 2317|       |
 2318|       |    // write nodes (i.e. model hierarchy)
 2319|       |    // start at root node
 2320|    207|    WriteModelNodes(
 2321|    207|        outstream, mScene->mRootNode, 0, limbnodes
 2322|    207|    );
 2323|       |
 2324|       |    // animations
 2325|       |    //
 2326|       |    // in FBX there are:
 2327|       |    // * AnimationStack - corresponds to an aiAnimation
 2328|       |    // * AnimationLayer - a combinable animation component
 2329|       |    // * AnimationCurveNode - links the property to be animated
 2330|       |    // * AnimationCurve - defines animation data for a single property value
 2331|       |    //
 2332|       |    // the CurveNode also provides the default value for a property,
 2333|       |    // such as the X, Y, Z coordinates for animatable translation.
 2334|       |    //
 2335|       |    // the Curve only specifies values for one component of the property,
 2336|       |    // so there will be a separate AnimationCurve for X, Y, and Z.
 2337|       |    //
 2338|       |    // Assimp has:
 2339|       |    // * aiAnimation - basically corresponds to an AnimationStack
 2340|       |    // * aiNodeAnim - defines all animation for one aiNode
 2341|       |    // * aiVectorKey/aiQuatKey - define the keyframe data for T/R/S
 2342|       |    //
 2343|       |    // assimp has no equivalent for AnimationLayer,
 2344|       |    // and these are flattened on FBX import.
 2345|       |    // we can assume there will be one per AnimationStack.
 2346|       |    //
 2347|       |    // the aiNodeAnim contains all animation data for a single aiNode,
 2348|       |    // which will correspond to three AnimationCurveNode's:
 2349|       |    // one each for translation, rotation and scale.
 2350|       |    // The data for each of these will be put in 9 AnimationCurve's,
 2351|       |    // T.X, T.Y, T.Z, R.X, R.Y, R.Z, etc.
 2352|       |
 2353|       |    // AnimationStack / aiAnimation
 2354|    207|    std::vector<int64_t> animation_stack_uids(mScene->mNumAnimations);
 2355|    235|    for (size_t ai = 0; ai < mScene->mNumAnimations; ++ai) {
  ------------------
  |  Branch (2355:25): [True: 28, False: 207]
  ------------------
 2356|     28|        int64_t animstack_uid = generate_uid();
 2357|     28|        animation_stack_uids[ai] = animstack_uid;
 2358|     28|        const aiAnimation* anim = mScene->mAnimations[ai];
 2359|       |
 2360|     28|        FBX::Node asnode("AnimationStack");
 2361|     28|        std::string name = anim->mName.C_Str() + FBX::SEPARATOR + "AnimStack";
 2362|     28|        asnode.AddProperties(animstack_uid, name, "");
 2363|     28|        FBX::Node p("Properties70");
 2364|     28|        p.AddP70time("LocalStart", 0); // assimp doesn't store this
 2365|     28|        p.AddP70time("LocalStop", to_ktime(anim->mDuration, anim));
 2366|     28|        p.AddP70time("ReferenceStart", 0);
 2367|     28|        p.AddP70time("ReferenceStop", to_ktime(anim->mDuration, anim));
 2368|     28|        asnode.AddChild(p);
 2369|       |
 2370|       |        // this node absurdly always pretends it has children
 2371|       |        // (in this case it does, but just in case...)
 2372|     28|        asnode.force_has_children = true;
 2373|     28|        asnode.Dump(outstream, binary, indent);
 2374|       |
 2375|       |        // note: animation stacks are not connected to anything
 2376|     28|    }
 2377|       |
 2378|       |    // AnimationLayer - one per aiAnimation
 2379|    207|    std::vector<int64_t> animation_layer_uids(mScene->mNumAnimations);
 2380|    235|    for (size_t ai = 0; ai < mScene->mNumAnimations; ++ai) {
  ------------------
  |  Branch (2380:25): [True: 28, False: 207]
  ------------------
 2381|     28|        int64_t animlayer_uid = generate_uid();
 2382|     28|        animation_layer_uids[ai] = animlayer_uid;
 2383|     28|        FBX::Node alnode("AnimationLayer");
 2384|     28|        alnode.AddProperties(animlayer_uid, FBX::SEPARATOR + "AnimLayer", "");
 2385|       |
 2386|       |        // this node absurdly always pretends it has children
 2387|     28|        alnode.force_has_children = true;
 2388|     28|        alnode.Dump(outstream, binary, indent);
 2389|       |
 2390|       |        // connect to the relevant animstack
 2391|     28|        connections.emplace_back(
 2392|     28|            "C", "OO", animlayer_uid, animation_stack_uids[ai]
 2393|     28|        );
 2394|     28|    }
 2395|       |
 2396|       |    // AnimCurveNode - three per aiNodeAnim
 2397|    207|    std::vector<std::vector<std::array<int64_t,3>>> curve_node_uids;
 2398|    235|    for (size_t ai = 0; ai < mScene->mNumAnimations; ++ai) {
  ------------------
  |  Branch (2398:25): [True: 28, False: 207]
  ------------------
 2399|     28|        const aiAnimation* anim = mScene->mAnimations[ai];
 2400|     28|        const int64_t layer_uid = animation_layer_uids[ai];
 2401|     28|        std::vector<std::array<int64_t,3>> nodeanim_uids;
 2402|    637|        for (size_t nai = 0; nai < anim->mNumChannels; ++nai) {
  ------------------
  |  Branch (2402:30): [True: 609, False: 28]
  ------------------
 2403|    609|            const aiNodeAnim* na = anim->mChannels[nai];
 2404|       |            // get the corresponding aiNode
 2405|    609|            const aiNode* node = mScene->mRootNode->FindNode(na->mNodeName);
 2406|       |            // and its transform
 2407|    609|            const aiMatrix4x4 node_xfm = get_world_transform(node, mScene);
 2408|    609|            aiVector3D T, R, S;
 2409|    609|            node_xfm.Decompose(S, R, T);
 2410|       |
 2411|       |            // AnimationCurveNode uids
 2412|    609|            std::array<int64_t,3> ids;
 2413|    609|            ids[0] = generate_uid(); // T
 2414|    609|            ids[1] = generate_uid(); // R
 2415|    609|            ids[2] = generate_uid(); // S
 2416|       |
 2417|       |            // translation
 2418|    609|            WriteAnimationCurveNode(outstream,
 2419|    609|                ids[0], "T", T, "Lcl Translation",
 2420|    609|                layer_uid, node_uids[node]
 2421|    609|            );
 2422|       |
 2423|       |            // rotation
 2424|    609|            WriteAnimationCurveNode(outstream,
 2425|    609|                ids[1], "R", R, "Lcl Rotation",
 2426|    609|                layer_uid, node_uids[node]
 2427|    609|            );
 2428|       |
 2429|       |            // scale
 2430|    609|            WriteAnimationCurveNode(outstream,
 2431|    609|                ids[2], "S", S, "Lcl Scale",
 2432|    609|                layer_uid, node_uids[node]
 2433|    609|            );
 2434|       |
 2435|       |            // store the uids for later use
 2436|    609|            nodeanim_uids.push_back(ids);
 2437|    609|        }
 2438|     28|        curve_node_uids.push_back(nodeanim_uids);
 2439|     28|    }
 2440|       |
 2441|       |    // AnimCurve - defines actual keyframe data.
 2442|       |    // there's a separate curve for every component of every vector,
 2443|       |    // for example a transform curvenode will have separate X/Y/Z AnimCurve's
 2444|    235|    for (size_t ai = 0; ai < mScene->mNumAnimations; ++ai) {
  ------------------
  |  Branch (2444:25): [True: 28, False: 207]
  ------------------
 2445|     28|        const aiAnimation* anim = mScene->mAnimations[ai];
 2446|    637|        for (size_t nai = 0; nai < anim->mNumChannels; ++nai) {
  ------------------
  |  Branch (2446:30): [True: 609, False: 28]
  ------------------
 2447|    609|            const aiNodeAnim* na = anim->mChannels[nai];
 2448|       |            // get the corresponding aiNode
 2449|    609|            const aiNode* node = mScene->mRootNode->FindNode(na->mNodeName);
 2450|       |            // and its transform
 2451|    609|            const aiMatrix4x4 node_xfm = get_world_transform(node, mScene);
 2452|    609|            aiVector3D T, R, S;
 2453|    609|            node_xfm.Decompose(S, R, T);
 2454|    609|            const std::array<int64_t,3>& ids = curve_node_uids[ai][nai];
 2455|       |
 2456|    609|            std::vector<int64_t> times;
 2457|    609|            std::vector<float> xval, yval, zval;
 2458|       |
 2459|       |            // position/translation
 2460|  4.05k|            for (size_t ki = 0; ki < na->mNumPositionKeys; ++ki) {
  ------------------
  |  Branch (2460:33): [True: 3.44k, False: 609]
  ------------------
 2461|  3.44k|                const aiVectorKey& k = na->mPositionKeys[ki];
 2462|  3.44k|                times.push_back(to_ktime(k.mTime, anim));
 2463|  3.44k|                xval.push_back(k.mValue.x);
 2464|  3.44k|                yval.push_back(k.mValue.y);
 2465|  3.44k|                zval.push_back(k.mValue.z);
 2466|  3.44k|            }
 2467|       |            // one curve each for X, Y, Z
 2468|    609|            WriteAnimationCurve(outstream, T.x, times, xval, ids[0], "d|X");
 2469|    609|            WriteAnimationCurve(outstream, T.y, times, yval, ids[0], "d|Y");
 2470|    609|            WriteAnimationCurve(outstream, T.z, times, zval, ids[0], "d|Z");
 2471|       |
 2472|       |            // rotation
 2473|    609|            times.clear(); xval.clear(); yval.clear(); zval.clear();
 2474|  9.14k|            for (size_t ki = 0; ki < na->mNumRotationKeys; ++ki) {
  ------------------
  |  Branch (2474:33): [True: 8.53k, False: 609]
  ------------------
 2475|  8.53k|                const aiQuatKey& k = na->mRotationKeys[ki];
 2476|  8.53k|                times.push_back(to_ktime(k.mTime, anim));
 2477|       |                // TODO: aiQuaternion method to convert to Euler...
 2478|  8.53k|                aiMatrix4x4 m(k.mValue.GetMatrix());
 2479|  8.53k|                aiVector3D qs, qr, qt;
 2480|  8.53k|                m.Decompose(qs, qr, qt);
 2481|  8.53k|                qr = AI_RAD_TO_DEG(qr);
 2482|  8.53k|                xval.push_back(qr.x);
 2483|  8.53k|                yval.push_back(qr.y);
 2484|  8.53k|                zval.push_back(qr.z);
 2485|  8.53k|            }
 2486|    609|            WriteAnimationCurve(outstream, R.x, times, xval, ids[1], "d|X");
 2487|    609|            WriteAnimationCurve(outstream, R.y, times, yval, ids[1], "d|Y");
 2488|    609|            WriteAnimationCurve(outstream, R.z, times, zval, ids[1], "d|Z");
 2489|       |
 2490|       |            // scaling/scale
 2491|    609|            times.clear(); xval.clear(); yval.clear(); zval.clear();
 2492|  1.43k|            for (size_t ki = 0; ki < na->mNumScalingKeys; ++ki) {
  ------------------
  |  Branch (2492:33): [True: 823, False: 609]
  ------------------
 2493|    823|                const aiVectorKey& k = na->mScalingKeys[ki];
 2494|    823|                times.push_back(to_ktime(k.mTime, anim));
 2495|    823|                xval.push_back(k.mValue.x);
 2496|    823|                yval.push_back(k.mValue.y);
 2497|    823|                zval.push_back(k.mValue.z);
 2498|    823|            }
 2499|    609|            WriteAnimationCurve(outstream, S.x, times, xval, ids[2], "d|X");
 2500|    609|            WriteAnimationCurve(outstream, S.y, times, yval, ids[2], "d|Y");
 2501|    609|            WriteAnimationCurve(outstream, S.z, times, zval, ids[2], "d|Z");
 2502|    609|        }
 2503|     28|    }
 2504|       |
 2505|    207|    indent = 0;
 2506|    207|    object_node.End(outstream, binary, indent, true);
 2507|    207|}
_Z8add_metaRN6Assimp3FBX4NodeEPK6aiNode:
 2532|  37.1k|void add_meta(FBX::Node& fbx_node, const aiNode* node){
 2533|  37.1k|    if(node->mMetaData == nullptr) return;
  ------------------
  |  Branch (2533:8): [True: 37.1k, False: 14]
  ------------------
 2534|     14|    aiMetadata* meta = node->mMetaData;
 2535|    124|    for (unsigned int i = 0; i < meta->mNumProperties; ++i) {
  ------------------
  |  Branch (2535:30): [True: 110, False: 14]
  ------------------
 2536|    110|        aiString key = meta->mKeys[i];
 2537|    110|        aiMetadataEntry* entry = &meta->mValues[i];
 2538|    110|        switch (entry->mType) {
 2539|      0|        case AI_BOOL:{
  ------------------
  |  Branch (2539:9): [True: 0, False: 110]
  ------------------
 2540|      0|            bool val = *static_cast<bool *>(entry->mData);
 2541|      0|            fbx_node.AddP70bool(key.C_Str(), val);
 2542|      0|            break;
 2543|      0|        }
 2544|     68|        case AI_INT32:{
  ------------------
  |  Branch (2544:9): [True: 68, False: 42]
  ------------------
 2545|     68|            int32_t val = *static_cast<int32_t *>(entry->mData);
 2546|     68|            fbx_node.AddP70int(key.C_Str(), val);
 2547|     68|            break;
 2548|      0|        }
 2549|      0|        case AI_UINT64:{
  ------------------
  |  Branch (2549:9): [True: 0, False: 110]
  ------------------
 2550|       |            //use string to add uint64
 2551|      0|            uint64_t val = *static_cast<uint64_t *>(entry->mData);
 2552|      0|            fbx_node.AddP70string(key.C_Str(), std::to_string(val).c_str());
 2553|      0|            break;
 2554|      0|        }
 2555|      3|        case AI_FLOAT:{
  ------------------
  |  Branch (2555:9): [True: 3, False: 107]
  ------------------
 2556|      3|            float val = *static_cast<float *>(entry->mData);
 2557|      3|            fbx_node.AddP70double(key.C_Str(), val);
 2558|      3|            break;
 2559|      0|        }
 2560|      0|        case AI_DOUBLE:{
  ------------------
  |  Branch (2560:9): [True: 0, False: 110]
  ------------------
 2561|      0|            double val = *static_cast<double *>(entry->mData);
 2562|      0|            fbx_node.AddP70double(key.C_Str(), val);
 2563|      0|            break;
 2564|      0|        }
 2565|     11|        case AI_AISTRING:{
  ------------------
  |  Branch (2565:9): [True: 11, False: 99]
  ------------------
 2566|     11|            aiString val = *static_cast<aiString *>(entry->mData);
 2567|     11|            fbx_node.AddP70string(key.C_Str(), val.C_Str());
 2568|     11|            break;
 2569|      0|        }
 2570|      0|        case AI_AIMETADATA: {
  ------------------
  |  Branch (2570:9): [True: 0, False: 110]
  ------------------
 2571|       |            //ignore
 2572|      0|            break;
 2573|      0|        }
 2574|     28|        default:
  ------------------
  |  Branch (2574:9): [True: 28, False: 82]
  ------------------
 2575|     28|            break;
 2576|    110|        }
 2577|       |
 2578|    110|    }
 2579|       |
 2580|     14|}
_ZN6Assimp11FBXExporter14WriteModelNodeERNS_12StreamWriterILb0ELb0EEEbPK6aiNodelRKNSt3__112basic_stringIcNS7_11char_traitsIcEENS7_9allocatorIcEEEERKNS7_6vectorINS7_4pairISD_10aiVector3tIfEEENSB_ISK_EEEENS_3FBX20TransformInheritanceE:
 2591|  37.1k|){
 2592|  37.1k|    const aiVector3D zero = {0, 0, 0};
 2593|  37.1k|    const aiVector3D one = {1, 1, 1};
 2594|  37.1k|    FBX::Node m("Model");
 2595|  37.1k|    std::string name = node->mName.C_Str() + FBX::SEPARATOR + "Model";
 2596|  37.1k|    m.AddProperties(node_uid, std::move(name), type);
 2597|  37.1k|    m.AddChild("Version", int32_t(232));
 2598|  37.1k|    FBX::Node p("Properties70");
 2599|  37.1k|    p.AddP70bool("RotationActive", true);
 2600|  37.1k|    p.AddP70int("DefaultAttributeIndex", 0);
 2601|  37.1k|    p.AddP70enum("InheritType", inherit_type);
 2602|  37.1k|    if (transform_chain.empty()) {
  ------------------
  |  Branch (2602:9): [True: 37.1k, False: 0]
  ------------------
 2603|       |        // decompose 4x4 transform matrix into TRS
 2604|  37.1k|        aiVector3D t, r, s;
 2605|  37.1k|        node->mTransformation.Decompose(s, r, t);
 2606|  37.1k|        if (t != zero) {
  ------------------
  |  Branch (2606:13): [True: 709, False: 36.4k]
  ------------------
 2607|    709|            p.AddP70(
 2608|    709|                "Lcl Translation", "Lcl Translation", "", "A",
 2609|    709|                double(t.x), double(t.y), double(t.z)
 2610|    709|            );
 2611|    709|        }
 2612|  37.1k|        if (r != zero) {
  ------------------
  |  Branch (2612:13): [True: 304, False: 36.8k]
  ------------------
 2613|    304|            r = AI_RAD_TO_DEG(r);
 2614|    304|            p.AddP70(
 2615|    304|                "Lcl Rotation", "Lcl Rotation", "", "A",
 2616|    304|                double(r.x), double(r.y), double(r.z)
 2617|    304|            );
 2618|    304|        }
 2619|  37.1k|        if (s != one) {
  ------------------
  |  Branch (2619:13): [True: 198, False: 36.9k]
  ------------------
 2620|    198|            p.AddP70(
 2621|    198|                "Lcl Scaling", "Lcl Scaling", "", "A",
 2622|    198|                double(s.x), double(s.y), double(s.z)
 2623|    198|            );
 2624|    198|        }
 2625|  37.1k|    } else {
 2626|       |        // apply the transformation chain.
 2627|       |        // these transformation elements are created when importing FBX,
 2628|       |        // which has a complex transformation hierarchy for each node.
 2629|       |        // as such we can bake the hierarchy back into the node on export.
 2630|      0|        for (auto &item : transform_chain) {
  ------------------
  |  Branch (2630:25): [True: 0, False: 0]
  ------------------
 2631|      0|            auto elem = transform_types.find(item.first);
 2632|      0|            if (elem == transform_types.end()) {
  ------------------
  |  Branch (2632:17): [True: 0, False: 0]
  ------------------
 2633|       |                // then this is a bug
 2634|      0|                std::stringstream err;
 2635|      0|                err << "unrecognized FBX transformation type: ";
 2636|      0|                err << item.first;
 2637|      0|                throw DeadlyExportError(err.str());
 2638|      0|            }
 2639|      0|            const std::string &cur_name = elem->second.first;
 2640|      0|            const aiVector3D &v = item.second;
 2641|      0|            if (cur_name.compare(0, 4, "Lcl ") == 0) {
  ------------------
  |  Branch (2641:17): [True: 0, False: 0]
  ------------------
 2642|       |                // special handling for animatable properties
 2643|      0|                p.AddP70( cur_name, cur_name, "", "A", double(v.x), double(v.y), double(v.z) );
 2644|      0|            } else {
 2645|      0|                p.AddP70vector(cur_name, v.x, v.y, v.z);
 2646|      0|            }
 2647|      0|        }
 2648|      0|    }
 2649|  37.1k|    add_meta(p, node);
 2650|  37.1k|    m.AddChild(p);
 2651|       |
 2652|       |    // not sure what these are for,
 2653|       |    // but they seem to be omnipresent
 2654|  37.1k|    m.AddChild("Shading", FBXExportProperty(true));
 2655|  37.1k|    m.AddChild("Culling", FBXExportProperty("CullingOff"));
 2656|       |
 2657|  37.1k|    m.Dump(outstream, binary, 1);
 2658|  37.1k|}
_ZN6Assimp11FBXExporter15WriteModelNodesERNS_12StreamWriterILb0ELb0EEEPK6aiNodelRKNSt3__113unordered_setIS6_NS7_4hashIS6_EENS7_8equal_toIS6_EENS7_9allocatorIS6_EEEE:
 2666|  37.2k|) {
 2667|  37.2k|    std::vector<std::pair<std::string,aiVector3D>> chain;
 2668|  37.2k|    WriteModelNodes(s, node, parent_uid, limbnodes, chain);
 2669|  37.2k|}
_ZN6Assimp11FBXExporter15WriteModelNodesERNS_12StreamWriterILb0ELb0EEEPK6aiNodelRKNSt3__113unordered_setIS6_NS7_4hashIS6_EENS7_8equal_toIS6_EENS7_9allocatorIS6_EEEERNS7_6vectorINS7_4pairINS7_12basic_stringIcNS7_11char_traitsIcEENSD_IcEEEE10aiVector3tIfEEENSD_ISR_EEEE:
 2677|  37.2k|) {
 2678|       |    // first collapse any expanded transformation chains created by FBX import.
 2679|  37.2k|    std::string node_name(node->mName.C_Str());
 2680|  37.2k|    if (node_name.find(MAGIC_NODE_TAG) != std::string::npos) {
  ------------------
  |  Branch (2680:9): [True: 0, False: 37.2k]
  ------------------
 2681|      0|        auto pos = node_name.find(MAGIC_NODE_TAG) + MAGIC_NODE_TAG.size() + 1;
 2682|      0|        std::string type_name = node_name.substr(pos);
 2683|      0|        auto elem = transform_types.find(type_name);
 2684|      0|        if (elem == transform_types.end()) {
  ------------------
  |  Branch (2684:13): [True: 0, False: 0]
  ------------------
 2685|       |            // then this is a bug and should be fixed
 2686|      0|            std::stringstream err;
 2687|      0|            err << "unrecognized FBX transformation node";
 2688|      0|            err << " of type " << type_name << " in node " << node_name;
 2689|      0|            throw DeadlyExportError(err.str());
 2690|      0|        }
 2691|      0|        aiVector3D t, r, s;
 2692|      0|        node->mTransformation.Decompose(s, r, t);
 2693|      0|        switch (elem->second.second) {
 2694|      0|        case 'i': // inverse
  ------------------
  |  Branch (2694:9): [True: 0, False: 0]
  ------------------
 2695|       |            // we don't need to worry about the inverse matrices
 2696|      0|            break;
 2697|      0|        case 't': // translation
  ------------------
  |  Branch (2697:9): [True: 0, False: 0]
  ------------------
 2698|      0|            transform_chain.emplace_back(elem->first, t);
 2699|      0|            break;
 2700|      0|        case 'r': // rotation
  ------------------
  |  Branch (2700:9): [True: 0, False: 0]
  ------------------
 2701|      0|            transform_chain.emplace_back(elem->first, AI_RAD_TO_DEG(r));
 2702|      0|            break;
 2703|      0|        case 's': // scale
  ------------------
  |  Branch (2703:9): [True: 0, False: 0]
  ------------------
 2704|      0|            transform_chain.emplace_back(elem->first, s);
 2705|      0|            break;
 2706|      0|        default:
  ------------------
  |  Branch (2706:9): [True: 0, False: 0]
  ------------------
 2707|       |            // this should never happen
 2708|      0|            std::stringstream err;
 2709|      0|            err << "unrecognized FBX transformation type code: ";
 2710|      0|            err << elem->second.second;
 2711|      0|            throw DeadlyExportError(err.str());
 2712|      0|        }
 2713|       |        // now continue on to any child nodes
 2714|      0|        for (unsigned i = 0; i < node->mNumChildren; ++i) {
  ------------------
  |  Branch (2714:30): [True: 0, False: 0]
  ------------------
 2715|      0|            WriteModelNodes(
 2716|      0|                outstream,
 2717|      0|                node->mChildren[i],
 2718|      0|                parent_uid,
 2719|      0|                limbnodes,
 2720|      0|                transform_chain
 2721|      0|            );
 2722|      0|        }
 2723|      0|        return;
 2724|      0|    }
 2725|       |
 2726|  37.2k|    int64_t node_uid = 0;
 2727|       |    // generate uid and connect to parent, if not the root node,
 2728|  37.2k|    if (node != mScene->mRootNode) {
  ------------------
  |  Branch (2728:9): [True: 37.0k, False: 207]
  ------------------
 2729|  37.0k|        auto elem = node_uids.find(node);
 2730|  37.0k|        if (elem != node_uids.end()) {
  ------------------
  |  Branch (2730:13): [True: 3.07k, False: 34.0k]
  ------------------
 2731|  3.07k|            node_uid = elem->second;
 2732|  34.0k|        } else {
 2733|  34.0k|            node_uid = generate_uid();
 2734|  34.0k|            node_uids[node] = node_uid;
 2735|  34.0k|        }
 2736|  37.0k|        connections.emplace_back("C", "OO", node_uid, parent_uid);
 2737|  37.0k|    }
 2738|       |
 2739|       |    // what type of node is this?
 2740|  37.2k|    if (node == mScene->mRootNode) {
  ------------------
  |  Branch (2740:9): [True: 207, False: 37.0k]
  ------------------
 2741|       |        // handled later
 2742|  37.0k|    } else if (node->mNumMeshes == 1) {
  ------------------
  |  Branch (2742:16): [True: 12.3k, False: 24.7k]
  ------------------
 2743|       |        // connect to child mesh, which should have been written previously
 2744|       |        // TODO double check this line
 2745|  12.3k|        connections.emplace_back("C", "OO", mesh_uids[node], node_uid);
 2746|       |        // also connect to the material for the child mesh
 2747|  12.3k|        connections.emplace_back(
 2748|  12.3k|            "C", "OO",
 2749|  12.3k|            material_uids[mScene->mMeshes[node->mMeshes[0]]->mMaterialIndex],
 2750|  12.3k|            node_uid
 2751|  12.3k|        );
 2752|       |        // write model node
 2753|  12.3k|        WriteModelNode(
 2754|  12.3k|            outstream, binary, node, node_uid, "Mesh", transform_chain
 2755|  12.3k|        );
 2756|  24.7k|    } else if (limbnodes.count(node)) {
  ------------------
  |  Branch (2756:16): [True: 3.07k, False: 21.7k]
  ------------------
 2757|  3.07k|        WriteModelNode(
 2758|  3.07k|            outstream, binary, node, node_uid, "LimbNode", transform_chain
 2759|  3.07k|        );
 2760|       |        // we also need to write a nodeattribute to mark it as a skeleton
 2761|  3.07k|        int64_t node_attribute_uid = generate_uid();
 2762|  3.07k|        FBX::Node na("NodeAttribute");
 2763|  3.07k|        na.AddProperties(
 2764|  3.07k|            node_attribute_uid, FBX::SEPARATOR + "NodeAttribute", "LimbNode"
 2765|  3.07k|        );
 2766|  3.07k|        na.AddChild("TypeFlags", FBXExportProperty("Skeleton"));
 2767|  3.07k|        na.Dump(outstream, binary, 1);
 2768|       |        // and connect them
 2769|  3.07k|        connections.emplace_back("C", "OO", node_attribute_uid, node_uid);
 2770|  21.7k|    } else if (node->mNumMeshes >= 1) {
  ------------------
  |  Branch (2770:16): [True: 267, False: 21.4k]
  ------------------
 2771|    267|      connections.emplace_back("C", "OO", mesh_uids[node], node_uid);
 2772|  1.50k|      for (size_t i = 0; i < node->mNumMeshes; i++) {
  ------------------
  |  Branch (2772:26): [True: 1.23k, False: 267]
  ------------------
 2773|  1.23k|        connections.emplace_back(
 2774|  1.23k|          "C", "OO",
 2775|  1.23k|          material_uids[mScene->mMeshes[node->mMeshes[i]]->mMaterialIndex],
 2776|  1.23k|          node_uid
 2777|  1.23k|        );
 2778|  1.23k|      }
 2779|    267|      WriteModelNode(outstream, binary, node, node_uid, "Mesh", transform_chain);
 2780|  21.4k|    } else {
 2781|  21.4k|        const auto& lightIt = lights_uids.find(node->mName.C_Str());
 2782|  21.4k|        if(lightIt != lights_uids.end()) {
  ------------------
  |  Branch (2782:12): [True: 52, False: 21.3k]
  ------------------
 2783|       |            // Node has a light connected to it.
 2784|     52|            WriteModelNode(
 2785|     52|                outstream, binary, node, node_uid, "Light", transform_chain
 2786|     52|            );
 2787|     52|            connections.emplace_back("C", "OO", lightIt->second, node_uid);
 2788|  21.3k|        } else {
 2789|       |            // generate a null node so we can add children to it
 2790|  21.3k|            WriteModelNode(
 2791|  21.3k|                outstream, binary, node, node_uid, "Null", transform_chain
 2792|  21.3k|            );
 2793|  21.3k|        }
 2794|  21.4k|    }
 2795|       |
 2796|  37.2k|    if (node == mScene->mRootNode && node->mNumMeshes > 0) {
  ------------------
  |  Branch (2796:9): [True: 207, False: 37.0k]
  |  Branch (2796:38): [True: 47, False: 160]
  ------------------
 2797|     47|      int64_t new_node_uid = generate_uid();
 2798|     47|      connections.emplace_back("C", "OO", new_node_uid, node_uid);
 2799|     47|      connections.emplace_back("C", "OO", mesh_uids[node], new_node_uid);
 2800|    142|      for (size_t i = 0; i < node->mNumMeshes; ++i) {
  ------------------
  |  Branch (2800:26): [True: 95, False: 47]
  ------------------
 2801|     95|        connections.emplace_back(
 2802|     95|          "C", "OO",
 2803|     95|          material_uids[mScene->mMeshes[node->mMeshes[i]]->mMaterialIndex],
 2804|     95|          new_node_uid
 2805|     95|        );
 2806|     95|      }
 2807|     47|      aiNode new_node;
 2808|     47|      new_node.mName = mScene->mMeshes[0]->mName;
 2809|     47|      WriteModelNode(outstream, binary, &new_node, new_node_uid, "Mesh", {});
 2810|     47|    }
 2811|       |
 2812|       |    // now recurse into children
 2813|  74.3k|    for (size_t i = 0; i < node->mNumChildren; ++i) {
  ------------------
  |  Branch (2813:24): [True: 37.0k, False: 37.2k]
  ------------------
 2814|  37.0k|        WriteModelNodes(
 2815|  37.0k|            outstream, node->mChildren[i], node_uid, limbnodes
 2816|  37.0k|        );
 2817|  37.0k|    }
 2818|  37.2k|}
_ZN6Assimp11FBXExporter23WriteAnimationCurveNodeERNS_12StreamWriterILb0ELb0EEElRKNSt3__112basic_stringIcNS4_11char_traitsIcEENS4_9allocatorIcEEEE10aiVector3tIfESC_ll:
 2827|  1.82k|        int64_t node_uid) {
 2828|  1.82k|    FBX::Node n("AnimationCurveNode");
 2829|  1.82k|    n.AddProperties(uid, name + FBX::SEPARATOR + "AnimCurveNode", "");
 2830|  1.82k|    FBX::Node p("Properties70");
 2831|  1.82k|    p.AddP70numberA("d|X", default_value.x);
 2832|  1.82k|    p.AddP70numberA("d|Y", default_value.y);
 2833|  1.82k|    p.AddP70numberA("d|Z", default_value.z);
 2834|  1.82k|    n.AddChild(p);
 2835|  1.82k|    n.Dump(outstream, binary, 1);
 2836|       |    // connect to layer
 2837|  1.82k|    this->connections.emplace_back("C", "OO", uid, layer_uid);
 2838|       |    // connect to bone
 2839|  1.82k|    this->connections.emplace_back("C", "OP", uid, node_uid, property_name);
 2840|  1.82k|}
_ZN6Assimp11FBXExporter19WriteAnimationCurveERNS_12StreamWriterILb0ELb0EEEdRKNSt3__16vectorIlNS4_9allocatorIlEEEERKNS5_IfNS6_IfEEEElRKNS4_12basic_stringIcNS4_11char_traitsIcEENS6_IcEEEE:
 2849|  5.48k|) {
 2850|  5.48k|    FBX::Node n("AnimationCurve");
 2851|  5.48k|    int64_t curve_uid = generate_uid();
 2852|  5.48k|    n.AddProperties(curve_uid, FBX::SEPARATOR + "AnimCurve", "");
 2853|  5.48k|    n.AddChild("Default", default_value);
 2854|  5.48k|    n.AddChild("KeyVer", int32_t(4009));
 2855|  5.48k|    n.AddChild("KeyTime", times);
 2856|  5.48k|    n.AddChild("KeyValueFloat", values);
 2857|       |    // TODO: keyattr flags and data (STUB for now)
 2858|  5.48k|    n.AddChild("KeyAttrFlags", std::vector<int32_t>{0});
 2859|  5.48k|    n.AddChild("KeyAttrDataFloat", std::vector<float>{0,0,0,0});
 2860|  5.48k|    n.AddChild(
 2861|  5.48k|        "KeyAttrRefCount",
 2862|  5.48k|        std::vector<int32_t>{static_cast<int32_t>(times.size())}
 2863|  5.48k|    );
 2864|  5.48k|    n.Dump(outstream, binary, 1);
 2865|  5.48k|    this->connections.emplace_back(
 2866|  5.48k|        "C", "OP", curve_uid, curvenode_uid, property_link
 2867|  5.48k|    );
 2868|  5.48k|}
_ZN6Assimp11FBXExporter16WriteConnectionsEv:
 2872|    207|{
 2873|       |    // we should have completed the connection graph already,
 2874|       |    // so basically just dump it here
 2875|    207|    if (!binary) {
  ------------------
  |  Branch (2875:9): [True: 0, False: 207]
  ------------------
 2876|      0|        WriteAsciiSectionHeader("Object connections");
 2877|      0|    }
 2878|       |    // TODO: comments with names in the ascii version
 2879|    207|    FBX::Node conn("Connections");
 2880|    207|    StreamWriterLE outstream(outfile);
 2881|    207|    conn.Begin(outstream, binary, 0);
 2882|    207|    conn.BeginChildren(outstream, binary, 0);
 2883|  82.0k|    for (auto &n : connections) {
  ------------------
  |  Branch (2883:18): [True: 82.0k, False: 207]
  ------------------
 2884|  82.0k|        n.Dump(outstream, binary, 1);
 2885|  82.0k|    }
 2886|    207|    conn.End(outstream, binary, 0, !connections.empty());
 2887|    207|    connections.clear();
 2888|    207|}
FBXExporter.cpp:_ZL13has_phong_matPK7aiScene:
  547|    174|static bool has_phong_mat(const aiScene* scene) {
  548|       |    // just search for any material with a shininess exponent
  549|    327|    for (size_t i = 0; i < scene->mNumMaterials; ++i) {
  ------------------
  |  Branch (549:24): [True: 210, False: 117]
  ------------------
  550|    210|        aiMaterial* mat = scene->mMaterials[i];
  551|    210|        float shininess = 0;
  552|    210|        mat->Get(AI_MATKEY_SHININESS, shininess);
  553|    210|        if (shininess > 0) {
  ------------------
  |  Branch (553:13): [True: 57, False: 153]
  ------------------
  554|     57|            return true;
  555|     57|        }
  556|    210|    }
  557|    117|    return false;
  558|    174|}
FBXExporter.cpp:_ZL12count_imagesPK7aiScene:
  560|    208|static size_t count_images(const aiScene* scene) {
  561|    208|    std::unordered_set<std::string> images;
  562|    208|    aiString texpath;
  563|    454|    for (size_t i = 0; i < scene->mNumMaterials; ++i) {
  ------------------
  |  Branch (563:24): [True: 246, False: 208]
  ------------------
  564|    246|        aiMaterial *mat = scene->mMaterials[i];
  565|  4.42k|        for (size_t tt = aiTextureType_DIFFUSE; tt < aiTextureType_UNKNOWN; ++tt) {
  ------------------
  |  Branch (565:49): [True: 4.18k, False: 246]
  ------------------
  566|  4.18k|            const aiTextureType textype = static_cast<aiTextureType>(tt);
  567|  4.18k|            const size_t texcount = mat->GetTextureCount(textype);
  568|  4.29k|            for (unsigned int j = 0; j < texcount; ++j) {
  ------------------
  |  Branch (568:38): [True: 116, False: 4.18k]
  ------------------
  569|    116|                mat->GetTexture(textype, j, &texpath);
  570|    116|                images.insert(std::string(texpath.C_Str()));
  571|    116|            }
  572|  4.18k|        }
  573|    246|    }
  574|       |
  575|    208|    return images.size();
  576|    208|}
FBXExporter.cpp:_ZL14count_texturesPK7aiScene:
  578|    208|static size_t count_textures(const aiScene* scene) {
  579|    208|    size_t count = 0;
  580|    454|    for (size_t i = 0; i < scene->mNumMaterials; ++i) {
  ------------------
  |  Branch (580:24): [True: 246, False: 208]
  ------------------
  581|    246|        aiMaterial* mat = scene->mMaterials[i];
  582|    246|        for (
  583|    246|            size_t tt = aiTextureType_DIFFUSE;
  584|  4.42k|            tt < aiTextureType_UNKNOWN;
  ------------------
  |  Branch (584:13): [True: 4.18k, False: 246]
  ------------------
  585|  4.18k|            ++tt
  586|  4.18k|        ){
  587|       |            // TODO: handle layered textures
  588|  4.18k|            if (mat->GetTextureCount(static_cast<aiTextureType>(tt)) > 0) {
  ------------------
  |  Branch (588:17): [True: 105, False: 4.07k]
  ------------------
  589|    105|                count += 1;
  590|    105|            }
  591|  4.18k|        }
  592|    246|    }
  593|    208|    return count;
  594|    208|}
FBXExporter.cpp:_ZL15count_deformersPK7aiScene:
  596|    208|static size_t count_deformers(const aiScene* scene) {
  597|    208|    size_t count = 0;
  598|  3.78k|    for (size_t i = 0; i < scene->mNumMeshes; ++i) {
  ------------------
  |  Branch (598:24): [True: 3.57k, False: 208]
  ------------------
  599|  3.57k|        const size_t n = scene->mMeshes[i]->mNumBones;
  600|  3.57k|        if (n) {
  ------------------
  |  Branch (600:13): [True: 27, False: 3.54k]
  ------------------
  601|       |            // 1 main deformer, 1 subdeformer per bone
  602|     27|            count += n + 1;
  603|     27|        }
  604|  3.57k|    }
  605|    208|    return count;
  606|    208|}
FBXExporter.cpp:_ZL17get_node_for_meshjP6aiNode:
 1019|    271|static aiNode* get_node_for_mesh(unsigned int meshIndex, aiNode* node) {
 1020|    280|    for (size_t i = 0; i < node->mNumMeshes; ++i) {
  ------------------
  |  Branch (1020:24): [True: 35, False: 245]
  ------------------
 1021|     35|        if (node->mMeshes[i] == meshIndex) {
  ------------------
  |  Branch (1021:13): [True: 26, False: 9]
  ------------------
 1022|     26|            return node;
 1023|     26|        }
 1024|     35|    }
 1025|    473|    for (size_t i = 0; i < node->mNumChildren; ++i) {
  ------------------
  |  Branch (1025:24): [True: 245, False: 228]
  ------------------
 1026|    245|        aiNode* ret = get_node_for_mesh(meshIndex, node->mChildren[i]);
 1027|    245|        if (ret) { return ret; }
  ------------------
  |  Branch (1027:13): [True: 17, False: 228]
  ------------------
 1028|    245|    }
 1029|    228|    return nullptr;
 1030|    245|}
_Z8to_ktimedPK11aiAnimation:
 1045|  12.8k|inline int64_t to_ktime(double ticks, const aiAnimation* anim) {
 1046|  12.8k|    if (FP_ZERO == std::fpclassify(anim->mTicksPerSecond)) {
  ------------------
  |  Branch (1046:9): [True: 2.47k, False: 10.3k]
  ------------------
 1047|  2.47k|        return static_cast<int64_t>(ticks * FBX::SECOND);
 1048|  2.47k|    }
 1049|       |    
 1050|       |    // Defensive: handle zero or near-zero mTicksPerSecond
 1051|  10.3k|    double tps = anim->mTicksPerSecond;
 1052|  10.3k|    double timeVal;
 1053|  10.3k|    if (FP_ZERO == std::fpclassify(tps)) {
  ------------------
  |  Branch (1053:9): [True: 0, False: 10.3k]
  ------------------
 1054|      0|        timeVal = ticks;
 1055|  10.3k|    } else {
 1056|  10.3k|        timeVal = ticks / tps;
 1057|  10.3k|    }
 1058|       |
 1059|       |    // Clamp to prevent overflow
 1060|  10.3k|    const double kMax = static_cast<double>(INT64_MAX) / static_cast<double>(FBX::SECOND);
 1061|  10.3k|    const double kMin = static_cast<double>(INT64_MIN) / static_cast<double>(FBX::SECOND);
 1062|       |
 1063|  10.3k|    if (timeVal > kMax) {
  ------------------
  |  Branch (1063:9): [True: 0, False: 10.3k]
  ------------------
 1064|      0|        return INT64_MAX;
 1065|      0|    }
 1066|  10.3k|    if (timeVal < kMin) {
  ------------------
  |  Branch (1066:9): [True: 0, False: 10.3k]
  ------------------
 1067|      0|        return INT64_MIN;
 1068|      0|    }
 1069|  10.3k|    return static_cast<int64_t>((ticks / anim->mTicksPerSecond) * FBX::SECOND);
 1070|  10.3k|}
FBXExporter.cpp:_ZZN6Assimp11FBXExporter12WriteObjectsEvENK3$_0clEPK6aiNode:
 1108|  37.2k|    std::function<void(const aiNode*)> visit_node_geo = [&](const aiNode *node) {
 1109|  37.2k|        if (node->mNumMeshes == 0) {
  ------------------
  |  Branch (1109:13): [True: 24.6k, False: 12.6k]
  ------------------
 1110|  58.8k|          for (uint32_t ni = 0; ni < node->mNumChildren; ni++) {
  ------------------
  |  Branch (1110:33): [True: 34.1k, False: 24.6k]
  ------------------
 1111|  34.1k|            visit_node_geo(node->mChildren[ni]);
 1112|  34.1k|          }
 1113|  24.6k|          return;
 1114|  24.6k|        }
 1115|       |
 1116|       |        // start the node record
 1117|  12.6k|        FBX::Node n("Geometry");
 1118|  12.6k|        int64_t uid = generate_uid();
 1119|  12.6k|        mesh_uids[node] = uid;
 1120|  12.6k|        n.AddProperty(uid);
 1121|  12.6k|        n.AddProperty(FBX::SEPARATOR + "Geometry");
 1122|  12.6k|        n.AddProperty("Mesh");
 1123|  12.6k|        n.Begin(outstream, binary, indent);
 1124|  12.6k|        n.DumpProperties(outstream, binary, indent);
 1125|  12.6k|        n.EndProperties(outstream, binary, indent);
 1126|  12.6k|        n.BeginChildren(outstream, binary, indent);
 1127|       |
 1128|       |        // output vertex data - each vertex should be unique (probably)
 1129|  12.6k|        std::vector<double> flattened_vertices;
 1130|       |        // index of original vertex in vertex data vector
 1131|  12.6k|        std::vector<int32_t> vertex_indices;
 1132|       |
 1133|  12.6k|        std::vector<double> normal_data;
 1134|  12.6k|        std::vector<double> color_data;
 1135|       |
 1136|  12.6k|        std::vector<int32_t> polygon_data;
 1137|       |
 1138|  12.6k|        std::vector<std::vector<double>> uv_data;
 1139|  12.6k|        std::vector<std::vector<int32_t>> uv_indices;
 1140|       |
 1141|  12.6k|        indent = 2;
 1142|       |
 1143|  26.2k|        for (uint32_t n_mi = 0; n_mi < node->mNumMeshes; n_mi++) {
  ------------------
  |  Branch (1143:33): [True: 13.6k, False: 12.6k]
  ------------------
 1144|  13.6k|          const auto mi = node->mMeshes[n_mi];
 1145|  13.6k|          const aiMesh *m = mScene->mMeshes[mi];
 1146|       |
 1147|  13.6k|          size_t v_offset = vertex_indices.size();
 1148|  13.6k|          size_t uniq_v_before = flattened_vertices.size() / 3;
 1149|       |
 1150|       |          // map of vertex value to its index in the data vector
 1151|  13.6k|          std::map<aiVector3D,size_t> index_by_vertex_value;
 1152|  13.6k|          if (bJoinIdenticalVertices) {
  ------------------
  |  Branch (1152:15): [True: 0, False: 13.6k]
  ------------------
 1153|      0|              int32_t index = 0;
 1154|      0|              for (size_t vi = 0; vi < m->mNumVertices; ++vi) {
  ------------------
  |  Branch (1154:35): [True: 0, False: 0]
  ------------------
 1155|      0|                  aiVector3D vtx = m->mVertices[vi];
 1156|      0|                  auto elem = index_by_vertex_value.find(vtx);
 1157|      0|                  if (elem == index_by_vertex_value.end()) {
  ------------------
  |  Branch (1157:23): [True: 0, False: 0]
  ------------------
 1158|      0|                      vertex_indices.push_back(index);
 1159|      0|                      index_by_vertex_value[vtx] = index;
 1160|      0|                      flattened_vertices.insert(flattened_vertices.end(), { vtx.x, vtx.y, vtx.z });
 1161|      0|                      ++index;
 1162|      0|                  } else {
 1163|      0|                      vertex_indices.push_back(int32_t(elem->second));
 1164|      0|                  }
 1165|      0|              }
 1166|  13.6k|          } else { // do not join vertex, respect the export flag
 1167|  13.6k|              vertex_indices.resize(v_offset + m->mNumVertices);
 1168|  13.6k|              std::iota(vertex_indices.begin() + v_offset, vertex_indices.end(), 0);
 1169|   959k|              for(unsigned int v = 0; v < m->mNumVertices; ++ v) {
  ------------------
  |  Branch (1169:39): [True: 946k, False: 13.6k]
  ------------------
 1170|   946k|                  aiVector3D vtx = m->mVertices[v];
 1171|   946k|                  flattened_vertices.insert(flattened_vertices.end(), {vtx.x, vtx.y, vtx.z});
 1172|   946k|              }
 1173|  13.6k|          }
 1174|  13.6k|          vVertexIndice[mi].insert(
 1175|       |            // TODO test whether this can be end or not
 1176|  13.6k|            vVertexIndice[mi].end(),
 1177|  13.6k|            vertex_indices.begin() + v_offset,
 1178|  13.6k|            vertex_indices.end()
 1179|  13.6k|          );
 1180|       |
 1181|       |          // here could be edges but they're insane.
 1182|       |          // it's optional anyway, so let's ignore it.
 1183|       |
 1184|       |        // output polygon data as a flattened array of vertex indices.
 1185|       |        // the last vertex index of each polygon is negated and - 1
 1186|  1.78M|          for (size_t fi = 0; fi < m->mNumFaces; fi++) {
  ------------------
  |  Branch (1186:31): [True: 1.77M, False: 13.6k]
  ------------------
 1187|  1.77M|            const aiFace &f = m->mFaces[fi];
 1188|  1.77M|            if (f.mNumIndices == 0) continue;
  ------------------
  |  Branch (1188:17): [True: 0, False: 1.77M]
  ------------------
 1189|  1.77M|            size_t pvi = 0;
 1190|  5.27M|            for (; pvi < f.mNumIndices - 1; pvi++) {
  ------------------
  |  Branch (1190:20): [True: 3.49M, False: 1.77M]
  ------------------
 1191|  3.49M|              polygon_data.push_back(
 1192|  3.49M|                static_cast<int32_t>(uniq_v_before + vertex_indices[v_offset + f.mIndices[pvi]])
 1193|  3.49M|              );
 1194|  3.49M|            }
 1195|  1.77M|            polygon_data.push_back(
 1196|  1.77M|              static_cast<int32_t>(-1 ^ (uniq_v_before + vertex_indices[v_offset+f.mIndices[pvi]]))
 1197|  1.77M|            );
 1198|  1.77M|          }
 1199|       |
 1200|  13.6k|          uniq_v_before_mi.push_back(static_cast<uint32_t>(uniq_v_before));
 1201|       |
 1202|  13.6k|          if (m->HasNormals()) {
  ------------------
  |  Branch (1202:15): [True: 12.6k, False: 1.02k]
  ------------------
 1203|  12.6k|            normal_data.reserve(3 * polygon_data.size());
 1204|  1.78M|            for (size_t fi = 0; fi < m->mNumFaces; fi++) {
  ------------------
  |  Branch (1204:33): [True: 1.77M, False: 12.6k]
  ------------------
 1205|  1.77M|              const aiFace & f = m->mFaces[fi];
 1206|  7.03M|              for (size_t pvi = 0; pvi < f.mNumIndices; pvi++) {
  ------------------
  |  Branch (1206:36): [True: 5.26M, False: 1.77M]
  ------------------
 1207|  5.26M|                const aiVector3D &curN = m->mNormals[f.mIndices[pvi]];
 1208|  5.26M|                normal_data.insert(normal_data.end(), { curN.x, curN.y, curN.z });
 1209|  5.26M|              }
 1210|  1.77M|            }
 1211|  12.6k|          }
 1212|       |
 1213|  13.6k|          const int32_t colorChannelIndex = 0;
 1214|  13.6k|          if (m->HasVertexColors(colorChannelIndex)) {
  ------------------
  |  Branch (1214:15): [True: 214, False: 13.4k]
  ------------------
 1215|    214|            color_data.reserve(4 * polygon_data.size());
 1216|  33.6k|            for (size_t fi = 0; fi < m->mNumFaces; fi++) {
  ------------------
  |  Branch (1216:33): [True: 33.4k, False: 214]
  ------------------
 1217|  33.4k|              const aiFace &f = m->mFaces[fi];
 1218|   133k|              for (size_t pvi = 0; pvi < f.mNumIndices; pvi++) {
  ------------------
  |  Branch (1218:36): [True: 99.5k, False: 33.4k]
  ------------------
 1219|  99.5k|                const aiColor4D &c = m->mColors[colorChannelIndex][f.mIndices[pvi]];
 1220|  99.5k|                color_data.insert(color_data.end(), { c.r, c.g, c.b, c.a });
 1221|  99.5k|              }
 1222|  33.4k|            }
 1223|    214|          }
 1224|       |
 1225|  13.6k|          const auto num_uv = static_cast<size_t>(m->GetNumUVChannels());
 1226|  13.6k|          uv_indices.resize(std::max(num_uv, uv_indices.size()));
 1227|  13.6k|          uv_data.resize(std::max(num_uv, uv_data.size()));
 1228|  13.6k|          std::map<aiVector3D, int32_t> index_by_uv;
 1229|       |
 1230|       |          // uvs, if any
 1231|  13.9k|          for (size_t uvi = 0; uvi < m->GetNumUVChannels(); uvi++) {
  ------------------
  |  Branch (1231:32): [True: 276, False: 13.6k]
  ------------------
 1232|    276|            const auto nc = m->mNumUVComponents[uvi];
 1233|    276|            if (nc > 2) {
  ------------------
  |  Branch (1233:17): [True: 1, False: 275]
  ------------------
 1234|       |                // FBX only supports 2-channel UV maps...
 1235|       |                // or at least i'm not sure how to indicate a different number
 1236|      1|                std::stringstream err;
 1237|      1|                err << "Only 2-channel UV maps supported by FBX,";
 1238|      1|                err << " but mesh " << mi;
 1239|      1|                if (m->mName.length) {
  ------------------
  |  Branch (1239:21): [True: 1, False: 0]
  ------------------
 1240|      1|                    err << " (" << m->mName.C_Str() << ")";
 1241|      1|                }
 1242|      1|                err << " UV map " << uvi;
 1243|      1|                err << " has " << m->mNumUVComponents[uvi];
 1244|      1|                err << " components! Data will be preserved,";
 1245|      1|                err << " but may be incorrectly interpreted on load.";
 1246|      1|                ASSIMP_LOG_WARN(err.str());
 1247|      1|            }
 1248|       |
 1249|    276|            int32_t index = static_cast<int32_t>(uv_data[uvi].size()) / nc;
 1250|   152k|            for (size_t fi = 0; fi < m->mNumFaces; fi++) {
  ------------------
  |  Branch (1250:33): [True: 151k, False: 276]
  ------------------
 1251|   151k|              const aiFace &f = m->mFaces[fi];
 1252|   607k|              for (size_t pvi = 0; pvi < f.mNumIndices; pvi++) {
  ------------------
  |  Branch (1252:36): [True: 455k, False: 151k]
  ------------------
 1253|   455k|                const aiVector3D &curUv = m->mTextureCoords[uvi][f.mIndices[pvi]];
 1254|   455k|                auto elem = index_by_uv.find(curUv);
 1255|   455k|                if (elem == index_by_uv.end()) {
  ------------------
  |  Branch (1255:21): [True: 78.6k, False: 376k]
  ------------------
 1256|  78.6k|                  index_by_uv[curUv] = index;
 1257|  78.6k|                  uv_indices[uvi].push_back(index);
 1258|   236k|                  for (uint32_t x = 0; x < nc; ++x) {
  ------------------
  |  Branch (1258:40): [True: 157k, False: 78.6k]
  ------------------
 1259|   157k|                    uv_data[uvi].push_back(curUv[x]);
 1260|   157k|                  }
 1261|  78.6k|                  ++index;
 1262|   376k|                } else {
 1263|   376k|                  uv_indices[uvi].push_back(elem->second);
 1264|   376k|                }
 1265|   455k|              }
 1266|   151k|            }
 1267|    276|          }
 1268|  13.6k|        }
 1269|       |
 1270|       |
 1271|  12.6k|        FBX::Node::WritePropertyNode("Vertices", flattened_vertices, outstream, binary, indent);
 1272|  12.6k|        FBX::Node::WritePropertyNode("PolygonVertexIndex", polygon_data, outstream, binary, indent);
 1273|  12.6k|        FBX::Node::WritePropertyNode("GeometryVersion", int32_t(124), outstream, binary, indent);
 1274|       |
 1275|  12.6k|	if (!normal_data.empty()) {
  ------------------
  |  Branch (1275:6): [True: 12.1k, False: 516]
  ------------------
 1276|  12.1k|	    FBX::Node normals("LayerElementNormal", int32_t(0));
 1277|  12.1k|	    normals.Begin(outstream, binary, indent);
 1278|  12.1k|	    normals.DumpProperties(outstream, binary, indent);
 1279|  12.1k|	    normals.EndProperties(outstream, binary, indent);
 1280|  12.1k|	    normals.BeginChildren(outstream, binary, indent);
 1281|  12.1k|	    indent = 3;
 1282|  12.1k|	    FBX::Node::WritePropertyNode("Version", int32_t(101), outstream, binary, indent);
 1283|  12.1k|	    FBX::Node::WritePropertyNode("Name", "", outstream, binary, indent);
 1284|  12.1k|	    FBX::Node::WritePropertyNode("MappingInformationType", "ByPolygonVertex", outstream, binary, indent);
 1285|  12.1k|	    FBX::Node::WritePropertyNode("ReferenceInformationType", "Direct", outstream, binary, indent);
 1286|  12.1k|	    FBX::Node::WritePropertyNode("Normals", normal_data, outstream, binary, indent);
 1287|       |	    // note: version 102 has a NormalsW also... not sure what it is,
 1288|       |	    // so stick with version 101 for now.
 1289|  12.1k|	    indent = 2;
 1290|  12.1k|	    normals.End(outstream, binary, indent, true);
 1291|  12.1k|        }
 1292|       |
 1293|  12.6k|	if (!color_data.empty()) {
  ------------------
  |  Branch (1293:6): [True: 201, False: 12.4k]
  ------------------
 1294|    201|	    const auto colorChannelIndex = 0;
 1295|    201|	    FBX::Node vertexcolors("LayerElementColor", int32_t(colorChannelIndex));
 1296|    201|	    vertexcolors.Begin(outstream, binary, indent);
 1297|    201|	    vertexcolors.DumpProperties(outstream, binary, indent);
 1298|    201|	    vertexcolors.EndProperties(outstream, binary, indent);
 1299|    201|	    vertexcolors.BeginChildren(outstream, binary, indent);
 1300|    201|	    indent = 3;
 1301|    201|	    FBX::Node::WritePropertyNode("Version", int32_t(101), outstream, binary, indent);
 1302|    201|	    char layerName[8];
 1303|    201|	    snprintf(layerName, sizeof(layerName), "COLOR_%d", colorChannelIndex);
 1304|    201|	    FBX::Node::WritePropertyNode("Name", (const char *)layerName, outstream, binary, indent);
 1305|    201|	    FBX::Node::WritePropertyNode("MappingInformationType", "ByPolygonVertex", outstream, binary, indent);
 1306|    201|	    FBX::Node::WritePropertyNode("ReferenceInformationType", "Direct", outstream, binary, indent);
 1307|    201|	    FBX::Node::WritePropertyNode("Colors", color_data, outstream, binary, indent);
 1308|    201|	    indent = 2;
 1309|    201|	    vertexcolors.End(outstream, binary, indent, true);
 1310|    201|        }
 1311|       |
 1312|  12.8k|        for (uint32_t uvi = 0; uvi < uv_data.size(); uvi++) {
  ------------------
  |  Branch (1312:32): [True: 189, False: 12.6k]
  ------------------
 1313|    189|          FBX::Node uv("LayerElementUV", int32_t(uvi));
 1314|    189|          uv.Begin(outstream, binary, indent);
 1315|    189|          uv.DumpProperties(outstream, binary, indent);
 1316|    189|          uv.EndProperties(outstream, binary, indent);
 1317|    189|          uv.BeginChildren(outstream, binary, indent);
 1318|    189|          indent = 3;
 1319|    189|          FBX::Node::WritePropertyNode("Version", int32_t(101), outstream, binary, indent);
 1320|    189|          FBX::Node::WritePropertyNode("Name", "", outstream, binary, indent);
 1321|    189|          FBX::Node::WritePropertyNode("MappingInformationType", "ByPolygonVertex", outstream, binary, indent);
 1322|    189|          FBX::Node::WritePropertyNode("ReferenceInformationType", "IndexToDirect", outstream, binary, indent);
 1323|    189|          FBX::Node::WritePropertyNode("UV", uv_data[uvi], outstream, binary, indent);
 1324|    189|          FBX::Node::WritePropertyNode("UVIndex", uv_indices[uvi], outstream, binary, indent);
 1325|    189|          indent = 2;
 1326|    189|          uv.End(outstream, binary, indent, true);
 1327|    189|        }
 1328|       |
 1329|       |
 1330|       |        // When merging multiple meshes, we instead use by polygon so the correct material is
 1331|       |        // assigned to each face. Previously, this LayerElementMaterial always had 0 since it
 1332|       |        // assumed there was 1 material for each node for all meshes.
 1333|  12.6k|        FBX::Node mat("LayerElementMaterial", int32_t(0));
 1334|  12.6k|        mat.AddChild("Version", int32_t(101));
 1335|  12.6k|        mat.AddChild("Name", "");
 1336|  12.6k|        if (node->mNumMeshes == 1) {
  ------------------
  |  Branch (1336:13): [True: 12.3k, False: 290]
  ------------------
 1337|  12.3k|          mat.AddChild("MappingInformationType", "AllSame");
 1338|  12.3k|          mat.AddChild("ReferenceInformationType", "IndexToDirect");
 1339|  12.3k|          std::vector<int32_t> mat_indices = {0};
 1340|  12.3k|          mat.AddChild("Materials", mat_indices);
 1341|  12.3k|        } else {
 1342|    290|          mat.AddChild("MappingInformationType", "ByPolygon");
 1343|    290|          mat.AddChild("ReferenceInformationType", "IndexToDirect");
 1344|    290|          std::vector<int32_t> mat_indices;
 1345|  1.59k|          for (uint32_t n_mi = 0; n_mi < node->mNumMeshes; n_mi++) {
  ------------------
  |  Branch (1345:35): [True: 1.30k, False: 290]
  ------------------
 1346|  1.30k|            const auto mi = node->mMeshes[n_mi];
 1347|  1.30k|            const auto *const m = mScene->mMeshes[mi];
 1348|   227k|            for (size_t fi = 0; fi < m->mNumFaces; fi++) {
  ------------------
  |  Branch (1348:33): [True: 226k, False: 1.30k]
  ------------------
 1349|   226k|              mat_indices.push_back(n_mi);
 1350|   226k|            }
 1351|  1.30k|          }
 1352|    290|          mat.AddChild("Materials", mat_indices);
 1353|    290|        }
 1354|  12.6k|        mat.Dump(outstream, binary, indent);
 1355|       |
 1356|       |        // finally we have the layer specifications,
 1357|       |        // which select the normals / UV set / etc to use.
 1358|       |        // TODO: handle multiple uv sets correctly?
 1359|  12.6k|        FBX::Node layer("Layer", int32_t(0));
 1360|  12.6k|        layer.AddChild("Version", int32_t(100));
 1361|  12.6k|        FBX::Node le;
 1362|       |
 1363|  12.6k|		if (!normal_data.empty()) {
  ------------------
  |  Branch (1363:7): [True: 12.1k, False: 516]
  ------------------
 1364|  12.1k|		  le = FBX::Node("LayerElement");
 1365|  12.1k|		  le.AddChild("Type", "LayerElementNormal");
 1366|  12.1k|		  le.AddChild("TypedIndex", int32_t(0));
 1367|  12.1k|		  layer.AddChild(le);
 1368|  12.1k|        }
 1369|       |
 1370|  12.6k|		if (!color_data.empty()) {
  ------------------
  |  Branch (1370:7): [True: 201, False: 12.4k]
  ------------------
 1371|    201|		  le = FBX::Node("LayerElement");
 1372|    201|		  le.AddChild("Type", "LayerElementColor");
 1373|    201|		  le.AddChild("TypedIndex", int32_t(0));
 1374|    201|		  layer.AddChild(le);
 1375|    201|        }
 1376|       |
 1377|  12.6k|        le = FBX::Node("LayerElement");
 1378|  12.6k|        le.AddChild("Type", "LayerElementMaterial");
 1379|  12.6k|        le.AddChild("TypedIndex", int32_t(0));
 1380|  12.6k|        layer.AddChild(le);
 1381|  12.6k|        le = FBX::Node("LayerElement");
 1382|  12.6k|        le.AddChild("Type", "LayerElementUV");
 1383|  12.6k|        le.AddChild("TypedIndex", int32_t(0));
 1384|  12.6k|        layer.AddChild(le);
 1385|  12.6k|        layer.Dump(outstream, binary, indent);
 1386|       |
 1387|  12.6k|        for(unsigned int lr = 1; lr < uv_data.size(); ++ lr) {
  ------------------
  |  Branch (1387:34): [True: 3, False: 12.6k]
  ------------------
 1388|      3|            FBX::Node layerExtra("Layer", int32_t(lr));
 1389|      3|            layerExtra.AddChild("Version", int32_t(100));
 1390|      3|            FBX::Node leExtra("LayerElement");
 1391|      3|            leExtra.AddChild("Type", "LayerElementUV");
 1392|      3|            leExtra.AddChild("TypedIndex", int32_t(lr));
 1393|      3|            layerExtra.AddChild(leExtra);
 1394|      3|            layerExtra.Dump(outstream, binary, indent);
 1395|      3|        }
 1396|       |        // finish the node record
 1397|  12.6k|        indent = 1;
 1398|  12.6k|        n.End(outstream, binary, indent, true);
 1399|       |
 1400|  15.5k|        for (uint32_t ni = 0; ni < node->mNumChildren; ni++) {
  ------------------
  |  Branch (1400:31): [True: 2.93k, False: 12.6k]
  ------------------
 1401|  2.93k|          visit_node_geo(node->mChildren[ni]);
 1402|  2.93k|        }
 1403|  12.6k|        return;
 1404|  37.2k|    };

_ZN6Assimp11FBXExporter12generate_uidEv:
  101|  64.0k|        int64_t generate_uid() { return ++last_uid; }

_ZN6Assimp3FBX14ImportSettingsC2Ev:
   54|    624|            strictMode(true),
   55|    624|            readAllLayers(true),
   56|    624|            readAllMaterials(false),
   57|    624|            readMaterials(true),
   58|    624|            readTextures(true),
   59|    624|            readCameras(true),
   60|    624|            readLights(true),
   61|    624|            readAnimations(true),
   62|    624|            readWeights(true),
   63|    624|            useSkeleton(false),
   64|    624|            preservePivots(true),
   65|    624|            optimizeEmptyAnimationCurves(true),
   66|    624|            useLegacyEmbeddedTextureNaming(false),
   67|    624|            removeEmptyBones(true),
   68|    624|            convertToMeters(false) {
   69|       |        // empty
   70|    624|    }

_ZNK6Assimp11FBXImporter7CanReadERKNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEPNS_8IOSystemEb:
   91|     49|bool FBXImporter::CanRead(const std::string & pFile, IOSystem * pIOHandler, bool /*checkSig*/) const {
   92|       |	// at least ASCII-FBX files usually have a 'FBX' somewhere in their head
   93|     49|	static const char *tokens[] = { " \n\r\n " };
   94|       |	return SearchFileHeaderForToken(pIOHandler, pFile, tokens, AI_COUNT_OF(tokens));
   95|     49|}
_ZNK6Assimp11FBXImporter7GetInfoEv:
   99|    634|const aiImporterDesc *FBXImporter::GetInfo() const {
  100|    634|	return &desc;
  101|    634|}

_ZN6Assimp11FBXImporterC2Ev:
   73|    624|    FBXImporter() = default;

_ZN6Assimp11HMPImporterC2Ev:
   75|    624|HMPImporter::HMPImporter() = default;
_ZN6Assimp11HMPImporterD2Ev:
   79|    624|HMPImporter::~HMPImporter() = default;
_ZNK6Assimp11HMPImporter7CanReadERKNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEPNS_8IOSystemEb:
   83|    410|bool HMPImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool /*checkSig*/) const {
   84|    410|    static constexpr uint32_t tokens[] = {
   85|    410|        AI_HMP_MAGIC_NUMBER_LE_4,
  ------------------
  |  |   53|    410|#define AI_HMP_MAGIC_NUMBER_LE_4    AI_MAKE_MAGIC("4PMH")
  ------------------
   86|    410|        AI_HMP_MAGIC_NUMBER_LE_5,
  ------------------
  |  |   56|    410|#define AI_HMP_MAGIC_NUMBER_LE_5    AI_MAKE_MAGIC("5PMH")
  ------------------
   87|    410|        AI_HMP_MAGIC_NUMBER_LE_7
  ------------------
  |  |   59|    410|#define AI_HMP_MAGIC_NUMBER_LE_7    AI_MAKE_MAGIC("7PMH")
  ------------------
   88|    410|    };
   89|       |    return CheckMagicToken(pIOHandler, pFile, tokens, AI_COUNT_OF(tokens));
   90|    410|}
_ZNK6Assimp11HMPImporter7GetInfoEv:
   94|    634|const aiImporterDesc *HMPImporter::GetInfo() const {
   95|    634|    return &desc;
   96|    634|}

_ZN6Assimp12LogFunctionsINS_11IFCImporterEE6PrefixEv:
   73|      1|const char *LogFunctions<IFCImporter>::Prefix() {
   74|      1|    return "IFC: ";
   75|      1|}
_ZNK6Assimp11IFCImporter7CanReadERKNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEPNS_8IOSystemEb:
  121|     54|bool IFCImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool /*checkSig*/) const {
  122|       |    // note: this is the common identification for STEP-encoded files, so
  123|       |    // it is only unambiguous as long as we don't support any further
  124|       |    // file formats with STEP as their encoding.
  125|     54|    static const char *tokens[] = { "ISO-10303-21" };
  126|       |    return SearchFileHeaderForToken(pIOHandler, pFile, tokens, AI_COUNT_OF(tokens));
  127|     54|}
_ZNK6Assimp11IFCImporter7GetInfoEv:
  131|    637|const aiImporterDesc *IFCImporter::GetInfo() const {
  132|    637|    return &desc;
  133|    637|}
_ZN6Assimp11IFCImporter15SetupPropertiesEPKNS_8ImporterE:
  137|      3|void IFCImporter::SetupProperties(const Importer *pImp) {
  138|      3|    settings.skipSpaceRepresentations = pImp->GetPropertyBool(AI_CONFIG_IMPORT_IFC_SKIP_SPACE_REPRESENTATIONS, true);
  139|      3|    settings.useCustomTriangulation = pImp->GetPropertyBool(AI_CONFIG_IMPORT_IFC_CUSTOM_TRIANGULATION, true);
  140|      3|    settings.conicSamplingAngle = std::min(std::max((float)pImp->GetPropertyFloat(AI_CONFIG_IMPORT_IFC_SMOOTHING_ANGLE, AI_IMPORT_IFC_DEFAULT_SMOOTHING_ANGLE), 5.0f), 120.0f);
  141|      3|    settings.cylindricalTessellation = std::min(std::max(pImp->GetPropertyInteger(AI_CONFIG_IMPORT_IFC_CYLINDRICAL_TESSELLATION, AI_IMPORT_IFC_DEFAULT_CYLINDRICAL_TESSELLATION), 3), 180);
  142|      3|    settings.skipAnnotations = true;
  143|      3|}
_ZN6Assimp11IFCImporter14InternReadFileERKNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEP7aiScenePNS_8IOSystemE:
  147|      3|void IFCImporter::InternReadFile(const std::string &pFile, aiScene *pScene, IOSystem *pIOHandler) {
  148|      3|    std::shared_ptr<IOStream> stream(pIOHandler->Open(pFile));
  149|      3|    if (!stream) {
  ------------------
  |  Branch (149:9): [True: 0, False: 3]
  ------------------
  150|      0|        ThrowException("Could not open file for reading");
  151|      0|    }
  152|       |
  153|       |    // if this is a ifczip file, decompress its contents first
  154|      3|    if (GetExtension(pFile) == "ifczip") {
  ------------------
  |  Branch (154:9): [True: 0, False: 3]
  ------------------
  155|      0|#ifndef ASSIMP_BUILD_NO_COMPRESSED_IFC
  156|      0|        unzFile zip = unzOpen(pFile.c_str());
  157|      0|        if (zip == nullptr) {
  ------------------
  |  Branch (157:13): [True: 0, False: 0]
  ------------------
  158|      0|            ThrowException("Could not open ifczip file for reading, unzip failed");
  159|      0|        }
  160|       |
  161|       |        // chop 'zip' postfix
  162|      0|        std::string fileName = pFile.substr(0, pFile.length() - 3);
  163|       |
  164|      0|        std::string::size_type s = pFile.find_last_of('\\');
  165|      0|        if (s == std::string::npos) {
  ------------------
  |  Branch (165:13): [True: 0, False: 0]
  ------------------
  166|      0|            s = pFile.find_last_of('/');
  167|      0|        }
  168|      0|        if (s != std::string::npos) {
  ------------------
  |  Branch (168:13): [True: 0, False: 0]
  ------------------
  169|      0|            fileName = fileName.substr(s + 1);
  170|      0|        }
  171|       |
  172|       |        // search file (same name as the IFCZIP except for the file extension) and place file pointer there
  173|      0|        if (UNZ_OK == unzGoToFirstFile(zip)) {
  ------------------
  |  |   74|      0|#define UNZ_OK                          (0)
  ------------------
  |  Branch (173:13): [True: 0, False: 0]
  ------------------
  174|      0|            do {
  175|       |                // get file size, etc.
  176|      0|                unz_file_info fileInfo;
  177|      0|                char filename[256];
  178|      0|                unzGetCurrentFileInfo(zip, &fileInfo, filename, sizeof(filename), nullptr, 0, nullptr, 0);
  179|      0|                if (GetExtension(filename) != "ifc") {
  ------------------
  |  Branch (179:21): [True: 0, False: 0]
  ------------------
  180|      0|                    continue;
  181|      0|                }
  182|      0|                uint8_t *buff = new uint8_t[fileInfo.uncompressed_size];
  183|      0|                LogInfo("Decompressing IFCZIP file");
  184|      0|                unzOpenCurrentFile(zip);
  185|      0|                size_t total = 0;
  186|      0|                int read = 0;
  187|      0|                do {
  188|      0|                    unsigned bufferSize = fileInfo.uncompressed_size < INT16_MAX ? static_cast<unsigned>(fileInfo.uncompressed_size) : INT16_MAX;
  ------------------
  |  Branch (188:43): [True: 0, False: 0]
  ------------------
  189|      0|                    void *buffer = malloc(bufferSize);
  190|      0|                    read = unzReadCurrentFile(zip, buffer, bufferSize);
  191|      0|                    if (read > 0) {
  ------------------
  |  Branch (191:25): [True: 0, False: 0]
  ------------------
  192|      0|                        memcpy((char *)buff + total, buffer, read);
  193|      0|                        total += read;
  194|      0|                    }
  195|      0|                    free(buffer);
  196|      0|                } while (read > 0);
  ------------------
  |  Branch (196:26): [True: 0, False: 0]
  ------------------
  197|      0|                size_t filesize = fileInfo.uncompressed_size;
  198|      0|                if (total == 0 || size_t(total) != filesize) {
  ------------------
  |  Branch (198:21): [True: 0, False: 0]
  |  Branch (198:35): [True: 0, False: 0]
  ------------------
  199|      0|                    delete[] buff;
  200|      0|                    ThrowException("Failed to decompress IFC ZIP file");
  201|      0|                }
  202|      0|                unzCloseCurrentFile(zip);
  203|      0|                stream = std::make_shared<MemoryIOStream>(buff, fileInfo.uncompressed_size, true);
  204|      0|                if (unzGoToNextFile(zip) == UNZ_END_OF_LIST_OF_FILE) {
  ------------------
  |  |   75|      0|#define UNZ_END_OF_LIST_OF_FILE         (-100)
  ------------------
  |  Branch (204:21): [True: 0, False: 0]
  ------------------
  205|      0|                    ThrowException("Found no IFC file member in IFCZIP file (1)");
  206|      0|                }
  207|      0|                break;
  208|       |
  209|      0|            } while (true);
  ------------------
  |  Branch (209:22): [True: 0, Folded]
  ------------------
  210|      0|        } else {
  211|      0|            ThrowException("Found no IFC file member in IFCZIP file (2)");
  212|      0|        }
  213|       |
  214|      0|        unzClose(zip);
  215|       |#else
  216|       |        ThrowException("Could not open ifczip file for reading, assimp was built without ifczip support");
  217|       |#endif
  218|      0|    }
  219|       |
  220|      3|    std::unique_ptr<STEP::DB> db(STEP::ReadFileHeader(std::move(stream)));
  221|      3|    const STEP::HeaderInfo &head = static_cast<const STEP::DB &>(*db).GetHeader();
  222|       |
  223|      3|    if (!head.fileSchema.size() || head.fileSchema.substr(0, 4) != "IFC2") {
  ------------------
  |  Branch (223:9): [True: 3, False: 0]
  |  Branch (223:9): [True: 1, False: 2]
  |  Branch (223:36): [True: 0, False: 0]
  ------------------
  224|      1|        ThrowException("Unrecognized file schema: " + head.fileSchema);
  225|      1|    }
  226|       |
  227|      3|    if (!DefaultLogger::isNullLogger()) {
  ------------------
  |  Branch (227:9): [True: 0, False: 3]
  ------------------
  228|      0|        LogDebug("File schema is \'", head.fileSchema, '\'');
  229|      0|        if (head.timestamp.length()) {
  ------------------
  |  Branch (229:13): [True: 0, False: 0]
  ------------------
  230|      0|            LogDebug("Timestamp \'", head.timestamp, '\'');
  231|      0|        }
  232|      0|        if (head.app.length()) {
  ------------------
  |  Branch (232:13): [True: 0, False: 0]
  ------------------
  233|      0|            LogDebug("Application/Exporter identline is \'", head.app, '\'');
  234|      0|        }
  235|      0|    }
  236|       |
  237|       |    // obtain a copy of the machine-generated IFC scheme
  238|      3|    ::Assimp::STEP::EXPRESS::ConversionSchema schema;
  239|      3|    Schema_2x3::GetSchema(schema);
  240|       |
  241|       |    // tell the reader which entity types to track with special care
  242|      3|    static const char *const types_to_track[] = {
  243|      3|        "ifcsite", "ifcbuilding", "ifcproject"
  244|      3|    };
  245|       |
  246|       |    // tell the reader for which types we need to simulate STEPs reverse indices
  247|      3|    static const char *const inverse_indices_to_track[] = {
  248|      3|        "ifcrelcontainedinspatialstructure",
  249|      3|        "ifcrelaggregates",
  250|      3|        "ifcrelvoidselement",
  251|      3|        "ifcreldefinesbyproperties",
  252|      3|        "ifcpropertyset",
  253|      3|        "ifcstyleditem"
  254|      3|    };
  255|       |
  256|       |    // feed the IFC schema into the reader and pre-parse all lines
  257|      3|    STEP::ReadFile(*db, schema, types_to_track, inverse_indices_to_track);
  258|      3|    const STEP::LazyObject *proj = db->GetObject("ifcproject");
  259|      3|    if (!proj) {
  ------------------
  |  Branch (259:9): [True: 0, False: 3]
  ------------------
  260|      0|        ThrowException("missing IfcProject entity");
  261|      0|    }
  262|       |
  263|      3|    ConversionData conv(*db, proj->To<Schema_2x3::IfcProject>(), pScene, settings);
  264|      3|    SetUnits(conv);
  265|      3|    SetCoordinateSpace(conv);
  266|      3|    ProcessSpatialStructures(conv);
  267|      3|    MakeTreeRelative(conv);
  268|       |
  269|       |// NOTE - this is a stress test for the importer, but it works only
  270|       |// in a build with no entities disabled. See
  271|       |//     scripts/IFCImporter/CPPGenerator.py
  272|       |// for more information.
  273|       |#ifdef ASSIMP_IFC_TEST
  274|       |    db->EvaluateAll();
  275|       |#endif
  276|       |
  277|       |    // do final data copying
  278|      3|    if (conv.meshes.size()) {
  ------------------
  |  Branch (278:9): [True: 0, False: 3]
  ------------------
  279|      0|        pScene->mNumMeshes = static_cast<unsigned int>(conv.meshes.size());
  280|      0|        pScene->mMeshes = new aiMesh *[pScene->mNumMeshes]();
  281|      0|        std::copy(conv.meshes.begin(), conv.meshes.end(), pScene->mMeshes);
  282|       |
  283|       |        // needed to keep the d'tor from burning us
  284|      0|        conv.meshes.clear();
  285|      0|    }
  286|       |
  287|      3|    if (conv.materials.size()) {
  ------------------
  |  Branch (287:9): [True: 0, False: 3]
  ------------------
  288|      0|        pScene->mNumMaterials = static_cast<unsigned int>(conv.materials.size());
  289|      0|        pScene->mMaterials = new aiMaterial *[pScene->mNumMaterials]();
  290|      0|        std::copy(conv.materials.begin(), conv.materials.end(), pScene->mMaterials);
  291|       |
  292|       |        // needed to keep the d'tor from burning us
  293|      0|        conv.materials.clear();
  294|      0|    }
  295|       |
  296|       |    // apply world coordinate system (which includes the scaling to convert to meters and a -90 degrees rotation around x)
  297|      3|    aiMatrix4x4 scale, rot;
  298|      3|    aiMatrix4x4::Scaling(static_cast<aiVector3D>(IfcVector3(conv.len_scale)), scale);
  299|      3|    aiMatrix4x4::RotationX(-AI_MATH_HALF_PI_F, rot);
  300|       |
  301|      3|    pScene->mRootNode->mTransformation = rot * scale * conv.wcs * pScene->mRootNode->mTransformation;
  302|       |
  303|       |    // this must be last because objects are evaluated lazily as we process them
  304|      3|    if (!DefaultLogger::isNullLogger()) {
  ------------------
  |  Branch (304:9): [True: 0, False: 3]
  ------------------
  305|      0|        LogDebug("STEP: evaluated ", db->GetEvaluatedObjectCount(), " object records");
  306|      0|    }
  307|      3|}

_ZN6Assimp11IFCImporterC2Ev:
   89|    624|    IFCImporter() = default;
_ZN6Assimp11IFCImporter8SettingsC2Ev:
   80|    624|                skipSpaceRepresentations(), useCustomTriangulation(), skipAnnotations(), conicSamplingAngle(10.f), cylindricalTessellation(32) {}

_ZN6Assimp11IQMImporterC2Ev:
   87|    624|        mScene(nullptr) {
   88|       |    // empty
   89|    624|}
_ZNK6Assimp11IQMImporter7CanReadERKNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEPNS_8IOSystemEb:
   93|     43|bool IQMImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool checkSig) const {
   94|     43|    const std::string extension = GetExtension(pFile);
   95|       |
   96|     43|    if (extension == "iqm")
  ------------------
  |  Branch (96:9): [True: 0, False: 43]
  ------------------
   97|      0|        return true;
   98|     43|    else if (!extension.length() || checkSig) {
  ------------------
  |  Branch (98:14): [True: 43, False: 0]
  |  Branch (98:37): [True: 0, False: 0]
  ------------------
   99|     43|        if (!pIOHandler) {
  ------------------
  |  Branch (99:13): [True: 0, False: 43]
  ------------------
  100|      0|            return true;
  101|      0|        }
  102|     43|        std::unique_ptr<IOStream> pStream(pIOHandler->Open(pFile, "rb"));
  103|     43|        unsigned char data[15];
  104|     43|        if (!pStream || 15 != pStream->Read(data, 1, 15)) {
  ------------------
  |  Branch (104:13): [True: 0, False: 43]
  |  Branch (104:25): [True: 0, False: 43]
  ------------------
  105|      0|            return false;
  106|      0|        }
  107|     43|        return !memcmp(data, "INTERQUAKEMODEL", 15);
  108|     43|    }
  109|      0|    return false;
  110|     43|}
_ZNK6Assimp11IQMImporter7GetInfoEv:
  113|    635|const aiImporterDesc *IQMImporter::GetInfo() const {
  114|    635|    return &desc;
  115|    635|}
_ZN6Assimp11IQMImporter14InternReadFileERKNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEP7aiScenePNS_8IOSystemE:
  119|      1|void IQMImporter::InternReadFile(const std::string &file, aiScene *pScene, IOSystem *pIOHandler) {
  120|       |    // Read file into memory
  121|      1|    std::unique_ptr<IOStream> pStream(pIOHandler->Open(file, "rb"));
  122|      1|    if (!pStream) {
  ------------------
  |  Branch (122:9): [True: 0, False: 1]
  ------------------
  123|      0|        throw DeadlyImportError("Failed to open file ", file, ".");
  124|      0|    }
  125|       |
  126|       |    // Get the file-size and validate it, throwing an exception when fails
  127|      1|    const size_t fileSize = pStream->FileSize();
  128|      1|    if (fileSize < sizeof( iqmheader )) {
  ------------------
  |  Branch (128:9): [True: 0, False: 1]
  ------------------
  129|      0|        throw DeadlyImportError("IQM-file ", file, " is too small.");
  130|      0|    }
  131|      1|    std::vector<unsigned char> buffer(fileSize);
  132|      1|    unsigned char *data = buffer.data();
  133|      1|    if (fileSize != pStream->Read(data, 1, fileSize)) {
  ------------------
  |  Branch (133:9): [True: 0, False: 1]
  ------------------
  134|      0|        throw DeadlyImportError("Failed to read the file ", file, ".");
  135|      0|    }
  136|       |
  137|       |    // get header
  138|      1|    iqmheader &hdr = reinterpret_cast<iqmheader&>( *data );
  139|      1|    swap_block( &hdr.version, sizeof( iqmheader ) - sizeof( iqmheader::magic ) );
  140|       |
  141|       |    // extra check for header
  142|      1|    if (memcmp(data, IQM_MAGIC, sizeof( IQM_MAGIC ) )
  ------------------
  |  |    4|      1|#define IQM_MAGIC "INTERQUAKEMODEL"
  ------------------
                  if (memcmp(data, IQM_MAGIC, sizeof( IQM_MAGIC ) )
  ------------------
  |  |    4|      1|#define IQM_MAGIC "INTERQUAKEMODEL"
  ------------------
  |  Branch (142:9): [True: 0, False: 1]
  ------------------
  143|      1|     || hdr.version != IQM_VERSION
  ------------------
  |  |    5|      2|#define IQM_VERSION 2
  ------------------
  |  Branch (143:9): [True: 0, False: 1]
  ------------------
  144|      1|     || hdr.filesize != fileSize) {
  ------------------
  |  Branch (144:9): [True: 0, False: 1]
  ------------------
  145|      0|        throw DeadlyImportError("Bad binary header in file ", file, ".");
  146|      0|    }
  147|       |
  148|      1|    ASSIMP_LOG_DEBUG("IQM: loading ", file);
  149|       |
  150|       |    // create the root node
  151|      1|    pScene->mRootNode = new aiNode( "<IQMRoot>" );
  152|       |    // Now rotate the whole scene 90 degrees around the x axis to convert to internal coordinate system
  153|      1|    pScene->mRootNode->mTransformation = aiMatrix4x4(
  154|      1|            1.f, 0.f, 0.f, 0.f,
  155|      1|            0.f, 0.f, 1.f, 0.f,
  156|      1|            0.f, -1.f, 0.f, 0.f,
  157|      1|            0.f, 0.f, 0.f, 1.f);
  158|      1|    pScene->mRootNode->mNumMeshes = hdr.num_meshes;
  159|      1|    pScene->mRootNode->mMeshes = new unsigned int[hdr.num_meshes];
  160|      1|    std::iota( pScene->mRootNode->mMeshes, pScene->mRootNode->mMeshes + pScene->mRootNode->mNumMeshes, 0 );
  161|       |
  162|      1|    mScene = pScene;
  163|       |
  164|       |    // Allocate output storage
  165|      1|    pScene->mNumMeshes = 0;
  166|      1|    pScene->mMeshes = new aiMesh *[hdr.num_meshes](); // Set arrays to zero to ensue proper destruction if an exception is raised
  167|       |
  168|      1|    pScene->mNumMaterials = 0;
  169|      1|    pScene->mMaterials = new aiMaterial *[hdr.num_meshes]();
  170|       |
  171|       |    // swap vertex arrays beforehand...
  172|      7|    for( auto array = reinterpret_cast<iqmvertexarray*>( data + hdr.ofs_vertexarrays ), end = array + hdr.num_vertexarrays; array != end; ++array )
  ------------------
  |  Branch (172:125): [True: 6, False: 1]
  ------------------
  173|      6|    {
  174|      6|        swap_block( &array->type, sizeof( iqmvertexarray ) );
  175|      6|    }
  176|       |
  177|       |    // Read all surfaces from the file
  178|      3|    for( auto imesh = reinterpret_cast<iqmmesh*>( data + hdr.ofs_meshes ), end_ = imesh + hdr.num_meshes; imesh != end_; ++imesh )
  ------------------
  |  Branch (178:107): [True: 2, False: 1]
  ------------------
  179|      2|    {
  180|      2|        swap_block( &imesh->name, sizeof( iqmmesh ) );
  181|       |        // Allocate output mesh & material
  182|      2|        auto mesh = pScene->mMeshes[pScene->mNumMeshes++] = new aiMesh();
  183|      2|        mesh->mMaterialIndex = pScene->mNumMaterials;
  184|      2|        auto mat = pScene->mMaterials[pScene->mNumMaterials++] = new aiMaterial();
  185|       |
  186|      2|        {
  187|      2|            auto text = reinterpret_cast<char*>( data + hdr.ofs_text );
  188|      2|            aiString name( text + imesh->material );
  189|      2|            mat->AddProperty( &name, AI_MATKEY_NAME );
  190|      2|            mat->AddProperty( &name, AI_MATKEY_TEXTURE_DIFFUSE(0) );
  191|      2|        }
  192|       |
  193|       |        // Fill mesh information
  194|      2|        mesh->mPrimitiveTypes = aiPrimitiveType_TRIANGLE;
  195|      2|        mesh->mNumFaces = 0;
  196|      2|        mesh->mFaces = new aiFace[imesh->num_triangles];
  197|       |
  198|       |        // Fill in all triangles
  199|  2.99k|        for( auto tri = reinterpret_cast<iqmtriangle*>( data + hdr.ofs_triangles ) + imesh->first_triangle, end = tri + imesh->num_triangles; tri != end; ++tri )
  ------------------
  |  Branch (199:143): [True: 2.98k, False: 2]
  ------------------
  200|  2.98k|        {
  201|  2.98k|            swap_block( tri->vertex, sizeof( tri->vertex ) );
  202|  2.98k|            auto& face = mesh->mFaces[mesh->mNumFaces++];
  203|  2.98k|            face.mNumIndices = 3;
  204|  2.98k|            face.mIndices = new unsigned int[3]{ tri->vertex[0] - imesh->first_vertex,
  205|  2.98k|                                                 tri->vertex[2] - imesh->first_vertex,
  206|  2.98k|                                                 tri->vertex[1] - imesh->first_vertex };
  207|  2.98k|        }
  208|       |
  209|       |        // Fill in all vertices
  210|     14|        for( auto array = reinterpret_cast<const iqmvertexarray*>( data + hdr.ofs_vertexarrays ), end__ = array + hdr.num_vertexarrays; array != end__; ++array )
  ------------------
  |  Branch (210:137): [True: 12, False: 2]
  ------------------
  211|     12|        {
  212|     12|            const unsigned int nVerts = imesh->num_vertexes;
  213|     12|            const unsigned int step = array->size;
  214|       |
  215|     12|            switch ( array->type )
  216|     12|            {
  217|      2|            case IQM_POSITION:
  ------------------
  |  Branch (217:13): [True: 2, False: 10]
  ------------------
  218|      2|                if( array->format == IQM_FLOAT && step >= 3 ){
  ------------------
  |  Branch (218:21): [True: 2, False: 0]
  |  Branch (218:51): [True: 2, False: 0]
  ------------------
  219|      2|                    mesh->mNumVertices = nVerts;
  220|      2|                    auto v = mesh->mVertices = new aiVector3D[nVerts];
  221|      2|                    for( auto f = reinterpret_cast<const float*>( data + array->offset ) + imesh->first_vertex * step,
  222|  1.86k|                        end = f + nVerts * step; f != end; f += step, ++v )
  ------------------
  |  Branch (222:50): [True: 1.86k, False: 2]
  ------------------
  223|  1.86k|                    {
  224|  1.86k|                        *v = { AI_BE( f[0] ),
  225|  1.86k|                               AI_BE( f[1] ),
  226|  1.86k|                               AI_BE( f[2] ) };
  227|  1.86k|                    }
  228|      2|                }
  229|      2|                break;
  230|      2|               case IQM_TEXCOORD:
  ------------------
  |  Branch (230:16): [True: 2, False: 10]
  ------------------
  231|      2|                if( array->format == IQM_FLOAT && step >= 2)
  ------------------
  |  Branch (231:21): [True: 2, False: 0]
  |  Branch (231:51): [True: 2, False: 0]
  ------------------
  232|      2|                {
  233|      2|                    auto v = mesh->mTextureCoords[0] = new aiVector3D[nVerts];
  234|      2|                    mesh->mNumUVComponents[0] = 2;
  235|      2|                    for( auto f = reinterpret_cast<const float*>( data + array->offset ) + imesh->first_vertex * step,
  236|  1.86k|                        end = f + nVerts * step; f != end; f += step, ++v )
  ------------------
  |  Branch (236:50): [True: 1.86k, False: 2]
  ------------------
  237|  1.86k|                    {
  238|  1.86k|                        *v = { AI_BE( f[0] ),
  239|  1.86k|                           1 - AI_BE( f[1] ), 0 };
  240|  1.86k|                    }
  241|      2|                }
  242|      2|                break;
  243|      2|            case IQM_NORMAL:
  ------------------
  |  Branch (243:13): [True: 2, False: 10]
  ------------------
  244|      2|                if (array->format == IQM_FLOAT && step >= 3)
  ------------------
  |  Branch (244:21): [True: 2, False: 0]
  |  Branch (244:51): [True: 2, False: 0]
  ------------------
  245|      2|                {
  246|      2|                    auto v = mesh->mNormals = new aiVector3D[nVerts];
  247|      2|                    for( auto f = reinterpret_cast<const float*>( data + array->offset ) + imesh->first_vertex * step,
  248|  1.86k|                        end = f + nVerts * step; f != end; f += step, ++v )
  ------------------
  |  Branch (248:50): [True: 1.86k, False: 2]
  ------------------
  249|  1.86k|                    {
  250|  1.86k|                        *v = { AI_BE( f[0] ),
  251|  1.86k|                               AI_BE( f[1] ),
  252|  1.86k|                               AI_BE( f[2] ) };
  253|  1.86k|                    }
  254|      2|                }
  255|      2|                break;
  256|      0|            case IQM_COLOR:
  ------------------
  |  Branch (256:13): [True: 0, False: 12]
  ------------------
  257|      0|                if (array->format == IQM_UBYTE && step >= 3)
  ------------------
  |  Branch (257:21): [True: 0, False: 0]
  |  Branch (257:51): [True: 0, False: 0]
  ------------------
  258|      0|                {
  259|      0|                    auto v = mesh->mColors[0] = new aiColor4D[nVerts];
  260|      0|                    for( auto f = ( data + array->offset ) + imesh->first_vertex * step,
  261|      0|                        end = f + nVerts * step; f != end; f += step, ++v )
  ------------------
  |  Branch (261:50): [True: 0, False: 0]
  ------------------
  262|      0|                    {
  263|      0|                        *v = { ( f[0] ) / 255.f,
  264|      0|                               ( f[1] ) / 255.f,
  265|      0|                               ( f[2] ) / 255.f,
  266|      0|                               step == 3? 1 : ( f[3] ) / 255.f };
  ------------------
  |  Branch (266:32): [True: 0, False: 0]
  ------------------
  267|      0|                    }
  268|      0|                }
  269|      0|                else if (array->format == IQM_FLOAT && step >= 3)
  ------------------
  |  Branch (269:26): [True: 0, False: 0]
  |  Branch (269:56): [True: 0, False: 0]
  ------------------
  270|      0|                {
  271|      0|                    auto v = mesh->mColors[0] = new aiColor4D[nVerts];
  272|      0|                    for( auto f = reinterpret_cast<const float*>( data + array->offset ) + imesh->first_vertex * step,
  273|      0|                        end = f + nVerts * step; f != end; f += step, ++v )
  ------------------
  |  Branch (273:50): [True: 0, False: 0]
  ------------------
  274|      0|                    {
  275|      0|                        *v = { AI_BE( f[0] ),
  276|      0|                               AI_BE( f[1] ),
  277|      0|                               AI_BE( f[2] ),
  278|      0|                               step == 3? 1 : AI_BE( f[3] ) };
  ------------------
  |  Branch (278:32): [True: 0, False: 0]
  ------------------
  279|      0|                    }
  280|      0|                }
  281|      0|                break;
  282|      2|            case IQM_TANGENT:
  ------------------
  |  Branch (282:13): [True: 2, False: 10]
  ------------------
  283|       |#if 0
  284|       |                if (array->format == IQM_FLOAT && step >= 3)
  285|       |                {
  286|       |                    auto v = mesh->mTangents = new aiVector3D[nVerts];
  287|       |                    for( auto f = reinterpret_cast<const float*>( data + array->offset ) + imesh->first_vertex * step,
  288|       |                        end = f + nVerts * step; f != end; f += step, ++v )
  289|       |                    {
  290|       |                        *v = { AI_BE( f[0] ),
  291|       |                               AI_BE( f[1] ),
  292|       |                               AI_BE( f[2] ) };
  293|       |                    }
  294|       |                }
  295|       |#endif
  296|      2|                break;
  297|      2|            case IQM_BLENDINDEXES:
  ------------------
  |  Branch (297:13): [True: 2, False: 10]
  ------------------
  298|      4|            case IQM_BLENDWEIGHTS:
  ------------------
  |  Branch (298:13): [True: 2, False: 10]
  ------------------
  299|      4|            case IQM_CUSTOM:
  ------------------
  |  Branch (299:13): [True: 0, False: 12]
  ------------------
  300|      4|                break; // these attributes are not relevant.
  301|       |
  302|      0|            default:
  ------------------
  |  Branch (302:13): [True: 0, False: 12]
  ------------------
  303|      0|                break;
  304|     12|            }
  305|     12|        }
  306|      2|    }
  307|      1|}
_Z10swap_blockPjm:
   62|  2.99k|inline void swap_block( uint32_t *block, size_t size ){
   63|  2.99k|    (void)block; // suppress 'unreferenced formal parameter' MSVC warning
   64|  2.99k|    size >>= 2;
   65|  12.0k|    for ( size_t i = 0; i < size; ++i )
  ------------------
  |  Branch (65:25): [True: 9.03k, False: 2.99k]
  ------------------
   66|  9.03k|        AI_SWAP4( block[ i ] );
   67|  2.99k|}

_ZN6Assimp11IRRImporterC2Ev:
   85|    624|        fps(), configSpeedFlag() {
   86|       |    // empty
   87|    624|}
_ZN6Assimp11IRRImporterD2Ev:
   91|    624|IRRImporter::~IRRImporter() = default;
_ZNK6Assimp11IRRImporter7CanReadERKNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEPNS_8IOSystemEb:
   95|    340|bool IRRImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool /*checkSig*/) const {
   96|    340|    static const char *tokens[] = { "irr_scene" };
   97|       |    return SearchFileHeaderForToken(pIOHandler, pFile, tokens, AI_COUNT_OF(tokens));
   98|    340|}
_ZNK6Assimp11IRRImporter7GetInfoEv:
  101|    645|const aiImporterDesc *IRRImporter::GetInfo() const {
  102|    645|    return &desc;
  103|    645|}
_ZN6Assimp11IRRImporter15SetupPropertiesEPKNS_8ImporterE:
  106|     11|void IRRImporter::SetupProperties(const Importer *pImp) {
  107|       |    // read the output frame rate of all node animation channels
  108|     11|    fps = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_IRR_ANIM_FPS, 100);
  109|     11|    if (fps < 10.) {
  ------------------
  |  Branch (109:9): [True: 0, False: 11]
  ------------------
  110|      0|        ASSIMP_LOG_ERROR("IRR: Invalid FPS configuration");
  111|      0|        fps = 100;
  112|      0|    }
  113|       |
  114|       |    // AI_CONFIG_FAVOUR_SPEED
  115|       |    configSpeedFlag = (0 != pImp->GetPropertyInteger(AI_CONFIG_FAVOUR_SPEED, 0));
  116|     11|}
_ZN6Assimp11IRRImporter12CopyMaterialERNSt3__16vectorIP10aiMaterialNS1_9allocatorIS4_EEEERNS2_INS1_4pairIS4_jEENS5_ISA_EEEERjP6aiMesh:
  237|     13|        aiMesh *mesh) {
  238|     13|    if (inmaterials.empty()) {
  ------------------
  |  Branch (238:9): [True: 0, False: 13]
  ------------------
  239|       |        // Do we have a default material? If not we need to create one
  240|      0|        if (UINT_MAX == defMatIdx) {
  ------------------
  |  Branch (240:13): [True: 0, False: 0]
  ------------------
  241|      0|            defMatIdx = (unsigned int)materials.size();
  242|       |            // TODO: add this materials to someone?
  243|       |            /*aiMaterial* mat = new aiMaterial();
  244|       |
  245|       |            aiString s;
  246|       |            s.Set(AI_DEFAULT_MATERIAL_NAME);
  247|       |            mat->AddProperty(&s,AI_MATKEY_NAME);
  248|       |
  249|       |            aiColor3D c(0.6f,0.6f,0.6f);
  250|       |            mat->AddProperty(&c,1,AI_MATKEY_COLOR_DIFFUSE);*/
  251|      0|        }
  252|      0|        mesh->mMaterialIndex = defMatIdx;
  253|      0|        return;
  254|     13|    } else if (inmaterials.size() > 1) {
  ------------------
  |  Branch (254:16): [True: 0, False: 13]
  ------------------
  255|      0|        ASSIMP_LOG_INFO("IRR: Skipping additional materials");
  256|      0|    }
  257|       |
  258|     13|    mesh->mMaterialIndex = (unsigned int)materials.size();
  259|     13|    materials.push_back(inmaterials[0].first);
  260|     13|}
_ZN6Assimp11IRRImporter17ComputeAnimationsEPNS0_4NodeEP6aiNodeRNSt3__16vectorIP10aiNodeAnimNS5_9allocatorIS8_EEEE:
  280|     71|void IRRImporter::ComputeAnimations(Node *root, aiNode *real, std::vector<aiNodeAnim *> &anims) {
  281|     71|    ai_assert(nullptr != root && nullptr != real);
  282|       |
  283|       |    // XXX totally WIP - doesn't produce proper results, need to evaluate
  284|       |    // whether there's any use for Irrlicht's proprietary scene format
  285|       |    // outside Irrlicht ...
  286|       |    // This also applies to the above function of FindSuitableMultiple and ClampSpline which are
  287|       |    // solely used in this function
  288|       |
  289|     71|    if (root->animators.empty()) {
  ------------------
  |  Branch (289:9): [True: 59, False: 12]
  ------------------
  290|     59|        return;
  291|     59|    }
  292|     12|    unsigned int total(0);
  293|     24|    for (std::list<Animator>::iterator it = root->animators.begin(); it != root->animators.end(); ++it) {
  ------------------
  |  Branch (293:70): [True: 12, False: 12]
  ------------------
  294|     12|        if ((*it).type == Animator::UNKNOWN || (*it).type == Animator::OTHER) {
  ------------------
  |  Branch (294:13): [True: 0, False: 12]
  |  Branch (294:48): [True: 0, False: 12]
  ------------------
  295|      0|            ASSIMP_LOG_WARN("IRR: Skipping unknown or unsupported animator");
  296|      0|            continue;
  297|      0|        }
  298|     12|        ++total;
  299|     12|    }
  300|     12|    if (!total) {
  ------------------
  |  Branch (300:9): [True: 0, False: 12]
  ------------------
  301|      0|        return;
  302|     12|    } else if (1 == total) {
  ------------------
  |  Branch (302:16): [True: 12, False: 0]
  ------------------
  303|     12|        ASSIMP_LOG_WARN("IRR: Adding dummy nodes to simulate multiple animators");
  304|     12|    }
  305|       |
  306|       |    // NOTE: 1 tick == i millisecond
  307|       |
  308|     12|    unsigned int cur = 0;
  309|     12|    for (std::list<Animator>::iterator it = root->animators.begin();
  310|     24|            it != root->animators.end(); ++it) {
  ------------------
  |  Branch (310:13): [True: 12, False: 12]
  ------------------
  311|     12|        if ((*it).type == Animator::UNKNOWN || (*it).type == Animator::OTHER) continue;
  ------------------
  |  Branch (311:13): [True: 0, False: 12]
  |  Branch (311:48): [True: 0, False: 12]
  ------------------
  312|       |
  313|     12|        Animator &in = *it;
  314|     12|        aiNodeAnim *anim = new aiNodeAnim();
  315|       |
  316|     12|        if (cur != total - 1) {
  ------------------
  |  Branch (316:13): [True: 0, False: 12]
  ------------------
  317|       |            // Build a new name - a prefix instead of a suffix because it is
  318|       |            // easier to check against
  319|      0|            anim->mNodeName.length = ::ai_snprintf(anim->mNodeName.data, AI_MAXLEN,
  320|      0|                    "$INST_DUMMY_%i_%s", total - 1,
  321|      0|                    (root->name.length() ? root->name.c_str() : ""));
  ------------------
  |  Branch (321:22): [True: 0, False: 0]
  ------------------
  322|       |
  323|       |            // we'll also need to insert a dummy in the node hierarchy.
  324|      0|            aiNode *dummy = new aiNode();
  325|       |
  326|      0|            for (unsigned int i = 0; i < real->mParent->mNumChildren; ++i)
  ------------------
  |  Branch (326:38): [True: 0, False: 0]
  ------------------
  327|      0|                if (real->mParent->mChildren[i] == real)
  ------------------
  |  Branch (327:21): [True: 0, False: 0]
  ------------------
  328|      0|                    real->mParent->mChildren[i] = dummy;
  329|       |
  330|      0|            dummy->mParent = real->mParent;
  331|      0|            dummy->mName = anim->mNodeName;
  332|       |
  333|      0|            dummy->mNumChildren = 1;
  334|      0|            dummy->mChildren = new aiNode *[dummy->mNumChildren];
  335|      0|            dummy->mChildren[0] = real;
  336|       |
  337|       |            // the transformation matrix of the dummy node is the identity
  338|       |
  339|      0|            real->mParent = dummy;
  340|      0|        } else
  341|     12|            anim->mNodeName.Set(root->name);
  342|     12|        ++cur;
  343|       |
  344|     12|        switch (in.type) {
  345|      6|        case Animator::ROTATION: {
  ------------------
  |  Branch (345:9): [True: 6, False: 6]
  ------------------
  346|       |            // -----------------------------------------------------
  347|       |            // find out how long a full rotation will take
  348|       |            // This is the least common multiple of 360.f and all
  349|       |            // three euler angles. Although we'll surely find a
  350|       |            // possible multiple (haha) it could be somewhat large
  351|       |            // for our purposes. So we need to modify the angles
  352|       |            // here in order to get good results.
  353|       |            // -----------------------------------------------------
  354|      6|            int angles[3];
  355|      6|            angles[0] = (int)(in.direction.x * 100);
  356|      6|            angles[1] = (int)(in.direction.y * 100);
  357|      6|            angles[2] = (int)(in.direction.z * 100);
  358|       |
  359|      6|            angles[0] %= 360;
  360|      6|            angles[1] %= 360;
  361|      6|            angles[2] %= 360;
  362|       |
  363|      6|            if ((angles[0] * angles[1]) != 0 && (angles[1] * angles[2]) != 0) {
  ------------------
  |  Branch (363:17): [True: 4, False: 2]
  |  Branch (363:49): [True: 4, False: 0]
  ------------------
  364|      4|                FindSuitableMultiple(angles[0]);
  365|      4|                FindSuitableMultiple(angles[1]);
  366|      4|                FindSuitableMultiple(angles[2]);
  367|      4|            }
  368|       |
  369|      6|            int lcm = 360;
  370|       |
  371|      6|            if (angles[0])
  ------------------
  |  Branch (371:17): [True: 6, False: 0]
  ------------------
  372|      6|                lcm = Math::lcm(lcm, angles[0]);
  373|       |
  374|      6|            if (angles[1])
  ------------------
  |  Branch (374:17): [True: 4, False: 2]
  ------------------
  375|      4|                lcm = Math::lcm(lcm, angles[1]);
  376|       |
  377|      6|            if (angles[2])
  ------------------
  |  Branch (377:17): [True: 4, False: 2]
  ------------------
  378|      4|                lcm = Math::lcm(lcm, angles[2]);
  379|       |
  380|      6|            if (360 == lcm)
  ------------------
  |  Branch (380:17): [True: 4, False: 2]
  ------------------
  381|      4|                break;
  382|       |
  383|       |            // find out how many time units we'll need for the finest
  384|       |            // track (in seconds) - this defines the number of output
  385|       |            // keys (fps * seconds)
  386|      2|            float max = 0.f;
  387|      2|            if (angles[0])
  ------------------
  |  Branch (387:17): [True: 2, False: 0]
  ------------------
  388|      2|                max = (float)lcm / angles[0];
  389|      2|            if (angles[1])
  ------------------
  |  Branch (389:17): [True: 2, False: 0]
  ------------------
  390|      2|                max = std::max(max, (float)lcm / angles[1]);
  391|      2|            if (angles[2])
  ------------------
  |  Branch (391:17): [True: 2, False: 0]
  ------------------
  392|      2|                max = std::max(max, (float)lcm / angles[2]);
  393|       |
  394|      2|            anim->mNumRotationKeys = (unsigned int)(max * fps);
  395|      2|            anim->mRotationKeys = new aiQuatKey[anim->mNumRotationKeys];
  396|       |
  397|       |            // begin with a zero angle
  398|      2|            aiVector3D angle;
  399|  12.0k|            for (unsigned int i = 0; i < anim->mNumRotationKeys; ++i) {
  ------------------
  |  Branch (399:38): [True: 12.0k, False: 2]
  ------------------
  400|       |                // build the quaternion for the given euler angles
  401|  12.0k|                aiQuatKey &q = anim->mRotationKeys[i];
  402|       |
  403|  12.0k|                q.mValue = aiQuaternion(angle.x, angle.y, angle.z);
  404|  12.0k|                q.mTime = (double)i;
  405|       |
  406|       |                // increase the angle
  407|  12.0k|                angle += in.direction;
  408|  12.0k|            }
  409|       |
  410|       |            // This animation is repeated and repeated ...
  411|      2|            anim->mPostState = anim->mPreState = aiAnimBehaviour_REPEAT;
  412|      2|        } break;
  413|       |
  414|      3|        case Animator::FLY_CIRCLE: {
  ------------------
  |  Branch (414:9): [True: 3, False: 9]
  ------------------
  415|       |            // -----------------------------------------------------
  416|       |            // Find out how much time we'll need to perform a
  417|       |            // full circle.
  418|       |            // -----------------------------------------------------
  419|      3|            const double seconds = (1. / in.speed) / 1000.;
  420|      3|            const double tdelta = 1000. / fps;
  421|       |
  422|      3|            anim->mNumPositionKeys = (unsigned int)(fps * seconds);
  423|      3|            anim->mPositionKeys = new aiVectorKey[anim->mNumPositionKeys];
  424|       |
  425|       |            // from Irrlicht, what else should we do than copying it?
  426|      3|            aiVector3D vecU, vecV;
  427|      3|            if (in.direction.y) {
  ------------------
  |  Branch (427:17): [True: 3, False: 0]
  ------------------
  428|      3|                vecV = aiVector3D(50, 0, 0) ^ in.direction;
  429|      3|            } else
  430|      0|                vecV = aiVector3D(0, 50, 00) ^ in.direction;
  431|      3|            vecV.Normalize();
  432|      3|            vecU = (vecV ^ in.direction).Normalize();
  433|       |
  434|       |            // build the output keys
  435|    300|            for (unsigned int i = 0; i < anim->mNumPositionKeys; ++i) {
  ------------------
  |  Branch (435:38): [True: 297, False: 3]
  ------------------
  436|    297|                aiVectorKey &key = anim->mPositionKeys[i];
  437|    297|                key.mTime = i * tdelta;
  438|       |
  439|    297|                const ai_real t = (ai_real)(in.speed * key.mTime);
  440|    297|                key.mValue = in.circleCenter + in.circleRadius * ((vecU * std::cos(t)) + (vecV * std::sin(t)));
  441|    297|            }
  442|       |
  443|       |            // This animation is repeated and repeated ...
  444|      3|            anim->mPostState = anim->mPreState = aiAnimBehaviour_REPEAT;
  445|      3|        } break;
  446|       |
  447|      0|        case Animator::FLY_STRAIGHT: {
  ------------------
  |  Branch (447:9): [True: 0, False: 12]
  ------------------
  448|      0|            anim->mPostState = anim->mPreState = (in.loop ? aiAnimBehaviour_REPEAT : aiAnimBehaviour_CONSTANT);
  ------------------
  |  Branch (448:51): [True: 0, False: 0]
  ------------------
  449|      0|            const double seconds = in.timeForWay / 1000.;
  450|      0|            const double tdelta = 1000. / fps;
  451|       |
  452|      0|            anim->mNumPositionKeys = (unsigned int)(fps * seconds);
  453|      0|            anim->mPositionKeys = new aiVectorKey[anim->mNumPositionKeys];
  454|       |
  455|      0|            aiVector3D diff = in.direction - in.circleCenter;
  456|      0|            const ai_real lengthOfWay = diff.Length();
  457|      0|            diff.Normalize();
  458|       |
  459|      0|            const double timeFactor = lengthOfWay / in.timeForWay;
  460|       |
  461|       |            // build the output keys
  462|      0|            for (unsigned int i = 0; i < anim->mNumPositionKeys; ++i) {
  ------------------
  |  Branch (462:38): [True: 0, False: 0]
  ------------------
  463|      0|                aiVectorKey &key = anim->mPositionKeys[i];
  464|      0|                key.mTime = i * tdelta;
  465|      0|                key.mValue = in.circleCenter + diff * ai_real(timeFactor * key.mTime);
  466|      0|            }
  467|      0|        } break;
  468|       |
  469|      3|        case Animator::FOLLOW_SPLINE: {
  ------------------
  |  Branch (469:9): [True: 3, False: 9]
  ------------------
  470|       |            // repeat outside the defined time range
  471|      3|            anim->mPostState = anim->mPreState = aiAnimBehaviour_REPEAT;
  472|      3|            const int size = (int)in.splineKeys.size();
  473|      3|            if (!size) {
  ------------------
  |  Branch (473:17): [True: 0, False: 3]
  ------------------
  474|       |                // We have no point in the spline. That's bad. Really bad.
  475|      0|                ASSIMP_LOG_WARN("IRR: Spline animators with no points defined");
  476|       |
  477|      0|                delete anim;
  478|      0|                anim = nullptr;
  479|      0|                break;
  480|      3|            } else if (size == 1) {
  ------------------
  |  Branch (480:24): [True: 0, False: 3]
  ------------------
  481|       |                // We have just one point in the spline so we don't need the full calculation
  482|      0|                anim->mNumPositionKeys = 1;
  483|      0|                anim->mPositionKeys = new aiVectorKey[anim->mNumPositionKeys];
  484|       |
  485|      0|                anim->mPositionKeys[0].mValue = in.splineKeys[0].mValue;
  486|      0|                anim->mPositionKeys[0].mTime = 0.f;
  487|      0|                break;
  488|      0|            }
  489|       |
  490|      3|            unsigned int ticksPerFull = 15;
  491|      3|            anim->mNumPositionKeys = (unsigned int)(ticksPerFull * fps);
  492|      3|            anim->mPositionKeys = new aiVectorKey[anim->mNumPositionKeys];
  493|       |
  494|  4.50k|            for (unsigned int i = 0; i < anim->mNumPositionKeys; ++i) {
  ------------------
  |  Branch (494:38): [True: 4.50k, False: 3]
  ------------------
  495|  4.50k|                aiVectorKey &key = anim->mPositionKeys[i];
  496|       |
  497|  4.50k|                const ai_real dt = (i * in.speed * ai_real(0.001));
  498|  4.50k|                const ai_real u = dt - std::floor(dt);
  499|  4.50k|                const int idx = (int)std::floor(dt) % size;
  500|       |
  501|       |                // get the 4 current points to evaluate the spline
  502|  4.50k|                const aiVector3D &p0 = in.splineKeys[ClampSpline(idx - 1, size)].mValue;
  503|  4.50k|                const aiVector3D &p1 = in.splineKeys[ClampSpline(idx + 0, size)].mValue;
  504|  4.50k|                const aiVector3D &p2 = in.splineKeys[ClampSpline(idx + 1, size)].mValue;
  505|  4.50k|                const aiVector3D &p3 = in.splineKeys[ClampSpline(idx + 2, size)].mValue;
  506|       |
  507|       |                // compute polynomials
  508|  4.50k|                const ai_real u2 = u * u;
  509|  4.50k|                const ai_real u3 = u2 * 2;
  510|       |
  511|  4.50k|                const ai_real h1 = ai_real(2.0) * u3 - ai_real(3.0) * u2 + ai_real(1.0);
  512|  4.50k|                const ai_real h2 = ai_real(-2.0) * u3 + ai_real(3.0) * u3;
  513|  4.50k|                const ai_real h3 = u3 - ai_real(2.0) * u3;
  514|  4.50k|                const ai_real h4 = u3 - u2;
  515|       |
  516|       |                // compute the spline tangents
  517|  4.50k|                const aiVector3D t1 = (p2 - p0) * in.tightness;
  518|  4.50k|                aiVector3D t2 = (p3 - p1) * in.tightness;
  519|       |
  520|       |                // and use them to get the interpolated point
  521|  4.50k|                t2 = (h1 * p1 + p2 * h2 + t1 * h3 + h4 * t2);
  522|       |
  523|       |                // build a simple translation matrix from it
  524|  4.50k|                key.mValue = t2;
  525|  4.50k|                key.mTime = (double)i;
  526|  4.50k|            }
  527|      3|        } break;
  528|      0|        default:
  ------------------
  |  Branch (528:9): [True: 0, False: 12]
  ------------------
  529|       |            // UNKNOWN , OTHER
  530|      0|            break;
  531|     12|        };
  532|     12|        if (anim) {
  ------------------
  |  Branch (532:13): [True: 12, False: 0]
  ------------------
  533|     12|            anims.push_back(anim);
  534|     12|            ++total;
  535|     12|        }
  536|     12|    }
  537|     12|}
_Z12SetupMappingP10aiMaterial16aiTextureMappingRK10aiVector3tIfE:
  541|     13|void SetupMapping(aiMaterial *mat, aiTextureMapping mode, const aiVector3D &axis = aiVector3D(0.f, 0.f, -1.f)) {
  542|     13|    if (nullptr == mat) {
  ------------------
  |  Branch (542:9): [True: 0, False: 13]
  ------------------
  543|      0|        return;
  544|      0|    }
  545|       |
  546|       |    // Check whether there are texture properties defined - setup
  547|       |    // the desired texture mapping mode for all of them and ignore
  548|       |    // all UV settings we might encounter. WE HAVE NO UVS!
  549|       |
  550|     13|    std::vector<aiMaterialProperty *> p;
  551|     13|    p.reserve(mat->mNumProperties + 1);
  552|       |
  553|     13|    for (unsigned int i = 0; i < mat->mNumProperties; ++i) {
  ------------------
  |  Branch (553:30): [True: 0, False: 13]
  ------------------
  554|      0|        aiMaterialProperty *prop = mat->mProperties[i];
  555|      0|        if (!::strcmp(prop->mKey.data, "$tex.file")) {
  ------------------
  |  Branch (555:13): [True: 0, False: 0]
  ------------------
  556|       |            // Setup the mapping key
  557|      0|            aiMaterialProperty *m = new aiMaterialProperty();
  558|      0|            m->mKey.Set("$tex.mapping");
  559|      0|            m->mIndex = prop->mIndex;
  560|      0|            m->mSemantic = prop->mSemantic;
  561|      0|            m->mType = aiPTI_Integer;
  562|       |
  563|      0|            m->mDataLength = 4;
  564|      0|            m->mData = new char[4];
  565|      0|            *((int *)m->mData) = mode;
  566|       |
  567|      0|            p.push_back(prop);
  568|      0|            p.push_back(m);
  569|       |
  570|       |            // Setup the mapping axis
  571|      0|            if (mode == aiTextureMapping_CYLINDER || mode == aiTextureMapping_PLANE || mode == aiTextureMapping_SPHERE) {
  ------------------
  |  Branch (571:17): [True: 0, False: 0]
  |  Branch (571:54): [True: 0, False: 0]
  |  Branch (571:88): [True: 0, False: 0]
  ------------------
  572|      0|                m = new aiMaterialProperty();
  573|      0|                m->mKey.Set("$tex.mapaxis");
  574|      0|                m->mIndex = prop->mIndex;
  575|      0|                m->mSemantic = prop->mSemantic;
  576|      0|                m->mType = aiPTI_Float;
  577|       |
  578|      0|                m->mDataLength = sizeof(aiVector3D);
  579|      0|                m->mData = new char[m->mDataLength];
  580|      0|                *((aiVector3D *)m->mData) = axis;
  581|      0|                p.push_back(m);
  582|      0|            }
  583|      0|        } else if (!::strcmp(prop->mKey.data, "$tex.uvwsrc")) {
  ------------------
  |  Branch (583:20): [True: 0, False: 0]
  ------------------
  584|      0|            delete mat->mProperties[i];
  585|      0|        } else
  586|      0|            p.push_back(prop);
  587|      0|    }
  588|       |
  589|     13|    if (p.empty()) return;
  ------------------
  |  Branch (589:9): [True: 13, False: 0]
  ------------------
  590|       |
  591|       |    // rebuild the output array
  592|      0|    if (p.size() > mat->mNumAllocated) {
  ------------------
  |  Branch (592:9): [True: 0, False: 0]
  ------------------
  593|      0|        delete[] mat->mProperties;
  594|      0|        mat->mProperties = new aiMaterialProperty *[p.size() * 2];
  595|       |
  596|      0|        mat->mNumAllocated = static_cast<unsigned int>(p.size() * 2);
  597|      0|    }
  598|      0|    mat->mNumProperties = (unsigned int)p.size();
  599|      0|    ::memcpy(mat->mProperties, &p[0], sizeof(void *) * mat->mNumProperties);
  600|      0|}
_ZN6Assimp11IRRImporter13GenerateGraphEPNS0_4NodeEP6aiNodeP7aiSceneRNS_11BatchLoaderERNSt3__16vectorIP6aiMeshNS9_9allocatorISC_EEEERNSA_IP10aiNodeAnimNSD_ISI_EEEERNSA_INS_14AttachmentInfoENSD_ISM_EEEERNSA_IP10aiMaterialNSD_ISR_EEEERj:
  609|     71|        unsigned int &defMatIdx) {
  610|     71|    unsigned int oldMeshSize = (unsigned int)meshes.size();
  611|       |    // unsigned int meshTrafoAssign = 0;
  612|       |
  613|       |    // Now determine the type of the node
  614|     71|    switch (root->type) {
  615|      5|    case Node::ANIMMESH:
  ------------------
  |  Branch (615:5): [True: 5, False: 66]
  ------------------
  616|     34|    case Node::MESH: {
  ------------------
  |  Branch (616:5): [True: 29, False: 42]
  ------------------
  617|     34|        if (!root->meshPath.length())
  ------------------
  |  Branch (617:13): [True: 0, False: 34]
  ------------------
  618|      0|            break;
  619|       |
  620|       |        // Get the loaded mesh from the scene and add it to
  621|       |        // the list of all scenes to be attached to the
  622|       |        // graph we're currently building
  623|     34|        aiScene *localScene = batch.GetImport(root->id);
  624|     34|        if (!localScene) {
  ------------------
  |  Branch (624:13): [True: 34, False: 0]
  ------------------
  625|     34|            ASSIMP_LOG_ERROR("IRR: Unable to load external file: ", root->meshPath);
  626|     34|            break;
  627|     34|        }
  628|      0|        attach.emplace_back(localScene, rootOut);
  629|       |
  630|       |        // Now combine the material we've loaded for this mesh
  631|       |        // with the real materials we got from the file. As we
  632|       |        // don't execute any pp-steps on the file, the numbers
  633|       |        // should be equal. If they are not, we can impossibly
  634|       |        // do this  ...
  635|      0|        if (root->materials.size() != (unsigned int)localScene->mNumMaterials) {
  ------------------
  |  Branch (635:13): [True: 0, False: 0]
  ------------------
  636|      0|            ASSIMP_LOG_WARN("IRR: Failed to match imported materials "
  637|      0|                            "with the materials found in the IRR scene file");
  638|       |
  639|      0|            break;
  640|      0|        }
  641|      0|        for (unsigned int i = 0; i < localScene->mNumMaterials; ++i) {
  ------------------
  |  Branch (641:34): [True: 0, False: 0]
  ------------------
  642|       |            // Delete the old material, we don't need it anymore
  643|      0|            delete localScene->mMaterials[i];
  644|       |
  645|      0|            std::pair<aiMaterial *, unsigned int> &src = root->materials[i];
  646|      0|            localScene->mMaterials[i] = src.first;
  647|      0|        }
  648|       |
  649|       |        // NOTE: Each mesh should have exactly one material assigned,
  650|       |        // but we do it in a separate loop if this behavior changes
  651|       |        // in future.
  652|      0|        for (unsigned int i = 0; i < localScene->mNumMeshes; ++i) {
  ------------------
  |  Branch (652:34): [True: 0, False: 0]
  ------------------
  653|       |            // Process material flags
  654|      0|            aiMesh *mesh = localScene->mMeshes[i];
  655|       |
  656|       |            // If "trans_vertex_alpha" mode is enabled, search all vertex colors
  657|       |            // and check whether they have a common alpha value. This is quite
  658|       |            // often the case so we can simply extract it to a shared oacity
  659|       |            // value.
  660|      0|            std::pair<aiMaterial *, unsigned int> &src = root->materials[mesh->mMaterialIndex];
  661|      0|            aiMaterial *mat = (aiMaterial *)src.first;
  662|       |
  663|      0|            if (mesh->HasVertexColors(0) && src.second & AI_IRRMESH_MAT_trans_vertex_alpha) {
  ------------------
  |  |   26|      0|#define AI_IRRMESH_MAT_trans_vertex_alpha 0x1
  ------------------
  |  Branch (663:17): [True: 0, False: 0]
  |  Branch (663:45): [True: 0, False: 0]
  ------------------
  664|      0|                bool bdo = true;
  665|      0|                for (unsigned int a = 1; a < mesh->mNumVertices; ++a) {
  ------------------
  |  Branch (665:42): [True: 0, False: 0]
  ------------------
  666|       |
  667|      0|                    if (mesh->mColors[0][a].a != mesh->mColors[0][a - 1].a) {
  ------------------
  |  Branch (667:25): [True: 0, False: 0]
  ------------------
  668|      0|                        bdo = false;
  669|      0|                        break;
  670|      0|                    }
  671|      0|                }
  672|      0|                if (bdo) {
  ------------------
  |  Branch (672:21): [True: 0, False: 0]
  ------------------
  673|      0|                    ASSIMP_LOG_INFO("IRR: Replacing mesh vertex alpha with common opacity");
  674|       |
  675|      0|                    for (unsigned int a = 0; a < mesh->mNumVertices; ++a)
  ------------------
  |  Branch (675:46): [True: 0, False: 0]
  ------------------
  676|      0|                        mesh->mColors[0][a].a = 1.f;
  677|       |
  678|      0|                    mat->AddProperty(&mesh->mColors[0][0].a, 1, AI_MATKEY_OPACITY);
  679|      0|                }
  680|      0|            }
  681|       |
  682|       |            // If we have a second texture coordinate set and a second texture
  683|       |            // (either light-map, normal-map, 2layered material) we need to
  684|       |            // setup the correct UV index for it. The texture can either
  685|       |            // be diffuse (light-map & 2layer) or a normal map (normal & parallax)
  686|      0|            if (mesh->HasTextureCoords(1)) {
  ------------------
  |  Branch (686:17): [True: 0, False: 0]
  ------------------
  687|       |
  688|      0|                int idx = 1;
  689|      0|                if (src.second & (AI_IRRMESH_MAT_solid_2layer | AI_IRRMESH_MAT_lightmap)) {
  ------------------
  |  |   23|      0|#define AI_IRRMESH_MAT_solid_2layer 0x10000
  ------------------
                              if (src.second & (AI_IRRMESH_MAT_solid_2layer | AI_IRRMESH_MAT_lightmap)) {
  ------------------
  |  |   30|      0|#define AI_IRRMESH_MAT_lightmap 0x2
  ------------------
  |  Branch (689:21): [True: 0, False: 0]
  ------------------
  690|      0|                    mat->AddProperty(&idx, 1, AI_MATKEY_UVWSRC_DIFFUSE(0));
  691|      0|                } else if (src.second & AI_IRRMESH_MAT_normalmap_solid) {
  ------------------
  |  |   39|      0|#define AI_IRRMESH_MAT_normalmap_solid (0x100)
  ------------------
  |  Branch (691:28): [True: 0, False: 0]
  ------------------
  692|      0|                    mat->AddProperty(&idx, 1, AI_MATKEY_UVWSRC_NORMALS(0));
  693|      0|                }
  694|      0|            }
  695|      0|        }
  696|      0|    } break;
  697|       |
  698|      6|    case Node::LIGHT:
  ------------------
  |  Branch (698:5): [True: 6, False: 65]
  ------------------
  699|      9|    case Node::CAMERA:
  ------------------
  |  Branch (699:5): [True: 3, False: 68]
  ------------------
  700|       |
  701|       |        // We're already finished with lights and cameras
  702|      9|        break;
  703|       |
  704|      6|    case Node::SPHERE: {
  ------------------
  |  Branch (704:5): [True: 6, False: 65]
  ------------------
  705|       |        // Generate the sphere model. Our input parameter to
  706|       |        // the sphere generation algorithm is the number of
  707|       |        // subdivisions of each triangle - but here we have
  708|       |        // the number of polygons on a specific axis. Just
  709|       |        // use some hard-coded limits to approximate this ...
  710|      6|        unsigned int mul = root->spherePolyCountX * root->spherePolyCountY;
  711|      6|        if (mul < 100)
  ------------------
  |  Branch (711:13): [True: 0, False: 6]
  ------------------
  712|      0|            mul = 2;
  713|      6|        else if (mul < 300)
  ------------------
  |  Branch (713:18): [True: 6, False: 0]
  ------------------
  714|      6|            mul = 3;
  715|      0|        else
  716|      0|            mul = 4;
  717|       |
  718|      6|        meshes.push_back(StandardShapes::MakeMesh(mul,
  719|      6|                &StandardShapes::MakeSphere));
  720|       |
  721|       |        // Adjust scaling
  722|      6|        root->scaling *= root->sphereRadius / 2;
  723|       |
  724|       |        // Copy one output material
  725|      6|        CopyMaterial(materials, root->materials, defMatIdx, meshes.back());
  726|       |
  727|       |        // Now adjust this output material - if there is a first texture
  728|       |        // set, setup spherical UV mapping around the Y axis.
  729|      6|        SetupMapping((aiMaterial *)materials.back(), aiTextureMapping_SPHERE);
  730|      6|    } break;
  731|       |
  732|      7|    case Node::CUBE: {
  ------------------
  |  Branch (732:5): [True: 7, False: 64]
  ------------------
  733|       |        // Generate an unit cube first
  734|      7|        meshes.push_back(StandardShapes::MakeMesh(
  735|      7|                &StandardShapes::MakeHexahedron));
  736|       |
  737|       |        // Adjust scaling
  738|      7|        root->scaling *= root->sphereRadius;
  739|       |
  740|       |        // Copy one output material
  741|      7|        CopyMaterial(materials, root->materials, defMatIdx, meshes.back());
  742|       |
  743|       |        // Now adjust this output material - if there is a first texture
  744|       |        // set, setup cubic UV mapping
  745|      7|        SetupMapping((aiMaterial *)materials.back(), aiTextureMapping_BOX);
  746|      7|    } break;
  747|       |
  748|      1|    case Node::SKYBOX: {
  ------------------
  |  Branch (748:5): [True: 1, False: 70]
  ------------------
  749|       |        // A sky-box is defined by six materials
  750|      1|        if (root->materials.size() < 6) {
  ------------------
  |  Branch (750:13): [True: 1, False: 0]
  ------------------
  751|      1|            ASSIMP_LOG_ERROR("IRR: There should be six materials for a skybox");
  752|      1|            break;
  753|      1|        }
  754|       |
  755|       |        // copy those materials and generate 6 meshes for our new sky-box
  756|      0|        materials.reserve(materials.size() + 6);
  757|      0|        for (unsigned int i = 0; i < 6; ++i)
  ------------------
  |  Branch (757:34): [True: 0, False: 0]
  ------------------
  758|      0|            materials.insert(materials.end(), root->materials[i].first);
  759|       |
  760|      0|        BuildSkybox(meshes, materials);
  761|       |
  762|       |        // *************************************************************
  763|       |        // Skyboxes will require a different code path for rendering,
  764|       |        // so there must be a way for the user to add special support
  765|       |        // for IRR skyboxes. We add a 'IRR.SkyBox_' prefix to the node.
  766|       |        // *************************************************************
  767|      0|        root->name = "IRR.SkyBox_" + root->name;
  768|      0|        ASSIMP_LOG_INFO("IRR: Loading skybox, this will "
  769|      0|                        "require special handling to be displayed correctly");
  770|      0|    } break;
  771|       |
  772|      0|    case Node::TERRAIN: {
  ------------------
  |  Branch (772:5): [True: 0, False: 71]
  ------------------
  773|       |        // to support terrains, we'd need to have a texture decoder
  774|      0|        ASSIMP_LOG_ERROR("IRR: Unsupported node - TERRAIN");
  775|      0|    } break;
  776|     14|    default:
  ------------------
  |  Branch (776:5): [True: 14, False: 57]
  ------------------
  777|       |        // DUMMY
  778|     14|        break;
  779|     71|    };
  780|       |
  781|       |    // Check whether we added a mesh (or more than one ...). In this case
  782|       |    // we'll also need to attach it to the node
  783|     71|    if (oldMeshSize != (unsigned int)meshes.size()) {
  ------------------
  |  Branch (783:9): [True: 13, False: 58]
  ------------------
  784|       |
  785|     13|        rootOut->mNumMeshes = (unsigned int)meshes.size() - oldMeshSize;
  786|     13|        rootOut->mMeshes = new unsigned int[rootOut->mNumMeshes];
  787|       |
  788|     26|        for (unsigned int a = 0; a < rootOut->mNumMeshes; ++a) {
  ------------------
  |  Branch (788:34): [True: 13, False: 13]
  ------------------
  789|     13|            rootOut->mMeshes[a] = oldMeshSize + a;
  790|     13|        }
  791|     13|    }
  792|       |
  793|       |    // Setup the name of this node
  794|     71|    rootOut->mName.Set(root->name);
  795|       |
  796|       |    // Now compute the final local transformation matrix of the
  797|       |    // node from the given translation, rotation and scaling values.
  798|       |    // (the rotation is given in Euler angles, XYZ order)
  799|       |    // std::swap((float&)root->rotation.z,(float&)root->rotation.y);
  800|     71|    rootOut->mTransformation.FromEulerAnglesXYZ(AI_DEG_TO_RAD(root->rotation));
  801|       |
  802|       |    // apply scaling
  803|     71|    aiMatrix4x4 &mat = rootOut->mTransformation;
  804|     71|    mat.a1 *= root->scaling.x;
  805|     71|    mat.b1 *= root->scaling.x;
  806|     71|    mat.c1 *= root->scaling.x;
  807|     71|    mat.a2 *= root->scaling.y;
  808|     71|    mat.b2 *= root->scaling.y;
  809|     71|    mat.c2 *= root->scaling.y;
  810|     71|    mat.a3 *= root->scaling.z;
  811|     71|    mat.b3 *= root->scaling.z;
  812|     71|    mat.c3 *= root->scaling.z;
  813|       |
  814|       |    // apply translation
  815|     71|    mat.a4 += root->position.x;
  816|     71|    mat.b4 += root->position.y;
  817|     71|    mat.c4 += root->position.z;
  818|       |
  819|       |    // now compute animations for the node
  820|     71|    ComputeAnimations(root, rootOut, anims);
  821|       |
  822|       |    // Add all children recursively. First allocate enough storage
  823|       |    // for them, then call us again
  824|     71|    rootOut->mNumChildren = (unsigned int)root->children.size();
  825|     71|    if (rootOut->mNumChildren) {
  ------------------
  |  Branch (825:9): [True: 14, False: 57]
  ------------------
  826|       |
  827|     14|        rootOut->mChildren = new aiNode *[rootOut->mNumChildren];
  828|     77|        for (unsigned int i = 0; i < rootOut->mNumChildren; ++i) {
  ------------------
  |  Branch (828:34): [True: 63, False: 14]
  ------------------
  829|       |
  830|     63|            aiNode *node = rootOut->mChildren[i] = new aiNode();
  831|     63|            node->mParent = rootOut;
  832|     63|            GenerateGraph(root->children[i], node, scene, batch, meshes,
  833|     63|                    anims, attach, materials, defMatIdx);
  834|     63|        }
  835|     14|    }
  836|     71|}
_ZN6Assimp11IRRImporter19ParseNodeAttributesERN4pugi8xml_nodeEPNS0_4NodeERNS_11BatchLoaderE:
  838|     63|void IRRImporter::ParseNodeAttributes(pugi::xml_node &attributesNode, IRRImporter::Node *nd, BatchLoader &batch) {
  839|     63|    ai_assert(!ASSIMP_stricmp(attributesNode.name(), "attributes")); // Node must be <attributes>
  840|     63|    ai_assert(nd != nullptr); // dude
  841|       |
  842|       |    // Big switch statement that tests for various tags inside <attributes>
  843|       |    // and applies them to nd
  844|       |    // I don't believe nodes have boolean attributes
  845|    729|    for (pugi::xml_node &attribute : attributesNode.children()) {
  ------------------
  |  Branch (845:36): [True: 729, False: 63]
  ------------------
  846|    729|        if (attribute.type() != pugi::node_element) continue;
  ------------------
  |  Branch (846:13): [True: 0, False: 729]
  ------------------
  847|    729|        if (!ASSIMP_stricmp(attribute.name(), "vector3d")) { // <vector3d />
  ------------------
  |  Branch (847:13): [True: 196, False: 533]
  ------------------
  848|    196|            VectorProperty prop;
  849|    196|            ReadVectorProperty(prop, attribute);
  850|    196|            if (prop.name == "Position") {
  ------------------
  |  Branch (850:17): [True: 63, False: 133]
  ------------------
  851|     63|                nd->position = prop.value;
  852|    133|            } else if (prop.name == "Rotation") {
  ------------------
  |  Branch (852:24): [True: 63, False: 70]
  ------------------
  853|     63|                nd->rotation = prop.value;
  854|     70|            } else if (prop.name == "Scale") {
  ------------------
  |  Branch (854:24): [True: 63, False: 7]
  ------------------
  855|     63|                nd->scaling = prop.value;
  856|     63|            } else if (Node::CAMERA == nd->type) {
  ------------------
  |  Branch (856:24): [True: 6, False: 1]
  ------------------
  857|      6|                aiCamera *cam = cameras.back();
  858|      6|                if (prop.name == "Target") {
  ------------------
  |  Branch (858:21): [True: 3, False: 3]
  ------------------
  859|      3|                    cam->mLookAt = prop.value;
  860|      3|                } else if (prop.name == "UpVector") {
  ------------------
  |  Branch (860:28): [True: 3, False: 0]
  ------------------
  861|      3|                    cam->mUp = prop.value;
  862|      3|                }
  863|      6|            }
  864|    533|        } else if (!ASSIMP_stricmp(attribute.name(), "float")) { // <float />
  ------------------
  |  Branch (864:20): [True: 38, False: 495]
  ------------------
  865|     38|            FloatProperty prop;
  866|     38|            ReadFloatProperty(prop, attribute);
  867|     38|            if (prop.name == "FramesPerSecond" && Node::ANIMMESH == nd->type) {
  ------------------
  |  Branch (867:17): [True: 7, False: 31]
  |  Branch (867:51): [True: 5, False: 2]
  ------------------
  868|      5|                nd->framesPerSecond = prop.value;
  869|     33|            } else if (Node::CAMERA == nd->type) {
  ------------------
  |  Branch (869:24): [True: 12, False: 21]
  ------------------
  870|       |                /*  This is the vertical, not the horizontal FOV.
  871|       |                 *  We need to compute the right FOV from the
  872|       |                 *  screen aspect which we don't know yet.
  873|       |                 */
  874|     12|                if (prop.name == "Fovy") {
  ------------------
  |  Branch (874:21): [True: 3, False: 9]
  ------------------
  875|      3|                    cameras.back()->mHorizontalFOV = prop.value;
  876|      9|                } else if (prop.name == "Aspect") {
  ------------------
  |  Branch (876:28): [True: 3, False: 6]
  ------------------
  877|      3|                    cameras.back()->mAspect = prop.value;
  878|      6|                } else if (prop.name == "ZNear") {
  ------------------
  |  Branch (878:28): [True: 3, False: 3]
  ------------------
  879|      3|                    cameras.back()->mClipPlaneNear = prop.value;
  880|      3|                } else if (prop.name == "ZFar") {
  ------------------
  |  Branch (880:28): [True: 3, False: 0]
  ------------------
  881|      3|                    cameras.back()->mClipPlaneFar = prop.value;
  882|      3|                }
  883|     21|            } else if (Node::LIGHT == nd->type) {
  ------------------
  |  Branch (883:24): [True: 6, False: 15]
  ------------------
  884|       |                /*  Additional light information
  885|       |                 */
  886|      6|                if (prop.name == "Attenuation") {
  ------------------
  |  Branch (886:21): [True: 0, False: 6]
  ------------------
  887|      0|                    lights.back()->mAttenuationLinear = prop.value;
  888|      6|                } else if (prop.name == "OuterCone") {
  ------------------
  |  Branch (888:28): [True: 0, False: 6]
  ------------------
  889|      0|                    lights.back()->mAngleOuterCone = AI_DEG_TO_RAD(prop.value);
  890|      6|                } else if (prop.name == "InnerCone") {
  ------------------
  |  Branch (890:28): [True: 0, False: 6]
  ------------------
  891|      0|                    lights.back()->mAngleInnerCone = AI_DEG_TO_RAD(prop.value);
  892|      0|                }
  893|      6|            }
  894|       |            // radius of the sphere to be generated -
  895|       |            // or alternatively, size of the cube
  896|     15|            else if ((Node::SPHERE == nd->type && prop.name == "Radius") ||
  ------------------
  |  Branch (896:23): [True: 6, False: 9]
  |  Branch (896:51): [True: 6, False: 0]
  ------------------
  897|     13|                     (Node::CUBE == nd->type && prop.name == "Size")) {
  ------------------
  |  Branch (897:23): [True: 7, False: 2]
  |  Branch (897:49): [True: 7, False: 0]
  ------------------
  898|     13|                nd->sphereRadius = prop.value;
  899|     13|            }
  900|    495|        } else if (!ASSIMP_stricmp(attribute.name(), "int")) { // <int />
  ------------------
  |  Branch (900:20): [True: 138, False: 357]
  ------------------
  901|       |            // Only sphere nodes make use of integer attributes
  902|    138|            if (Node::SPHERE == nd->type) {
  ------------------
  |  Branch (902:17): [True: 24, False: 114]
  ------------------
  903|     24|                IntProperty prop;
  904|     24|                ReadIntProperty(prop, attribute);
  905|     24|                if (prop.name == "PolyCountX") {
  ------------------
  |  Branch (905:21): [True: 6, False: 18]
  ------------------
  906|      6|                    nd->spherePolyCountX = prop.value;
  907|     18|                } else if (prop.name == "PolyCountY") {
  ------------------
  |  Branch (907:28): [True: 6, False: 12]
  ------------------
  908|      6|                    nd->spherePolyCountY = prop.value;
  909|      6|                }
  910|     24|            }
  911|    357|        } else if (!ASSIMP_stricmp(attribute.name(), "string") || !ASSIMP_stricmp(attribute.name(), "enum")) { // <string /> or < enum />
  ------------------
  |  Branch (911:20): [True: 97, False: 260]
  |  Branch (911:67): [True: 69, False: 191]
  ------------------
  912|    166|            StringProperty prop;
  913|    166|            ReadStringProperty(prop, attribute);
  914|    166|            if (prop.value.length() == 0) continue; // skip empty strings
  ------------------
  |  Branch (914:17): [True: 37, False: 129]
  ------------------
  915|    129|            if (prop.name == "Name") {
  ------------------
  |  Branch (915:17): [True: 26, False: 103]
  ------------------
  916|     26|                nd->name = prop.value;
  917|       |
  918|       |                /*  If we're either a camera or a light source
  919|       |                 *  we need to update the name in the aiLight/
  920|       |                 *  aiCamera structure, too.
  921|       |                 */
  922|     26|                if (Node::CAMERA == nd->type) {
  ------------------
  |  Branch (922:21): [True: 0, False: 26]
  ------------------
  923|      0|                    cameras.back()->mName.Set(prop.value);
  924|     26|                } else if (Node::LIGHT == nd->type) {
  ------------------
  |  Branch (924:28): [True: 6, False: 20]
  ------------------
  925|      6|                    lights.back()->mName.Set(prop.value);
  926|      6|                }
  927|    103|            } else if (Node::LIGHT == nd->type && "LightType" == prop.name) {
  ------------------
  |  Branch (927:24): [True: 12, False: 91]
  |  Branch (927:51): [True: 6, False: 6]
  ------------------
  928|      6|                if (prop.value == "Spot")
  ------------------
  |  Branch (928:21): [True: 3, False: 3]
  ------------------
  929|      3|                    lights.back()->mType = aiLightSource_SPOT;
  930|      3|                else if (prop.value == "Point")
  ------------------
  |  Branch (930:26): [True: 3, False: 0]
  ------------------
  931|      3|                    lights.back()->mType = aiLightSource_POINT;
  932|      0|                else if (prop.value == "Directional")
  ------------------
  |  Branch (932:26): [True: 0, False: 0]
  ------------------
  933|      0|                    lights.back()->mType = aiLightSource_DIRECTIONAL;
  934|      0|                else {
  935|       |                    // We won't pass the validation with aiLightSourceType_UNDEFINED,
  936|       |                    // so we remove the light and replace it with a silly dummy node
  937|      0|                    delete lights.back();
  938|      0|                    lights.pop_back();
  939|      0|                    nd->type = Node::DUMMY;
  940|       |
  941|      0|                    ASSIMP_LOG_ERROR("Ignoring light of unknown type: ", prop.value);
  942|      0|                }
  943|     97|            } else if ((prop.name == "Mesh" && Node::MESH == nd->type) ||
  ------------------
  |  Branch (943:25): [True: 34, False: 63]
  |  Branch (943:48): [True: 29, False: 5]
  ------------------
  944|     68|                       Node::ANIMMESH == nd->type) {
  ------------------
  |  Branch (944:24): [True: 10, False: 58]
  ------------------
  945|       |                /*  This is the file name of the mesh - either
  946|       |                 *  animated or not. We need to make sure we setup
  947|       |                 *  the correct post-processing settings here.
  948|       |                 */
  949|     39|                unsigned int pp = 0;
  950|     39|                BatchLoader::PropertyMap map;
  951|       |
  952|       |                /* If the mesh is a static one remove all animations from the impor data
  953|       |                 */
  954|     39|                if (Node::ANIMMESH != nd->type) {
  ------------------
  |  Branch (954:21): [True: 29, False: 10]
  ------------------
  955|     29|                    pp |= aiProcess_RemoveComponent;
  956|     29|                    SetGenericProperty<int>(map.ints, AI_CONFIG_PP_RVC_FLAGS,
  957|     29|                            aiComponent_ANIMATIONS | aiComponent_BONEWEIGHTS);
  958|     29|                }
  959|       |
  960|       |                /*  TODO: maybe implement the protection against recursive
  961|       |                 *  loading calls directly in BatchLoader? The current
  962|       |                 *  implementation is not absolutely safe. A LWS and an IRR
  963|       |                 *  file referencing each other *could* cause the system to
  964|       |                 *  recurse forever.
  965|       |                 */
  966|       |
  967|     39|                const std::string extension = GetExtension(prop.value);
  968|     39|                if ("irr" == extension) {
  ------------------
  |  Branch (968:21): [True: 0, False: 39]
  ------------------
  969|      0|                    ASSIMP_LOG_ERROR("IRR: Can't load another IRR file recursively");
  970|     39|                } else {
  971|     39|                    nd->id = batch.AddLoadRequest(prop.value, pp, &map);
  972|     39|                    nd->meshPath = prop.value;
  973|     39|                }
  974|     39|            }
  975|    129|        }
  976|    729|    }
  977|     63|}
_ZN6Assimp11IRRImporter14ParseAnimatorsERN4pugi8xml_nodeEPNS0_4NodeE:
  979|     12|void IRRImporter::ParseAnimators(pugi::xml_node &animatorNode, IRRImporter::Node *nd) {
  980|     12|    Animator *curAnim = nullptr;
  981|       |    // Make empty animator
  982|     12|    nd->animators.emplace_back();
  983|     12|    curAnim = &nd->animators.back(); // Push it back
  984|     12|    pugi::xml_node attributes = animatorNode.child("attributes");
  985|     12|    if (!attributes) {
  ------------------
  |  Branch (985:9): [True: 0, False: 12]
  ------------------
  986|      0|        ASSIMP_LOG_WARN("Animator node does not contain attributes. ");
  987|      0|        return;
  988|      0|    }
  989|       |
  990|     48|    for (pugi::xml_node attrib : attributes.children()) {
  ------------------
  |  Branch (990:32): [True: 48, False: 12]
  ------------------
  991|       |        // XML may contain useless noes like CDATA
  992|     48|        if (!ASSIMP_stricmp(attrib.name(), "vector3d")) {
  ------------------
  |  Branch (992:13): [True: 24, False: 24]
  ------------------
  993|     24|            VectorProperty prop;
  994|     24|            ReadVectorProperty(prop, attrib);
  995|       |
  996|     24|            if (curAnim->type == Animator::ROTATION && prop.name == "Rotation") {
  ------------------
  |  Branch (996:17): [True: 6, False: 18]
  |  Branch (996:56): [True: 6, False: 0]
  ------------------
  997|       |                // We store the rotation euler angles in 'direction'
  998|      6|                curAnim->direction = prop.value;
  999|     18|            } else if (curAnim->type == Animator::FOLLOW_SPLINE) {
  ------------------
  |  Branch (999:24): [True: 12, False: 6]
  ------------------
 1000|       |                // Check whether the vector follows the PointN naming scheme,
 1001|       |                // here N is the ONE-based index of the point
 1002|     12|                if (prop.name.length() >= 6 && prop.name.substr(0, 5) == "Point") {
  ------------------
  |  Branch (1002:21): [True: 12, False: 0]
  |  Branch (1002:21): [True: 12, False: 0]
  |  Branch (1002:48): [True: 12, False: 0]
  ------------------
 1003|       |                    // Add a new key to the list
 1004|     12|                    curAnim->splineKeys.emplace_back();
 1005|     12|                    aiVectorKey &key = curAnim->splineKeys.back();
 1006|       |
 1007|       |                    // and parse its properties
 1008|     12|                    key.mValue = prop.value;
 1009|     12|                    key.mTime = strtoul10(&prop.name[5]);
 1010|     12|                }
 1011|     12|            } else if (curAnim->type == Animator::FLY_CIRCLE) {
  ------------------
  |  Branch (1011:24): [True: 6, False: 0]
  ------------------
 1012|      6|                if (prop.name == "Center") {
  ------------------
  |  Branch (1012:21): [True: 3, False: 3]
  ------------------
 1013|      3|                    curAnim->circleCenter = prop.value;
 1014|      3|                } else if (prop.name == "Direction") {
  ------------------
  |  Branch (1014:28): [True: 3, False: 0]
  ------------------
 1015|      3|                    curAnim->direction = prop.value;
 1016|       |
 1017|       |                    // From Irrlicht's source - a workaround for backward compatibility with Irrlicht 1.1
 1018|      3|                    if (curAnim->direction == aiVector3D()) {
  ------------------
  |  Branch (1018:25): [True: 0, False: 3]
  ------------------
 1019|      0|                        curAnim->direction = aiVector3D(0.f, 1.f, 0.f);
 1020|      0|                    } else
 1021|      3|                        curAnim->direction.Normalize();
 1022|      3|                }
 1023|      6|            } else if (curAnim->type == Animator::FLY_STRAIGHT) {
  ------------------
  |  Branch (1023:24): [True: 0, False: 0]
  ------------------
 1024|      0|                if (prop.name == "Start") {
  ------------------
  |  Branch (1024:21): [True: 0, False: 0]
  ------------------
 1025|       |                    // We reuse the field here
 1026|      0|                    curAnim->circleCenter = prop.value;
 1027|      0|                } else if (prop.name == "End") {
  ------------------
  |  Branch (1027:28): [True: 0, False: 0]
  ------------------
 1028|       |                    // We reuse the field here
 1029|      0|                    curAnim->direction = prop.value;
 1030|      0|                }
 1031|      0|            }
 1032|       |
 1033|       |            //} else if (!ASSIMP_stricmp(reader->getNodeName(), "bool")) {
 1034|     24|        } else if (!ASSIMP_stricmp(attrib.name(), "bool")) {
  ------------------
  |  Branch (1034:20): [True: 0, False: 24]
  ------------------
 1035|      0|            BoolProperty prop;
 1036|      0|            ReadBoolProperty(prop, attrib);
 1037|       |
 1038|      0|            if (curAnim->type == Animator::FLY_CIRCLE && prop.name == "Loop") {
  ------------------
  |  Branch (1038:17): [True: 0, False: 0]
  |  Branch (1038:58): [True: 0, False: 0]
  ------------------
 1039|      0|                curAnim->loop = prop.value;
 1040|      0|            }
 1041|       |            //} else if (!ASSIMP_stricmp(reader->getNodeName(), "float")) {
 1042|     24|        } else if (!ASSIMP_stricmp(attrib.name(), "float")) {
  ------------------
  |  Branch (1042:20): [True: 12, False: 12]
  ------------------
 1043|     12|            FloatProperty prop;
 1044|     12|            ReadFloatProperty(prop, attrib);
 1045|       |
 1046|       |            // The speed property exists for several animators
 1047|     12|            if (prop.name == "Speed") {
  ------------------
  |  Branch (1047:17): [True: 6, False: 6]
  ------------------
 1048|      6|                curAnim->speed = prop.value;
 1049|      6|            } else if (curAnim->type == Animator::FLY_CIRCLE && prop.name == "Radius") {
  ------------------
  |  Branch (1049:24): [True: 3, False: 3]
  |  Branch (1049:65): [True: 3, False: 0]
  ------------------
 1050|      3|                curAnim->circleRadius = prop.value;
 1051|      3|            } else if (curAnim->type == Animator::FOLLOW_SPLINE && prop.name == "Tightness") {
  ------------------
  |  Branch (1051:24): [True: 3, False: 0]
  |  Branch (1051:68): [True: 3, False: 0]
  ------------------
 1052|      3|                curAnim->tightness = prop.value;
 1053|      3|            }
 1054|       |            //} else if (!ASSIMP_stricmp(reader->getNodeName(), "int")) {
 1055|     12|        } else if (!ASSIMP_stricmp(attrib.name(), "int")) {
  ------------------
  |  Branch (1055:20): [True: 0, False: 12]
  ------------------
 1056|      0|            IntProperty prop;
 1057|      0|            ReadIntProperty(prop, attrib);
 1058|       |
 1059|      0|            if (curAnim->type == Animator::FLY_STRAIGHT && prop.name == "TimeForWay") {
  ------------------
  |  Branch (1059:17): [True: 0, False: 0]
  |  Branch (1059:60): [True: 0, False: 0]
  ------------------
 1060|      0|                curAnim->timeForWay = prop.value;
 1061|      0|            }
 1062|       |            //} else if (!ASSIMP_stricmp(reader->getNodeName(), "string") || !ASSIMP_stricmp(reader->getNodeName(), "enum")) {
 1063|     12|        } else if (!ASSIMP_stricmp(attrib.name(), "string") || !ASSIMP_stricmp(attrib.name(), "enum")) {
  ------------------
  |  Branch (1063:20): [True: 12, False: 0]
  |  Branch (1063:64): [True: 0, False: 0]
  ------------------
 1064|     12|            StringProperty prop;
 1065|     12|            ReadStringProperty(prop, attrib);
 1066|       |
 1067|     12|            if (prop.name == "Type") {
  ------------------
  |  Branch (1067:17): [True: 12, False: 0]
  ------------------
 1068|       |                // type of the animator
 1069|     12|                if (prop.value == "rotation") {
  ------------------
  |  Branch (1069:21): [True: 6, False: 6]
  ------------------
 1070|      6|                    curAnim->type = Animator::ROTATION;
 1071|      6|                } else if (prop.value == "flyCircle") {
  ------------------
  |  Branch (1071:28): [True: 3, False: 3]
  ------------------
 1072|      3|                    curAnim->type = Animator::FLY_CIRCLE;
 1073|      3|                } else if (prop.value == "flyStraight") {
  ------------------
  |  Branch (1073:28): [True: 0, False: 3]
  ------------------
 1074|      0|                    curAnim->type = Animator::FLY_CIRCLE;
 1075|      3|                } else if (prop.value == "followSpline") {
  ------------------
  |  Branch (1075:28): [True: 3, False: 0]
  ------------------
 1076|      3|                    curAnim->type = Animator::FOLLOW_SPLINE;
 1077|      3|                } else {
 1078|      0|                    ASSIMP_LOG_WARN("IRR: Ignoring unknown animator: ", prop.value);
 1079|       |
 1080|      0|                    curAnim->type = Animator::UNKNOWN;
 1081|      0|                }
 1082|     12|            }
 1083|     12|        }
 1084|     48|    }
 1085|     12|}
_ZN6Assimp11IRRImporter9ParseNodeERN4pugi8xml_nodeERNS_11BatchLoaderE:
 1087|     63|IRRImporter::Node *IRRImporter::ParseNode(pugi::xml_node &node, BatchLoader &batch) {
 1088|       |    // Parse <node> tags.
 1089|       |    // <node> tags have various types
 1090|       |    // <node> tags can contain <attribute>, <material>
 1091|       |    // they can also contain other <node> tags, (and can reference other files as well?)
 1092|       |    // ***********************************************************************
 1093|       |    /*  What we're going to do with the node depends
 1094|       |     *  on its type:
 1095|       |     *
 1096|       |     *  "mesh" - Load a mesh from an external file
 1097|       |     *  "cube" - Generate a cube
 1098|       |     *  "skybox" - Generate a skybox
 1099|       |     *  "light" - A light source
 1100|       |     *  "sphere" - Generate a sphere mesh
 1101|       |     *  "animatedMesh" - Load an animated mesh from an external file
 1102|       |     *    and join its animation channels with ours.
 1103|       |     *  "empty" - A dummy node
 1104|       |     *  "camera" - A camera
 1105|       |     *  "terrain" - a terrain node (data comes from a heightmap)
 1106|       |     *  "billboard", ""
 1107|       |     *
 1108|       |     *  Each of these nodes can be animated and all can have multiple
 1109|       |     *  materials assigned (except lights, cameras and dummies, of course).
 1110|       |     *  Said materials and animators are all collected at the bottom
 1111|       |     */
 1112|       |    // ***********************************************************************
 1113|     63|    Node *nd;
 1114|     63|    pugi::xml_attribute nodeTypeAttrib = node.attribute("type");
 1115|     63|    if (!ASSIMP_stricmp(nodeTypeAttrib.value(), "mesh") || !ASSIMP_stricmp(nodeTypeAttrib.value(), "octTree")) {
  ------------------
  |  Branch (1115:9): [True: 29, False: 34]
  |  Branch (1115:60): [True: 0, False: 34]
  ------------------
 1116|       |        // OctTree's and meshes are treated equally
 1117|     29|        nd = new Node(Node::MESH);
 1118|     34|    } else if (!ASSIMP_stricmp(nodeTypeAttrib.value(), "cube")) {
  ------------------
  |  Branch (1118:16): [True: 7, False: 27]
  ------------------
 1119|      7|        nd = new Node(Node::CUBE);
 1120|      7|        guessedMeshCnt += 1; // Cube is only one mesh
 1121|     27|    } else if (!ASSIMP_stricmp(nodeTypeAttrib.value(), "skybox")) {
  ------------------
  |  Branch (1121:16): [True: 1, False: 26]
  ------------------
 1122|      1|        nd = new Node(Node::SKYBOX);
 1123|      1|        guessedMeshCnt += 6; // Skybox is a box, with 6 meshes?
 1124|     26|    } else if (!ASSIMP_stricmp(nodeTypeAttrib.value(), "camera")) {
  ------------------
  |  Branch (1124:16): [True: 3, False: 23]
  ------------------
 1125|      3|        nd = new Node(Node::CAMERA);
 1126|       |        // Setup a temporary name for the camera
 1127|      3|        aiCamera *cam = new aiCamera();
 1128|      3|        cam->mName.Set(nd->name);
 1129|      3|        cameras.push_back(cam);
 1130|     23|    } else if (!ASSIMP_stricmp(nodeTypeAttrib.value(), "light")) {
  ------------------
  |  Branch (1130:16): [True: 6, False: 17]
  ------------------
 1131|      6|        nd = new Node(Node::LIGHT);
 1132|       |        // Setup a temporary name for the light
 1133|      6|        aiLight *cam = new aiLight();
 1134|      6|        cam->mName.Set(nd->name);
 1135|      6|        lights.push_back(cam);
 1136|     17|    } else if (!ASSIMP_stricmp(nodeTypeAttrib.value(), "sphere")) {
  ------------------
  |  Branch (1136:16): [True: 6, False: 11]
  ------------------
 1137|      6|        nd = new Node(Node::SPHERE);
 1138|      6|        guessedMeshCnt += 1;
 1139|     11|    } else if (!ASSIMP_stricmp(nodeTypeAttrib.value(), "animatedMesh")) {
  ------------------
  |  Branch (1139:16): [True: 5, False: 6]
  ------------------
 1140|      5|        nd = new Node(Node::ANIMMESH);
 1141|      6|    } else if (!ASSIMP_stricmp(nodeTypeAttrib.value(), "empty")) {
  ------------------
  |  Branch (1141:16): [True: 6, False: 0]
  ------------------
 1142|      6|        nd = new Node(Node::DUMMY);
 1143|      6|    } else if (!ASSIMP_stricmp(nodeTypeAttrib.value(), "terrain")) {
  ------------------
  |  Branch (1143:16): [True: 0, False: 0]
  ------------------
 1144|      0|        nd = new Node(Node::TERRAIN);
 1145|      0|    } else if (!ASSIMP_stricmp(nodeTypeAttrib.value(), "billBoard")) {
  ------------------
  |  Branch (1145:16): [True: 0, False: 0]
  ------------------
 1146|       |        // We don't support billboards, so ignore them
 1147|      0|        ASSIMP_LOG_ERROR("IRR: Billboards are not supported by Assimp");
 1148|      0|        nd = new Node(Node::DUMMY);
 1149|      0|    } else {
 1150|      0|        ASSIMP_LOG_WARN("IRR: Found unknown node: ", nodeTypeAttrib.value());
 1151|       |
 1152|       |        /*  We skip the contents of nodes we don't know.
 1153|       |         *  We parse the transformation and all animators
 1154|       |         *  and skip the rest.
 1155|       |         */
 1156|      0|        nd = new Node(Node::DUMMY);
 1157|      0|    }
 1158|       |
 1159|       |    // TODO: consolidate all into one loop
 1160|    147|    for (pugi::xml_node subNode : node.children()) {
  ------------------
  |  Branch (1160:33): [True: 147, False: 63]
  ------------------
 1161|       |        // Collect node attributes first
 1162|    147|        if (!ASSIMP_stricmp(subNode.name(), "attributes")) {
  ------------------
  |  Branch (1162:13): [True: 63, False: 84]
  ------------------
 1163|     63|            ParseNodeAttributes(subNode, nd, batch); // Parse attributes into this node
 1164|     84|        } else if (!ASSIMP_stricmp(subNode.name(), "animators")) {
  ------------------
  |  Branch (1164:20): [True: 12, False: 72]
  ------------------
 1165|       |            // Then parse any animators
 1166|       |            // All animators should contain an <attributes> tag
 1167|       |
 1168|       |            //  This is an animation path - add a new animator
 1169|       |            //  to the list.
 1170|     12|            ParseAnimators(subNode, nd); // Function modifies nd's animator vector
 1171|     12|            guessedAnimCnt += 1;
 1172|     12|        }
 1173|       |
 1174|       |        // Then parse any materials
 1175|       |        // Materials are available to almost all node types
 1176|    147|        if (nd->type != Node::DUMMY) {
  ------------------
  |  Branch (1176:13): [True: 138, False: 9]
  ------------------
 1177|    138|            if (!ASSIMP_stricmp(subNode.name(), "materials")) {
  ------------------
  |  Branch (1177:17): [True: 48, False: 90]
  ------------------
 1178|       |                // Parse material description directly
 1179|       |                // Each material should contain an <attributes> node
 1180|       |                // with everything specified
 1181|     48|                nd->materials.emplace_back();
 1182|     48|                std::pair<aiMaterial *, unsigned int> &p = nd->materials.back();
 1183|     48|                p.first = ParseMaterial(subNode, p.second);
 1184|     48|                guessedMatCnt += 1;
 1185|     48|            }
 1186|    138|        }
 1187|    147|    }
 1188|       |
 1189|       |    // Then parse any child nodes
 1190|       |    // Attach the newly created node to the scene-graph
 1191|    147|    for (pugi::xml_node child : node.children()) {
  ------------------
  |  Branch (1191:31): [True: 147, False: 63]
  ------------------
 1192|    147|        if (!ASSIMP_stricmp(child.name(), "node")) { // Is a child node
  ------------------
  |  Branch (1192:13): [True: 6, False: 141]
  ------------------
 1193|      6|            Node *childNd = ParseNode(child, batch); // Repeat this function for all children
 1194|      6|            nd->children.push_back(childNd);
 1195|      6|        };
 1196|    147|    }
 1197|       |
 1198|       |    // Return fully specified node
 1199|     63|    return nd;
 1200|     63|}
_ZN6Assimp11IRRImporter14InternReadFileERKNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEP7aiScenePNS_8IOSystemE:
 1204|     11|void IRRImporter::InternReadFile(const std::string &pFile, aiScene *pScene, IOSystem *pIOHandler) {
 1205|     11|    std::unique_ptr<IOStream> file(pIOHandler->Open(pFile));
 1206|       |    // Check whether we can read from the file
 1207|     11|    if (file == nullptr) {
  ------------------
  |  Branch (1207:9): [True: 0, False: 11]
  ------------------
 1208|      0|        throw DeadlyImportError("Failed to open IRR file ", pFile);
 1209|      0|    }
 1210|       |
 1211|       |    // Construct the irrXML parser
 1212|     11|    XmlParser st;
 1213|     11|    if (!st.parse(file.get())) {
  ------------------
  |  Branch (1213:9): [True: 3, False: 8]
  ------------------
 1214|      3|        throw DeadlyImportError("XML parse error while loading IRR file ", pFile);
 1215|      3|    }
 1216|      8|    pugi::xml_node documentRoot = st.getRootNode();
 1217|       |
 1218|       |    // The root node of the scene
 1219|      8|    Node *root = new Node(Node::DUMMY);
 1220|      8|    root->parent = nullptr;
 1221|      8|    root->name = "<IRRSceneRoot>";
 1222|       |
 1223|       |    // Batch loader used to load external models
 1224|      8|    BatchLoader batch(pIOHandler);
 1225|       |    // batch.SetBasePath(pFile);
 1226|       |
 1227|      8|    cameras.reserve(1); // Probably only one camera in entire scene
 1228|      8|    lights.reserve(5);
 1229|       |
 1230|      8|    this->guessedAnimCnt = 0;
 1231|      8|    this->guessedMeshCnt = 0;
 1232|      8|    this->guessedMatCnt = 0;
 1233|       |
 1234|       |    // Parse the XML
 1235|       |    // Find the scene root from document root.
 1236|      8|    const pugi::xml_node &sceneRoot = documentRoot.child("irr_scene");
 1237|      8|    if (!sceneRoot) {
  ------------------
  |  Branch (1237:9): [True: 0, False: 8]
  ------------------
 1238|      0|        delete root;
 1239|      0|        throw new DeadlyImportError("IRR: <irr_scene> not found in file");
 1240|      0|    }
 1241|     65|    for (pugi::xml_node &child : sceneRoot.children()) {
  ------------------
  |  Branch (1241:32): [True: 65, False: 8]
  ------------------
 1242|       |        // XML elements are either nodes, animators, attributes, or materials
 1243|     65|        if (!ASSIMP_stricmp(child.name(), "node")) {
  ------------------
  |  Branch (1243:13): [True: 57, False: 8]
  ------------------
 1244|       |            // Recursive collect subtree children
 1245|     57|            Node *nd = ParseNode(child, batch);
 1246|       |            // Attach to root
 1247|     57|            root->children.push_back(nd);
 1248|     57|        }
 1249|     65|    }
 1250|       |
 1251|       |    //  Now iterate through all cameras and compute their final (horizontal) FOV
 1252|      8|    for (aiCamera *cam : cameras) {
  ------------------
  |  Branch (1252:24): [True: 3, False: 8]
  ------------------
 1253|       |        // screen aspect could be missing
 1254|      3|        if (cam->mAspect) {
  ------------------
  |  Branch (1254:13): [True: 3, False: 0]
  ------------------
 1255|      3|            cam->mHorizontalFOV *= cam->mAspect;
 1256|      3|        } else {
 1257|      0|            ASSIMP_LOG_WARN("IRR: Camera aspect is not given, can't compute horizontal FOV");
 1258|      0|        }
 1259|      3|    }
 1260|       |
 1261|      8|    batch.LoadAll();
 1262|       |
 1263|       |    // Allocate a temporary scene data structure
 1264|      8|    aiScene *tempScene = new aiScene();
 1265|      8|    tempScene->mRootNode = new aiNode();
 1266|      8|    tempScene->mRootNode->mName.Set("<IRRRoot>");
 1267|       |
 1268|       |    // Copy the cameras to the output array
 1269|      8|    if (!cameras.empty()) {
  ------------------
  |  Branch (1269:9): [True: 3, False: 5]
  ------------------
 1270|      3|        tempScene->mNumCameras = (unsigned int)cameras.size();
 1271|      3|        tempScene->mCameras = new aiCamera *[tempScene->mNumCameras];
 1272|      3|        ::memcpy(tempScene->mCameras, &cameras[0], sizeof(void *) * tempScene->mNumCameras);
 1273|      3|    }
 1274|       |
 1275|       |    // Copy the light sources to the output array
 1276|      8|    if (!lights.empty()) {
  ------------------
  |  Branch (1276:9): [True: 3, False: 5]
  ------------------
 1277|      3|        tempScene->mNumLights = (unsigned int)lights.size();
 1278|      3|        tempScene->mLights = new aiLight *[tempScene->mNumLights];
 1279|      3|        ::memcpy(tempScene->mLights, &lights[0], sizeof(void *) * tempScene->mNumLights);
 1280|      3|    }
 1281|       |
 1282|       |    // temporary data
 1283|      8|    std::vector<aiNodeAnim *> anims;
 1284|      8|    std::vector<aiMaterial *> materials;
 1285|      8|    std::vector<AttachmentInfo> attach;
 1286|      8|    std::vector<aiMesh *> meshes;
 1287|       |
 1288|       |    // try to guess how much storage we'll need
 1289|      8|    anims.reserve(guessedAnimCnt + (guessedAnimCnt >> 2));
 1290|      8|    meshes.reserve(guessedMeshCnt + (guessedMeshCnt >> 2));
 1291|      8|    materials.reserve(guessedMatCnt + (guessedMatCnt >> 2));
 1292|       |
 1293|       |    // Now process our scene-graph recursively: generate final
 1294|       |    // meshes and generate animation channels for all nodes.
 1295|      8|    unsigned int defMatIdx = UINT_MAX;
 1296|      8|    GenerateGraph(root, tempScene->mRootNode, tempScene,
 1297|      8|            batch, meshes, anims, attach, materials, defMatIdx);
 1298|       |
 1299|      8|    if (!anims.empty()) {
  ------------------
  |  Branch (1299:9): [True: 3, False: 5]
  ------------------
 1300|      3|        tempScene->mNumAnimations = 1;
 1301|      3|        tempScene->mAnimations = new aiAnimation *[tempScene->mNumAnimations];
 1302|      3|        aiAnimation *an = tempScene->mAnimations[0] = new aiAnimation();
 1303|       |
 1304|       |        // ***********************************************************
 1305|       |        // This is only the global animation channel of the scene.
 1306|       |        // If there are animated models, they will have separate
 1307|       |        // animation channels in the scene. To display IRR scenes
 1308|       |        // correctly, users will need to combine the global anim
 1309|       |        // channel with all the local animations they want to play
 1310|       |        // ***********************************************************
 1311|      3|        an->mName.Set("Irr_GlobalAnimChannel");
 1312|       |
 1313|       |        // copy all node animation channels to the global channel
 1314|      3|        an->mNumChannels = (unsigned int)anims.size();
 1315|      3|        an->mChannels = new aiNodeAnim *[an->mNumChannels];
 1316|      3|        ::memcpy(an->mChannels, &anims[0], sizeof(void *) * an->mNumChannels);
 1317|      3|    }
 1318|      8|    if (!meshes.empty()) {
  ------------------
  |  Branch (1318:9): [True: 4, False: 4]
  ------------------
 1319|       |        // copy all meshes to the temporary scene
 1320|      4|        tempScene->mNumMeshes = (unsigned int)meshes.size();
 1321|      4|        tempScene->mMeshes = new aiMesh *[tempScene->mNumMeshes];
 1322|      4|        ::memcpy(tempScene->mMeshes, &meshes[0], tempScene->mNumMeshes * sizeof(void *));
 1323|      4|    }
 1324|       |
 1325|       |    // Copy all materials to the output array
 1326|      8|    if (!materials.empty()) {
  ------------------
  |  Branch (1326:9): [True: 4, False: 4]
  ------------------
 1327|      4|        tempScene->mNumMaterials = (unsigned int)materials.size();
 1328|      4|        tempScene->mMaterials = new aiMaterial *[tempScene->mNumMaterials];
 1329|      4|        ::memcpy(tempScene->mMaterials, &materials[0], sizeof(void *) * tempScene->mNumMaterials);
 1330|      4|    }
 1331|       |
 1332|       |    //  Now merge all sub scenes and attach them to the correct
 1333|       |    //  attachment points in the scenegraph.
 1334|      8|    SceneCombiner::MergeScenes(&pScene, tempScene, attach,
 1335|      8|            AI_INT_MERGE_SCENE_GEN_UNIQUE_NAMES | (!configSpeedFlag ? (AI_INT_MERGE_SCENE_GEN_UNIQUE_NAMES_IF_NECESSARY | AI_INT_MERGE_SCENE_GEN_UNIQUE_MATNAMES) :
  ------------------
  |  Branch (1335:52): [True: 8, False: 0]
  ------------------
 1336|      8|                                                                      0));
 1337|       |
 1338|       |    // If we have no meshes | no materials now set the INCOMPLETE
 1339|       |    // scene flag. This is necessary if we failed to load all
 1340|       |    // models from external files
 1341|      8|    if (!pScene->mNumMeshes || !pScene->mNumMaterials) {
  ------------------
  |  Branch (1341:9): [True: 4, False: 4]
  |  Branch (1341:32): [True: 0, False: 4]
  ------------------
 1342|      4|        ASSIMP_LOG_WARN("IRR: No meshes loaded, setting AI_SCENE_FLAGS_INCOMPLETE");
 1343|      4|        pScene->mFlags |= AI_SCENE_FLAGS_INCOMPLETE;
 1344|      4|    }
 1345|       |
 1346|       |    // Finished ... everything destructs automatically and all
 1347|       |    // temporary scenes have already been deleted by MergeScenes()
 1348|      8|    delete root;
 1349|      8|}
_Z20FindSuitableMultipleRi:
  268|     12|inline void FindSuitableMultiple(int &angle) {
  269|     12|    if (angle < 3)
  ------------------
  |  Branch (269:9): [True: 0, False: 12]
  ------------------
  270|      0|        angle = 3;
  271|     12|    else if (angle < 10)
  ------------------
  |  Branch (271:14): [True: 0, False: 12]
  ------------------
  272|      0|        angle = 10;
  273|     12|    else if (angle < 20)
  ------------------
  |  Branch (273:14): [True: 0, False: 12]
  ------------------
  274|      0|        angle = 20;
  275|     12|    else if (angle < 30)
  ------------------
  |  Branch (275:14): [True: 2, False: 10]
  ------------------
  276|      2|        angle = 30;
  277|     12|}
_Z11ClampSplineii:
  263|  18.0k|inline int ClampSpline(int idx, int size) {
  264|  18.0k|    return (idx < 0 ? size + idx : (idx >= size ? idx - size : idx));
  ------------------
  |  Branch (264:13): [True: 3.00k, False: 15.0k]
  |  Branch (264:37): [True: 0, False: 15.0k]
  ------------------
  265|  18.0k|}

_ZN6Assimp11IRRImporter8AnimatorC2ENS1_2ATE:
   98|     12|                type(t), speed(ai_real(0.001)), direction(ai_real(0.0), ai_real(1.0), ai_real(0.0)), circleRadius(ai_real(1.0)), tightness(ai_real(0.5)), loop(true), timeForWay(100) {
   99|     12|        }
_ZN6Assimp11IRRImporter4NodeC2ENS1_2ETE:
  138|     71|                type(t), scaling(1.0, 1.0, 1.0) // assume uniform scaling by default
  139|       |                ,
  140|       |                parent(),
  141|     71|                framesPerSecond(0.0),
  142|       |                id(),
  143|     71|                sphereRadius(1.0),
  144|     71|                spherePolyCountX(100),
  145|     71|                spherePolyCountY(100) {
  146|       |
  147|       |            // Generate a default name for the node
  148|     71|            char buffer[128];
  149|     71|            static int cnt;
  150|     71|            ai_snprintf(buffer, 128, "IrrNode_%i", cnt++);
  151|     71|            name = std::string(buffer);
  152|       |
  153|       |            // reserve space for up to 5 materials
  154|     71|            materials.reserve(5);
  155|       |
  156|       |            // reserve space for up to 5 children
  157|     71|            children.reserve(5);
  158|     71|        }

_ZNK6Assimp15IRRMeshImporter7CanReadERKNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEPNS_8IOSystemEb:
   74|    347|bool IRRMeshImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool /*checkSig*/) const {
   75|       |    /* NOTE: A simple check for the file extension is not enough
   76|       |     * here. Irrmesh and irr are easy, but xml is too generic
   77|       |     * and could be collada, too. So we need to open the file and
   78|       |     * search for typical tokens.
   79|       |     */
   80|    347|    static const char *tokens[] = { "irrmesh" };
   81|       |    return SearchFileHeaderForToken(pIOHandler, pFile, tokens, AI_COUNT_OF(tokens));
   82|    347|}
_ZNK6Assimp15IRRMeshImporter7GetInfoEv:
   86|    641|const aiImporterDesc *IRRMeshImporter::GetInfo() const {
   87|    641|    return &desc;
   88|    641|}
_ZN6Assimp15IRRMeshImporter14InternReadFileERKNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEP7aiScenePNS_8IOSystemE:
  107|      7|        aiScene *pScene, IOSystem *pIOHandler) {
  108|      7|    std::unique_ptr<IOStream> file(pIOHandler->Open(pFile));
  109|       |
  110|       |    // Check whether we can read from the file
  111|      7|    if (file == nullptr) {
  ------------------
  |  Branch (111:9): [True: 0, False: 7]
  ------------------
  112|      0|        throw DeadlyImportError("Failed to open IRRMESH file ", pFile);
  113|      0|    }
  114|       |
  115|       |    // Construct the irrXML parser
  116|      7|    XmlParser parser;
  117|      7|    if (!parser.parse(file.get())) {
  ------------------
  |  Branch (117:9): [True: 1, False: 6]
  ------------------
  118|      1|        throw DeadlyImportError("XML parse error while loading IRRMESH file ", pFile);
  119|      1|    }
  120|      6|    XmlNode root = parser.getRootNode();
  121|       |
  122|       |    // final data
  123|      6|    std::vector<aiMaterial *> materials;
  124|      6|    std::vector<aiMesh *> meshes;
  125|      6|    materials.reserve(5);
  126|      6|    meshes.reserve(5);
  127|       |
  128|       |    // temporary data - current mesh buffer
  129|       |    // TODO move all these to inside loop
  130|      6|    aiMaterial *curMat = nullptr;
  131|      6|    aiMesh *curMesh = nullptr;
  132|      6|    unsigned int curMatFlags = 0;
  133|       |
  134|      6|    std::vector<aiVector3D> curVertices, curNormals, curTangents, curBitangents;
  135|      6|    std::vector<aiColor4D> curColors;
  136|      6|    std::vector<aiVector3D> curUVs, curUV2s;
  137|       |
  138|       |    // some temporary variables
  139|       |    // textMeaning is a 15 year old variable, that could've been an enum
  140|       |    // int textMeaning = 0; // 0=none? 1=vertices 2=indices
  141|       |    // int vertexFormat = 0; // 0 = normal; 1 = 2 tcoords, 2 = tangents
  142|      6|    bool useColors = false;
  143|       |
  144|       |    // irrmesh files have a top level <mesh> owning multiple <buffer> nodes.
  145|       |    // Each <buffer> contains <material>, <vertices>, and <indices>
  146|       |    // <material> tags here directly owns the material data specs
  147|       |    // <vertices> are a vertex per line, contains position, UV1 coords, maybe UV2, normal, tangent, bitangent
  148|       |    // <boundingbox> is ignored, I think assimp recalculates those?
  149|       |
  150|       |    // Parse the XML file
  151|      6|    pugi::xml_node const &meshNode = root.child("mesh");
  152|     33|    for (pugi::xml_node bufferNode : meshNode.children()) {
  ------------------
  |  Branch (152:36): [True: 33, False: 6]
  ------------------
  153|     33|        if (ASSIMP_stricmp(bufferNode.name(), "buffer")) {
  ------------------
  |  Branch (153:13): [True: 12, False: 21]
  ------------------
  154|       |            // Might be a useless warning
  155|     12|            ASSIMP_LOG_WARN("IRRMESH: Ignoring non buffer node <", bufferNode.name(), "> in mesh declaration");
  156|     12|            continue;
  157|     12|        }
  158|       |
  159|     21|        curMat = nullptr;
  160|     21|        curMesh = nullptr;
  161|       |
  162|     21|        curVertices.clear();
  163|     21|        curColors.clear();
  164|     21|        curNormals.clear();
  165|     21|        curUV2s.clear();
  166|     21|        curUVs.clear();
  167|     21|        curTangents.clear();
  168|     21|        curBitangents.clear();
  169|       |
  170|       |        // TODO ensure all three nodes are present and populated
  171|       |        // before allocating everything
  172|       |
  173|       |        // Get first material node
  174|     21|        pugi::xml_node materialNode = bufferNode.child("material");
  175|     21|        if (materialNode) {
  ------------------
  |  Branch (175:13): [True: 21, False: 0]
  ------------------
  176|     21|            curMat = ParseMaterial(materialNode, curMatFlags);
  177|       |            // Warn if there's more materials
  178|     21|            if (materialNode.next_sibling("material")) {
  ------------------
  |  Branch (178:17): [True: 0, False: 21]
  ------------------
  179|      0|                ASSIMP_LOG_WARN("IRRMESH: Only one material description per buffer, please");
  180|      0|            }
  181|     21|        } else {
  182|      0|            ASSIMP_LOG_ERROR("IRRMESH: Buffer must contain one material");
  183|      0|            continue;
  184|      0|        }
  185|       |
  186|       |        // Get first vertices node
  187|     21|        pugi::xml_node verticesNode = bufferNode.child("vertices");
  188|     21|        if (verticesNode) {
  ------------------
  |  Branch (188:13): [True: 21, False: 0]
  ------------------
  189|     21|            pugi::xml_attribute vertexCountAttrib = verticesNode.attribute("vertexCount");
  190|     21|            int vertexCount = vertexCountAttrib.as_int();
  191|     21|            if (vertexCount == 0) {
  ------------------
  |  Branch (191:17): [True: 0, False: 21]
  ------------------
  192|       |                // This is possible ... remove the mesh from the list and skip further reading
  193|      0|                ASSIMP_LOG_WARN("IRRMESH: Found mesh with zero vertices");
  194|      0|                releaseMaterial(&curMat);
  195|      0|                continue; // Bail out early
  196|     21|            };
  197|       |
  198|     21|            curVertices.reserve(vertexCount);
  199|     21|            curNormals.reserve(vertexCount);
  200|     21|            curColors.reserve(vertexCount);
  201|     21|            curUVs.reserve(vertexCount);
  202|       |
  203|     21|            VertexFormat vertexFormat;
  204|       |            // Determine the file format
  205|     21|            pugi::xml_attribute typeAttrib = verticesNode.attribute("type");
  206|     21|            if (!ASSIMP_stricmp("2tcoords", typeAttrib.value())) {
  ------------------
  |  Branch (206:17): [True: 3, False: 18]
  ------------------
  207|      3|                curUV2s.reserve(vertexCount);
  208|      3|                vertexFormat = VertexFormat::t2coord;
  209|      3|                if (curMatFlags & AI_IRRMESH_EXTRA_2ND_TEXTURE) {
  ------------------
  |  |   51|      3|#define AI_IRRMESH_EXTRA_2ND_TEXTURE 0x100000
  ------------------
  |  Branch (209:21): [True: 3, False: 0]
  ------------------
  210|       |                    // *********************************************************
  211|       |                    // We have a second texture! So use this UV channel
  212|       |                    // for it. The 2nd texture can be either a normal
  213|       |                    // texture (solid_2layer or lightmap_xxx) or a normal
  214|       |                    // map (normal_..., parallax_...)
  215|       |                    // *********************************************************
  216|      3|                    int idx = 1;
  217|      3|                    aiMaterial *mat = (aiMaterial *)curMat;
  218|       |
  219|      3|                    if (curMatFlags & AI_IRRMESH_MAT_lightmap) {
  ------------------
  |  |   30|      3|#define AI_IRRMESH_MAT_lightmap 0x2
  ------------------
  |  Branch (219:25): [True: 3, False: 0]
  ------------------
  220|      3|                        mat->AddProperty(&idx, 1, AI_MATKEY_UVWSRC_LIGHTMAP(0));
  221|      3|                    } else if (curMatFlags & AI_IRRMESH_MAT_normalmap_solid) {
  ------------------
  |  |   39|      0|#define AI_IRRMESH_MAT_normalmap_solid (0x100)
  ------------------
  |  Branch (221:32): [True: 0, False: 0]
  ------------------
  222|      0|                        mat->AddProperty(&idx, 1, AI_MATKEY_UVWSRC_NORMALS(0));
  223|      0|                    } else if (curMatFlags & AI_IRRMESH_MAT_solid_2layer) {
  ------------------
  |  |   23|      0|#define AI_IRRMESH_MAT_solid_2layer 0x10000
  ------------------
  |  Branch (223:32): [True: 0, False: 0]
  ------------------
  224|      0|                        mat->AddProperty(&idx, 1, AI_MATKEY_UVWSRC_DIFFUSE(1));
  225|      0|                    }
  226|      3|                }
  227|     18|            } else if (!ASSIMP_stricmp("tangents", typeAttrib.value())) {
  ------------------
  |  Branch (227:24): [True: 0, False: 18]
  ------------------
  228|      0|                curTangents.reserve(vertexCount);
  229|      0|                curBitangents.reserve(vertexCount);
  230|      0|                vertexFormat = VertexFormat::tangent;
  231|     18|            } else if (!ASSIMP_stricmp("standard", typeAttrib.value())) {
  ------------------
  |  Branch (231:24): [True: 18, False: 0]
  ------------------
  232|     18|                vertexFormat = VertexFormat::standard;
  233|     18|            } else {
  234|       |                // Unsupported format, discard whole buffer/mesh
  235|       |                // Assuming we have a correct material, then release it
  236|       |                // We don't have a correct mesh for sure here
  237|      0|                releaseMaterial(&curMat);
  238|      0|                ASSIMP_LOG_ERROR("IRRMESH: Unknown vertex format");
  239|      0|                continue; // Skip rest of buffer
  240|     21|            };
  241|       |
  242|       |            // We know what format buffer is, collect numbers
  243|     21|            std::string v = verticesNode.text().get();
  244|     21|            const char *end = v.c_str() + v.size();
  245|     21|            ParseBufferVertices(v.c_str(), end, vertexFormat,
  246|     21|                    curVertices, curNormals,
  247|     21|                    curTangents, curBitangents,
  248|     21|                    curUVs, curUV2s, curColors, useColors);
  249|     21|        }
  250|       |
  251|       |        // Get indices
  252|       |        // At this point we have some vertices and a valid material
  253|       |        // Collect indices and create aiMesh at the same time
  254|     21|        pugi::xml_node indicesNode = bufferNode.child("indices");
  255|     21|        if (indicesNode) {
  ------------------
  |  Branch (255:13): [True: 20, False: 1]
  ------------------
  256|       |            // start a new mesh
  257|     20|            curMesh = new aiMesh();
  258|       |
  259|       |            // allocate storage for all faces
  260|     20|            pugi::xml_attribute attr = indicesNode.attribute("indexCount");
  261|     20|            curMesh->mNumVertices = attr.as_int();
  262|     20|            if (!curMesh->mNumVertices) {
  ------------------
  |  Branch (262:17): [True: 0, False: 20]
  ------------------
  263|       |                // This is possible ... remove the mesh from the list and skip further reading
  264|      0|                ASSIMP_LOG_WARN("IRRMESH: Found mesh with zero indices");
  265|       |
  266|       |                // mesh - away
  267|      0|                releaseMesh(&curMesh);
  268|       |
  269|       |                // material - away
  270|      0|                releaseMaterial(&curMat);
  271|      0|                continue; // Go to next buffer
  272|      0|            }
  273|       |
  274|     20|            if (curMesh->mNumVertices % 3) {
  ------------------
  |  Branch (274:17): [True: 0, False: 20]
  ------------------
  275|      0|                ASSIMP_LOG_WARN("IRRMESH: Number if indices isn't divisible by 3");
  276|      0|            }
  277|       |
  278|     20|            curMesh->mNumFaces = curMesh->mNumVertices / 3;
  279|     20|            curMesh->mFaces = new aiFace[curMesh->mNumFaces];
  280|       |
  281|       |            // setup some members
  282|     20|            curMesh->mMaterialIndex = (unsigned int)materials.size();
  283|     20|            curMesh->mPrimitiveTypes = aiPrimitiveType_TRIANGLE;
  284|       |
  285|       |            // allocate storage for all vertices
  286|     20|            curMesh->mVertices = new aiVector3D[curMesh->mNumVertices];
  287|       |
  288|     20|            if (curNormals.size() == curVertices.size()) {
  ------------------
  |  Branch (288:17): [True: 20, False: 0]
  ------------------
  289|     20|                curMesh->mNormals = new aiVector3D[curMesh->mNumVertices];
  290|     20|            }
  291|     20|            if (curTangents.size() == curVertices.size()) {
  ------------------
  |  Branch (291:17): [True: 0, False: 20]
  ------------------
  292|      0|                curMesh->mTangents = new aiVector3D[curMesh->mNumVertices];
  293|      0|            }
  294|     20|            if (curBitangents.size() == curVertices.size()) {
  ------------------
  |  Branch (294:17): [True: 0, False: 20]
  ------------------
  295|      0|                curMesh->mBitangents = new aiVector3D[curMesh->mNumVertices];
  296|      0|            }
  297|     20|            if (curColors.size() == curVertices.size() && useColors) {
  ------------------
  |  Branch (297:17): [True: 20, False: 0]
  |  Branch (297:59): [True: 0, False: 20]
  ------------------
  298|      0|                curMesh->mColors[0] = new aiColor4D[curMesh->mNumVertices];
  299|      0|            }
  300|     20|            if (curUVs.size() == curVertices.size()) {
  ------------------
  |  Branch (300:17): [True: 20, False: 0]
  ------------------
  301|     20|                curMesh->mTextureCoords[0] = new aiVector3D[curMesh->mNumVertices];
  302|     20|            }
  303|     20|            if (curUV2s.size() == curVertices.size()) {
  ------------------
  |  Branch (303:17): [True: 2, False: 18]
  ------------------
  304|      2|                curMesh->mTextureCoords[1] = new aiVector3D[curMesh->mNumVertices];
  305|      2|            }
  306|       |
  307|       |            // read indices
  308|     20|            aiFace *curFace = curMesh->mFaces;
  309|     20|            aiFace *const faceEnd = curMesh->mFaces + curMesh->mNumFaces;
  310|       |
  311|     20|            aiVector3D *pcV = curMesh->mVertices;
  312|     20|            aiVector3D *pcN = curMesh->mNormals;
  313|     20|            aiVector3D *pcT = curMesh->mTangents;
  314|     20|            aiVector3D *pcB = curMesh->mBitangents;
  315|     20|            aiColor4D *pcC0 = curMesh->mColors[0];
  316|     20|            aiVector3D *pcT0 = curMesh->mTextureCoords[0];
  317|     20|            aiVector3D *pcT1 = curMesh->mTextureCoords[1];
  318|       |
  319|     20|            unsigned int curIdx = 0;
  320|     20|            unsigned int total = 0;
  321|       |
  322|       |            // NOTE this might explode for UTF-16 and wchars
  323|     20|            const char *sz = indicesNode.text().get();
  324|     20|            const char *end = sz + std::strlen(sz);
  325|       |
  326|       |            // For each index loop over aiMesh faces
  327|  9.40k|            while (SkipSpacesAndLineEnd(&sz, end)) {
  ------------------
  |  Branch (327:20): [True: 9.38k, False: 20]
  ------------------
  328|  9.38k|                if (curFace >= faceEnd) {
  ------------------
  |  Branch (328:21): [True: 0, False: 9.38k]
  ------------------
  329|      0|                    ASSIMP_LOG_ERROR("IRRMESH: Too many indices");
  330|      0|                    break;
  331|      0|                }
  332|       |                // if new face
  333|  9.38k|                if (!curIdx) {
  ------------------
  |  Branch (333:21): [True: 3.12k, False: 6.25k]
  ------------------
  334|  3.12k|                    curFace->mNumIndices = 3;
  335|  3.12k|                    curFace->mIndices = new unsigned int[3];
  336|  3.12k|                }
  337|       |
  338|       |                // Read index base 10
  339|       |                // function advances the pointer
  340|  9.38k|                unsigned int idx = strtoul10(sz, &sz);
  341|  9.38k|                if (idx >= curVertices.size()) {
  ------------------
  |  Branch (341:21): [True: 0, False: 9.38k]
  ------------------
  342|      0|                    ASSIMP_LOG_ERROR("IRRMESH: Index out of range");
  343|      0|                    idx = 0;
  344|      0|                }
  345|       |
  346|       |                // make up our own indices?
  347|  9.38k|                curFace->mIndices[curIdx] = total++;
  348|       |
  349|       |                // Copy over data to aiMesh
  350|  9.38k|                *pcV++ = curVertices[idx];
  351|  9.38k|                if (pcN)
  ------------------
  |  Branch (351:21): [True: 9.38k, False: 0]
  ------------------
  352|  9.38k|                    *pcN++ = curNormals[idx];
  353|  9.38k|                if (pcT)
  ------------------
  |  Branch (353:21): [True: 0, False: 9.38k]
  ------------------
  354|      0|                    *pcT++ = curTangents[idx];
  355|  9.38k|                if (pcB)
  ------------------
  |  Branch (355:21): [True: 0, False: 9.38k]
  ------------------
  356|      0|                    *pcB++ = curBitangents[idx];
  357|  9.38k|                if (pcC0)
  ------------------
  |  Branch (357:21): [True: 0, False: 9.38k]
  ------------------
  358|      0|                    *pcC0++ = curColors[idx];
  359|  9.38k|                if (pcT0)
  ------------------
  |  Branch (359:21): [True: 9.38k, False: 0]
  ------------------
  360|  9.38k|                    *pcT0++ = curUVs[idx];
  361|  9.38k|                if (pcT1)
  ------------------
  |  Branch (361:21): [True: 816, False: 8.56k]
  ------------------
  362|    816|                    *pcT1++ = curUV2s[idx];
  363|       |
  364|       |                // start new face
  365|  9.38k|                if (++curIdx == 3) {
  ------------------
  |  Branch (365:21): [True: 3.12k, False: 6.25k]
  ------------------
  366|  3.12k|                    ++curFace;
  367|  3.12k|                    curIdx = 0;
  368|  3.12k|                }
  369|  9.38k|            }
  370|       |            // We should be at the end of mFaces
  371|     20|            if (curFace != faceEnd) {
  ------------------
  |  Branch (371:17): [True: 0, False: 20]
  ------------------
  372|      0|                ASSIMP_LOG_ERROR("IRRMESH: Not enough indices");
  373|      0|            }
  374|     20|        }
  375|       |
  376|       |        // Finish processing the mesh - do some small material workarounds
  377|     21|        if (curMatFlags & AI_IRRMESH_MAT_trans_vertex_alpha && !useColors) {
  ------------------
  |  |   26|     42|#define AI_IRRMESH_MAT_trans_vertex_alpha 0x1
  ------------------
  |  Branch (377:13): [True: 2, False: 19]
  |  Branch (377:64): [True: 2, False: 0]
  ------------------
  378|       |            // Take the opacity value of the current material
  379|       |            // from the common vertex color alpha
  380|      2|            aiMaterial *mat = (aiMaterial *)curMat;
  381|      2|            mat->AddProperty(&curColors[0].a, 1, AI_MATKEY_OPACITY);
  382|      2|        }
  383|       |
  384|       |        // end of previous buffer. A material and a mesh should be there
  385|     21|        if (!curMat || !curMesh) {
  ------------------
  |  Branch (385:13): [True: 1, False: 20]
  |  Branch (385:24): [True: 0, False: 20]
  ------------------
  386|      0|            ASSIMP_LOG_ERROR("IRRMESH: A buffer must contain a mesh and a material");
  387|      0|            releaseMaterial(&curMat);
  388|      0|            releaseMesh(&curMesh);
  389|     21|        } else {
  390|     21|            materials.push_back(curMat);
  391|     21|            meshes.push_back(curMesh);
  392|     21|        }
  393|     21|    }
  394|       |
  395|       |    // If one is empty then so is the other
  396|      6|    if (materials.empty() || meshes.empty()) {
  ------------------
  |  Branch (396:9): [True: 1, False: 5]
  |  Branch (396:30): [True: 0, False: 5]
  ------------------
  397|      0|        throw DeadlyImportError("IRRMESH: Unable to read a mesh from this file");
  398|      0|    }
  399|       |
  400|       |    // now generate the output scene
  401|      6|    pScene->mNumMeshes = (unsigned int)meshes.size();
  402|      6|    pScene->mMeshes = new aiMesh *[pScene->mNumMeshes];
  403|     26|    for (unsigned int i = 0; i < pScene->mNumMeshes; ++i) {
  ------------------
  |  Branch (403:30): [True: 20, False: 6]
  ------------------
  404|     20|        pScene->mMeshes[i] = meshes[i];
  405|       |
  406|       |        // clean this value ...
  407|     20|        pScene->mMeshes[i]->mNumUVComponents[3] = 0;
  408|     20|    }
  409|       |
  410|      6|    pScene->mNumMaterials = (unsigned int)materials.size();
  411|      6|    pScene->mMaterials = new aiMaterial *[pScene->mNumMaterials];
  412|      6|    ::memcpy(pScene->mMaterials, &materials[0], sizeof(void *) * pScene->mNumMaterials);
  413|       |
  414|      6|    pScene->mRootNode = new aiNode();
  415|      6|    pScene->mRootNode->mName.Set("<IRRMesh>");
  416|      6|    pScene->mRootNode->mNumMeshes = pScene->mNumMeshes;
  417|      6|    pScene->mRootNode->mMeshes = new unsigned int[pScene->mNumMeshes];
  418|       |
  419|     26|    for (unsigned int i = 0; i < pScene->mNumMeshes; ++i) {
  ------------------
  |  Branch (419:30): [True: 20, False: 6]
  ------------------
  420|     20|        pScene->mRootNode->mMeshes[i] = i;
  421|     20|    };
  422|      6|}
_ZN6Assimp15IRRMeshImporter19ParseBufferVerticesEPKcS2_NS0_12VertexFormatERNSt3__16vectorI10aiVector3tIfENS4_9allocatorIS7_EEEESB_SB_SB_SB_SB_RNS5_I9aiColor4tIfENS8_ISD_EEEERb:
  428|     21|        std::vector<aiColor4D> &colors, bool &useColors) {
  429|       |    // read vertices
  430|  4.07k|    do {
  431|  4.07k|        SkipSpacesAndLineEnd(&sz, end);
  432|  4.07k|        aiVector3D temp;
  433|  4.07k|        aiColor4D c;
  434|       |
  435|       |        // Read the vertex position
  436|  4.07k|        sz = fast_atoreal_move(sz, temp.x);
  437|  4.07k|        SkipSpaces(&sz, end);
  438|       |
  439|  4.07k|        sz = fast_atoreal_move(sz, temp.y);
  440|  4.07k|        SkipSpaces(&sz, end);
  441|       |
  442|  4.07k|        sz = fast_atoreal_move(sz, temp.z);
  443|  4.07k|        SkipSpaces(&sz, end);
  444|  4.07k|        vertices.push_back(temp);
  445|       |
  446|       |        // Read the vertex normals
  447|  4.07k|        sz = fast_atoreal_move(sz, temp.x);
  448|  4.07k|        SkipSpaces(&sz, end);
  449|       |
  450|  4.07k|        sz = fast_atoreal_move(sz, temp.y);
  451|  4.07k|        SkipSpaces(&sz, end);
  452|       |
  453|  4.07k|        sz = fast_atoreal_move(sz, temp.z);
  454|  4.07k|        SkipSpaces(&sz, end);
  455|  4.07k|        normals.push_back(temp);
  456|       |
  457|       |        // read the vertex colors
  458|  4.07k|        uint32_t clr = strtoul16(sz, &sz);
  459|  4.07k|        ColorFromARGBPacked(clr, c);
  460|       |
  461|       |        // If we're pushing more than one distinct color
  462|  4.07k|        if (!colors.empty() && c != *(colors.end() - 1))
  ------------------
  |  Branch (462:13): [True: 4.04k, False: 22]
  |  Branch (462:13): [True: 0, False: 4.07k]
  |  Branch (462:32): [True: 0, False: 4.04k]
  ------------------
  463|      0|            useColors = true;
  464|       |
  465|  4.07k|        colors.push_back(c);
  466|  4.07k|        SkipSpaces(&sz, end);
  467|       |
  468|       |        // read the first UV coordinate set
  469|  4.07k|        sz = fast_atoreal_move(sz, temp.x);
  470|  4.07k|        SkipSpaces(&sz, end);
  471|       |
  472|  4.07k|        sz = fast_atoreal_move(sz, temp.y);
  473|  4.07k|        SkipSpaces(&sz, end);
  474|  4.07k|        temp.z = 0.f;
  475|  4.07k|        temp.y = 1.f - temp.y; // DX to OGL
  476|  4.07k|        UVs.push_back(temp);
  477|       |
  478|       |        // NOTE these correspond to specific S3DVertex* structs in irr sourcecode
  479|       |        // So by definition, all buffers have either UV2 or tangents or neither
  480|       |        // read the (optional) second UV coordinate set
  481|  4.07k|        if (vertexFormat == VertexFormat::t2coord) {
  ------------------
  |  Branch (481:13): [True: 919, False: 3.15k]
  ------------------
  482|    919|            sz = fast_atoreal_move(sz, temp.x);
  483|    919|            SkipSpaces(&sz, end);
  484|       |
  485|    919|            sz = fast_atoreal_move(sz, temp.y);
  486|    919|            temp.y = 1.f - temp.y; // DX to OGL
  487|    919|            UV2s.push_back(temp);
  488|    919|        }
  489|       |        // read optional tangent and bitangent vectors
  490|  3.15k|        else if (vertexFormat == VertexFormat::tangent) {
  ------------------
  |  Branch (490:18): [True: 0, False: 3.15k]
  ------------------
  491|       |            // tangents
  492|      0|            sz = fast_atoreal_move(sz, temp.x);
  493|      0|            SkipSpaces(&sz, end);
  494|       |
  495|      0|            sz = fast_atoreal_move(sz, temp.z);
  496|      0|            SkipSpaces(&sz, end);
  497|       |
  498|      0|            sz = fast_atoreal_move(sz, temp.y);
  499|      0|            SkipSpaces(&sz, end);
  500|      0|            temp.y *= -1.0f;
  501|      0|            tangents.push_back(temp);
  502|       |
  503|       |            // bitangents
  504|      0|            sz = fast_atoreal_move(sz, temp.x);
  505|      0|            SkipSpaces(&sz, end);
  506|       |
  507|      0|            sz = fast_atoreal_move(sz, temp.z);
  508|      0|            SkipSpaces(&sz, end);
  509|       |
  510|      0|            sz = fast_atoreal_move(sz, temp.y);
  511|      0|            SkipSpaces(&sz, end);
  512|      0|            temp.y *= -1.0f;
  513|      0|            bitangents.push_back(temp);
  514|      0|        }
  515|  4.07k|    } while (SkipLine(&sz, end));
  ------------------
  |  Branch (515:14): [True: 4.04k, False: 21]
  ------------------
  516|       |    // IMPORTANT: We assume that each vertex is specified in one
  517|       |    // line. So we can skip the rest of the line - unknown vertex
  518|       |    // elements are ignored.
  519|     21|}

_ZN6Assimp15IRRMeshImporterC2Ev:
   66|    624|    IRRMeshImporter() = default;
_ZN6Assimp15IRRMeshImporterD2Ev:
   69|    624|    ~IRRMeshImporter() override = default;

_ZN6Assimp12IrrlichtBase15ReadHexPropertyERNS0_8PropertyIjEERN4pugi8xml_nodeE:
   66|     84|void IrrlichtBase::ReadHexProperty(HexProperty &out, pugi::xml_node& hexnode) {
   67|    168|    for (pugi::xml_attribute attrib : hexnode.attributes()) {
  ------------------
  |  Branch (67:37): [True: 168, False: 84]
  ------------------
   68|    168|        if (!ASSIMP_stricmp(attrib.name(), "name")) {
  ------------------
  |  Branch (68:13): [True: 84, False: 84]
  ------------------
   69|     84|            out.name = std::string(attrib.value());
   70|     84|        } else if (!ASSIMP_stricmp(attrib.name(), "value")) {
  ------------------
  |  Branch (70:20): [True: 84, False: 0]
  ------------------
   71|       |            // parse the hexadecimal value
   72|     84|            out.value = strtoul16(attrib.value());
   73|     84|        }
   74|    168|    }
   75|     84|}
_ZN6Assimp12IrrlichtBase15ReadIntPropertyERNS0_8PropertyIiEERN4pugi8xml_nodeE:
   79|     24|void IrrlichtBase::ReadIntProperty(IntProperty &out, pugi::xml_node& intnode) {
   80|     48|    for (pugi::xml_attribute attrib : intnode.attributes()) {
  ------------------
  |  Branch (80:37): [True: 48, False: 24]
  ------------------
   81|     48|        if (!ASSIMP_stricmp(attrib.name(), "name")) {
  ------------------
  |  Branch (81:13): [True: 24, False: 24]
  ------------------
   82|     24|            out.name = std::string(attrib.value());
   83|     24|        } else if (!ASSIMP_stricmp(attrib.name(), "value")) {
  ------------------
  |  Branch (83:20): [True: 24, False: 0]
  ------------------
   84|       |            // parse the int value
   85|     24|            out.value = strtol10(attrib.value());
   86|     24|        }
   87|     48|    }
   88|     24|}
_ZN6Assimp12IrrlichtBase18ReadStringPropertyERNS0_8PropertyINSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEEEERN4pugi8xml_nodeE:
   92|    367|void IrrlichtBase::ReadStringProperty(StringProperty &out, pugi::xml_node& stringnode) {
   93|    734|    for (pugi::xml_attribute attrib : stringnode.attributes()) {
  ------------------
  |  Branch (93:37): [True: 734, False: 367]
  ------------------
   94|    734|        if (!ASSIMP_stricmp(attrib.name(), "name")) {
  ------------------
  |  Branch (94:13): [True: 367, False: 367]
  ------------------
   95|    367|            out.name = std::string(attrib.value());
   96|    367|        } else if (!ASSIMP_stricmp(attrib.name(), "value")) {
  ------------------
  |  Branch (96:20): [True: 367, False: 0]
  ------------------
   97|       |            // simple copy the string
   98|    367|            out.value = std::string(attrib.value());
   99|    367|        }
  100|    734|    }
  101|    367|}
_ZN6Assimp12IrrlichtBase16ReadBoolPropertyERNS0_8PropertyIbEERN4pugi8xml_nodeE:
  105|    399|void IrrlichtBase::ReadBoolProperty(BoolProperty &out, pugi::xml_node& boolnode) {
  106|    798|    for (pugi::xml_attribute attrib : boolnode.attributes()) {
  ------------------
  |  Branch (106:37): [True: 798, False: 399]
  ------------------
  107|    798|        if (!ASSIMP_stricmp(attrib.name(), "name")) {
  ------------------
  |  Branch (107:13): [True: 399, False: 399]
  ------------------
  108|    399|            out.name = std::string(attrib.value());
  109|    399|        } else if (!ASSIMP_stricmp(attrib.name(), "value")) {
  ------------------
  |  Branch (109:20): [True: 399, False: 0]
  ------------------
  110|       |            // true or false, case insensitive
  111|    399|            out.value = (ASSIMP_stricmp(attrib.value(), "true") ? false : true);
  ------------------
  |  Branch (111:26): [True: 234, False: 165]
  ------------------
  112|    399|        }
  113|    798|    }
  114|    399|}
_ZN6Assimp12IrrlichtBase17ReadFloatPropertyERNS0_8PropertyIfEERN4pugi8xml_nodeE:
  118|    113|void IrrlichtBase::ReadFloatProperty(FloatProperty &out, pugi::xml_node &floatnode) {
  119|    226|    for (pugi::xml_attribute attrib : floatnode.attributes()) {
  ------------------
  |  Branch (119:37): [True: 226, False: 113]
  ------------------
  120|    226|        if (!ASSIMP_stricmp(attrib.name(), "name")) {
  ------------------
  |  Branch (120:13): [True: 113, False: 113]
  ------------------
  121|    113|            out.name = std::string(attrib.value());
  122|    113|        } else if (!ASSIMP_stricmp(attrib.name(), "value")) {
  ------------------
  |  Branch (122:20): [True: 113, False: 0]
  ------------------
  123|       |            // just parse the float
  124|    113|            out.value = fast_atof(attrib.value());
  125|    113|        }
  126|    226|    }
  127|    113|}
_ZN6Assimp12IrrlichtBase18ReadVectorPropertyERNS0_8PropertyI10aiVector3tIfEEERN4pugi8xml_nodeE:
  131|    220|void IrrlichtBase::ReadVectorProperty(VectorProperty &out, pugi::xml_node& vectornode) {
  132|    438|    for (pugi::xml_attribute attrib : vectornode.attributes()) {
  ------------------
  |  Branch (132:37): [True: 438, False: 220]
  ------------------
  133|    438|        if (!ASSIMP_stricmp(attrib.name(), "name")) {
  ------------------
  |  Branch (133:13): [True: 219, False: 219]
  ------------------
  134|    219|            out.name = std::string(attrib.value());
  135|    219|        } else if (!ASSIMP_stricmp(attrib.name(), "value")) {
  ------------------
  |  Branch (135:20): [True: 219, False: 0]
  ------------------
  136|       |            // three floats, separated with commas
  137|    219|            const char *ptr = attrib.value();
  138|    219|            size_t len = std::strlen(ptr);
  139|    219|            const char *end = ptr + len;
  140|       |
  141|    219|            SkipSpaces(&ptr, end);
  142|    219|            ptr = fast_atoreal_move(ptr, out.value.x);
  143|    219|            SkipSpaces(&ptr, end);
  144|    219|            if (',' != *ptr) {
  ------------------
  |  Branch (144:17): [True: 0, False: 219]
  ------------------
  145|      0|                ASSIMP_LOG_ERROR("IRR(MESH): Expected comma in vector definition");
  146|    219|            } else {
  147|    219|                SkipSpaces(ptr + 1, &ptr, end);
  148|    219|            }
  149|    219|            ptr = fast_atoreal_move(ptr, out.value.y);
  150|    219|            SkipSpaces(&ptr, end);
  151|    219|            if (',' != *ptr) {
  ------------------
  |  Branch (151:17): [True: 0, False: 219]
  ------------------
  152|      0|                ASSIMP_LOG_ERROR("IRR(MESH): Expected comma in vector definition");
  153|    219|            } else {
  154|    219|                SkipSpaces(ptr + 1, &ptr, end);
  155|    219|            }
  156|    219|            ptr = fast_atoreal_move(ptr, out.value.z);
  157|    219|        }
  158|    438|    }
  159|    220|}
_Z18ConvertMappingModeRKNSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEEE:
  163|     24|int ConvertMappingMode(const std::string &mode) {
  164|     24|    if (mode == "texture_clamp_repeat") {
  ------------------
  |  Branch (164:9): [True: 24, False: 0]
  ------------------
  165|     24|        return aiTextureMapMode_Wrap;
  166|     24|    } else if (mode == "texture_clamp_mirror") {
  ------------------
  |  Branch (166:16): [True: 0, False: 0]
  ------------------
  167|      0|        return aiTextureMapMode_Mirror;
  168|      0|    }
  169|       |
  170|      0|    return aiTextureMapMode_Clamp;
  171|     24|}
_ZN6Assimp12IrrlichtBase13ParseMaterialERN4pugi8xml_nodeERj:
  175|     69|aiMaterial *IrrlichtBase::ParseMaterial(pugi::xml_node& materialNode, unsigned int &matFlags) {
  176|     69|    aiMaterial *mat = new aiMaterial();
  177|     69|    aiColor4D clr;
  178|     69|    aiString s;
  179|       |
  180|     69|    matFlags = 0; // zero output flags
  181|     69|    int cnt = 0; // number of used texture channels
  182|     69|    unsigned int nd = 0;
  183|       |
  184|    871|    for (pugi::xml_node child : materialNode.children()) {
  ------------------
  |  Branch (184:31): [True: 871, False: 69]
  ------------------
  185|    871|        if (!ASSIMP_stricmp(child.name(), "color")) { // Hex properties
  ------------------
  |  Branch (185:13): [True: 84, False: 787]
  ------------------
  186|     84|            HexProperty prop;
  187|     84|            ReadHexProperty(prop, child);
  188|     84|            if (prop.name == "Diffuse") {
  ------------------
  |  Branch (188:17): [True: 21, False: 63]
  ------------------
  189|     21|                ColorFromARGBPacked(prop.value, clr);
  190|     21|                mat->AddProperty(&clr, 1, AI_MATKEY_COLOR_DIFFUSE);
  191|     63|            } else if (prop.name == "Ambient") {
  ------------------
  |  Branch (191:24): [True: 21, False: 42]
  ------------------
  192|     21|                ColorFromARGBPacked(prop.value, clr);
  193|     21|                mat->AddProperty(&clr, 1, AI_MATKEY_COLOR_AMBIENT);
  194|     42|            } else if (prop.name == "Specular") {
  ------------------
  |  Branch (194:24): [True: 21, False: 21]
  ------------------
  195|     21|                ColorFromARGBPacked(prop.value, clr);
  196|     21|                mat->AddProperty(&clr, 1, AI_MATKEY_COLOR_SPECULAR);
  197|     21|            }
  198|       |
  199|       |            // NOTE: The 'emissive' property causes problems. It is
  200|       |            // often != 0, even if there is obviously no light
  201|       |            // emitted by the described surface. In fact I think
  202|       |            // IRRLICHT ignores this property, too.
  203|       |#if 0
  204|       |            else if (prop.name == "Emissive") {
  205|       |                ColorFromARGBPacked(prop.value,clr);
  206|       |                mat->AddProperty(&clr,1,AI_MATKEY_COLOR_EMISSIVE);
  207|       |            }
  208|       |#endif
  209|    787|        } else if (!ASSIMP_stricmp(child.name(), "float")) { // Float properties
  ------------------
  |  Branch (209:20): [True: 63, False: 724]
  ------------------
  210|     63|            FloatProperty prop;
  211|     63|            ReadFloatProperty(prop, child);
  212|     63|            if (prop.name == "Shininess") {
  ------------------
  |  Branch (212:17): [True: 21, False: 42]
  ------------------
  213|     21|                mat->AddProperty(&prop.value, 1, AI_MATKEY_SHININESS);
  214|     21|            }
  215|    724|        } else if (!ASSIMP_stricmp(child.name(), "bool")) { // Bool properties
  ------------------
  |  Branch (215:20): [True: 399, False: 325]
  ------------------
  216|    399|            BoolProperty prop;
  217|    399|            ReadBoolProperty(prop, child);
  218|    399|            if (prop.name == "Wireframe") {
  ------------------
  |  Branch (218:17): [True: 21, False: 378]
  ------------------
  219|     21|                int val = (prop.value ? true : false);
  ------------------
  |  Branch (219:28): [True: 0, False: 21]
  ------------------
  220|     21|                mat->AddProperty(&val, 1, AI_MATKEY_ENABLE_WIREFRAME);
  221|    378|            } else if (prop.name == "GouraudShading") {
  ------------------
  |  Branch (221:24): [True: 21, False: 357]
  ------------------
  222|     21|                int val = (prop.value ? aiShadingMode_Gouraud : aiShadingMode_NoShading);
  ------------------
  |  Branch (222:28): [True: 21, False: 0]
  ------------------
  223|     21|                mat->AddProperty(&val, 1, AI_MATKEY_SHADING_MODEL);
  224|    357|            } else if (prop.name == "BackfaceCulling") {
  ------------------
  |  Branch (224:24): [True: 21, False: 336]
  ------------------
  225|     21|                int val = (!prop.value);
  226|     21|                mat->AddProperty(&val, 1, AI_MATKEY_TWOSIDED);
  227|     21|            }
  228|    399|        } else if (!ASSIMP_stricmp(child.name(), "texture") ||
  ------------------
  |  Branch (228:20): [True: 84, False: 241]
  ------------------
  229|    241|                   !ASSIMP_stricmp(child.name(), "enum")) { // String properties - textures and texture related properties
  ------------------
  |  Branch (229:20): [True: 105, False: 136]
  ------------------
  230|    189|            StringProperty prop;
  231|    189|            ReadStringProperty(prop, child);
  232|    189|            if (prop.value.length()) {
  ------------------
  |  Branch (232:17): [True: 129, False: 60]
  ------------------
  233|       |                // material type (shader)
  234|    129|                if (prop.name == "Type") {
  ------------------
  |  Branch (234:21): [True: 21, False: 108]
  ------------------
  235|     21|                    if (prop.value == "solid") {
  ------------------
  |  Branch (235:25): [True: 16, False: 5]
  ------------------
  236|       |                        // default material ...
  237|     16|                    } else if (prop.value == "trans_vertex_alpha") {
  ------------------
  |  Branch (237:32): [True: 2, False: 3]
  ------------------
  238|      2|                        matFlags = AI_IRRMESH_MAT_trans_vertex_alpha;
  ------------------
  |  |   26|      2|#define AI_IRRMESH_MAT_trans_vertex_alpha 0x1
  ------------------
  239|      3|                    } else if (prop.value == "lightmap") {
  ------------------
  |  Branch (239:32): [True: 0, False: 3]
  ------------------
  240|      0|                        matFlags = AI_IRRMESH_MAT_lightmap;
  ------------------
  |  |   30|      0|#define AI_IRRMESH_MAT_lightmap 0x2
  ------------------
  241|      3|                    } else if (prop.value == "solid_2layer") {
  ------------------
  |  Branch (241:32): [True: 0, False: 3]
  ------------------
  242|      0|                        matFlags = AI_IRRMESH_MAT_solid_2layer;
  ------------------
  |  |   23|      0|#define AI_IRRMESH_MAT_solid_2layer 0x10000
  ------------------
  243|      3|                    } else if (prop.value == "lightmap_m2") {
  ------------------
  |  Branch (243:32): [True: 0, False: 3]
  ------------------
  244|      0|                        matFlags = AI_IRRMESH_MAT_lightmap_m2;
  ------------------
  |  |   31|      0|#define AI_IRRMESH_MAT_lightmap_m2 (AI_IRRMESH_MAT_lightmap | 0x4)
  |  |  ------------------
  |  |  |  |   30|      0|#define AI_IRRMESH_MAT_lightmap 0x2
  |  |  ------------------
  ------------------
  245|      3|                    } else if (prop.value == "lightmap_m4") {
  ------------------
  |  Branch (245:32): [True: 3, False: 0]
  ------------------
  246|      3|                        matFlags = AI_IRRMESH_MAT_lightmap_m4;
  ------------------
  |  |   32|      3|#define AI_IRRMESH_MAT_lightmap_m4 (AI_IRRMESH_MAT_lightmap | 0x8)
  |  |  ------------------
  |  |  |  |   30|      3|#define AI_IRRMESH_MAT_lightmap 0x2
  |  |  ------------------
  ------------------
  247|      3|                    } else if (prop.value == "lightmap_light") {
  ------------------
  |  Branch (247:32): [True: 0, False: 0]
  ------------------
  248|      0|                        matFlags = AI_IRRMESH_MAT_lightmap_light;
  ------------------
  |  |   33|      0|#define AI_IRRMESH_MAT_lightmap_light (AI_IRRMESH_MAT_lightmap | 0x10)
  |  |  ------------------
  |  |  |  |   30|      0|#define AI_IRRMESH_MAT_lightmap 0x2
  |  |  ------------------
  ------------------
  249|      0|                    } else if (prop.value == "lightmap_light_m2") {
  ------------------
  |  Branch (249:32): [True: 0, False: 0]
  ------------------
  250|      0|                        matFlags = AI_IRRMESH_MAT_lightmap_light_m2;
  ------------------
  |  |   34|      0|#define AI_IRRMESH_MAT_lightmap_light_m2 (AI_IRRMESH_MAT_lightmap | 0x20)
  |  |  ------------------
  |  |  |  |   30|      0|#define AI_IRRMESH_MAT_lightmap 0x2
  |  |  ------------------
  ------------------
  251|      0|                    } else if (prop.value == "lightmap_light_m4") {
  ------------------
  |  Branch (251:32): [True: 0, False: 0]
  ------------------
  252|      0|                        matFlags = AI_IRRMESH_MAT_lightmap_light_m4;
  ------------------
  |  |   35|      0|#define AI_IRRMESH_MAT_lightmap_light_m4 (AI_IRRMESH_MAT_lightmap | 0x40)
  |  |  ------------------
  |  |  |  |   30|      0|#define AI_IRRMESH_MAT_lightmap 0x2
  |  |  ------------------
  ------------------
  253|      0|                    } else if (prop.value == "lightmap_add") {
  ------------------
  |  Branch (253:32): [True: 0, False: 0]
  ------------------
  254|      0|                        matFlags = AI_IRRMESH_MAT_lightmap_add;
  ------------------
  |  |   36|      0|#define AI_IRRMESH_MAT_lightmap_add (AI_IRRMESH_MAT_lightmap | 0x80)
  |  |  ------------------
  |  |  |  |   30|      0|#define AI_IRRMESH_MAT_lightmap 0x2
  |  |  ------------------
  ------------------
  255|      0|                    } else if (prop.value == "normalmap_solid" ||
  ------------------
  |  Branch (255:32): [True: 0, False: 0]
  ------------------
  256|      0|                               prop.value == "parallaxmap_solid") { // Normal and parallax maps are treated equally
  ------------------
  |  Branch (256:32): [True: 0, False: 0]
  ------------------
  257|      0|                        matFlags = AI_IRRMESH_MAT_normalmap_solid;
  ------------------
  |  |   39|      0|#define AI_IRRMESH_MAT_normalmap_solid (0x100)
  ------------------
  258|      0|                    } else if (prop.value == "normalmap_trans_vertex_alpha" ||
  ------------------
  |  Branch (258:32): [True: 0, False: 0]
  ------------------
  259|      0|                               prop.value == "parallaxmap_trans_vertex_alpha") {
  ------------------
  |  Branch (259:32): [True: 0, False: 0]
  ------------------
  260|      0|                        matFlags = AI_IRRMESH_MAT_normalmap_tva;
  ------------------
  |  |   43|      0|    (AI_IRRMESH_MAT_normalmap_solid | AI_IRRMESH_MAT_trans_vertex_alpha)
  |  |  ------------------
  |  |  |  |   39|      0|#define AI_IRRMESH_MAT_normalmap_solid (0x100)
  |  |  ------------------
  |  |                   (AI_IRRMESH_MAT_normalmap_solid | AI_IRRMESH_MAT_trans_vertex_alpha)
  |  |  ------------------
  |  |  |  |   26|      0|#define AI_IRRMESH_MAT_trans_vertex_alpha 0x1
  |  |  ------------------
  ------------------
  261|      0|                    } else if (prop.value == "normalmap_trans_add" ||
  ------------------
  |  Branch (261:32): [True: 0, False: 0]
  ------------------
  262|      0|                               prop.value == "parallaxmap_trans_add") {
  ------------------
  |  Branch (262:32): [True: 0, False: 0]
  ------------------
  263|      0|                        matFlags = AI_IRRMESH_MAT_normalmap_ta;
  ------------------
  |  |   47|      0|    (AI_IRRMESH_MAT_normalmap_solid | AI_IRRMESH_MAT_trans_add)
  |  |  ------------------
  |  |  |  |   39|      0|#define AI_IRRMESH_MAT_normalmap_solid (0x100)
  |  |  ------------------
  |  |                   (AI_IRRMESH_MAT_normalmap_solid | AI_IRRMESH_MAT_trans_add)
  |  |  ------------------
  |  |  |  |   27|      0|#define AI_IRRMESH_MAT_trans_add 0x2
  |  |  ------------------
  ------------------
  264|      0|                    } else {
  265|      0|                        ASSIMP_LOG_WARN("IRRMat: Unrecognized material type: ", prop.value);
  266|      0|                    }
  267|     21|                }
  268|       |
  269|       |                // Up to 4 texture channels are supported
  270|    129|                if (prop.name == "Texture1") {
  ------------------
  |  Branch (270:21): [True: 21, False: 108]
  ------------------
  271|       |                    // Always accept the primary texture channel
  272|     21|                    ++cnt;
  273|     21|                    s.Set(prop.value);
  274|     21|                    mat->AddProperty(&s, AI_MATKEY_TEXTURE_DIFFUSE(0));
  275|    108|                } else if (prop.name == "Texture2" && cnt == 1) {
  ------------------
  |  Branch (275:28): [True: 3, False: 105]
  |  Branch (275:55): [True: 3, False: 0]
  ------------------
  276|       |                    // 2-layer material lightmapped?
  277|      3|                    if (matFlags & AI_IRRMESH_MAT_lightmap) {
  ------------------
  |  |   30|      3|#define AI_IRRMESH_MAT_lightmap 0x2
  ------------------
  |  Branch (277:25): [True: 3, False: 0]
  ------------------
  278|      3|                        ++cnt;
  279|      3|                        s.Set(prop.value);
  280|      3|                        mat->AddProperty(&s, AI_MATKEY_TEXTURE_LIGHTMAP(0));
  281|       |
  282|       |                        // set the corresponding material flag
  283|      3|                        matFlags |= AI_IRRMESH_EXTRA_2ND_TEXTURE;
  ------------------
  |  |   51|      3|#define AI_IRRMESH_EXTRA_2ND_TEXTURE 0x100000
  ------------------
  284|      3|                    } else if (matFlags & AI_IRRMESH_MAT_normalmap_solid) { // alternatively: normal or parallax mapping
  ------------------
  |  |   39|      0|#define AI_IRRMESH_MAT_normalmap_solid (0x100)
  ------------------
  |  Branch (284:32): [True: 0, False: 0]
  ------------------
  285|      0|                        ++cnt;
  286|      0|                        s.Set(prop.value);
  287|      0|                        mat->AddProperty(&s, AI_MATKEY_TEXTURE_NORMALS(0));
  288|       |
  289|       |                        // set the corresponding material flag
  290|      0|                        matFlags |= AI_IRRMESH_EXTRA_2ND_TEXTURE;
  ------------------
  |  |   51|      0|#define AI_IRRMESH_EXTRA_2ND_TEXTURE 0x100000
  ------------------
  291|      0|                    } else if (matFlags & AI_IRRMESH_MAT_solid_2layer) { // or just as second diffuse texture
  ------------------
  |  |   23|      0|#define AI_IRRMESH_MAT_solid_2layer 0x10000
  ------------------
  |  Branch (291:32): [True: 0, False: 0]
  ------------------
  292|      0|                        ++cnt;
  293|      0|                        s.Set(prop.value);
  294|      0|                        mat->AddProperty(&s, AI_MATKEY_TEXTURE_DIFFUSE(1));
  295|      0|                        ++nd;
  296|       |
  297|       |                        // set the corresponding material flag
  298|      0|                        matFlags |= AI_IRRMESH_EXTRA_2ND_TEXTURE;
  ------------------
  |  |   51|      0|#define AI_IRRMESH_EXTRA_2ND_TEXTURE 0x100000
  ------------------
  299|      0|                    } else {
  300|      0|                        ASSIMP_LOG_WARN("IRRmat: Skipping second texture");
  301|      0|                    }
  302|    105|                } else if (prop.name == "Texture3" && cnt == 2) {
  ------------------
  |  Branch (302:28): [True: 0, False: 105]
  |  Branch (302:55): [True: 0, False: 0]
  ------------------
  303|       |                    // Irrlicht does not seem to use these channels.
  304|      0|                    ++cnt;
  305|      0|                    s.Set(prop.value);
  306|      0|                    mat->AddProperty(&s, AI_MATKEY_TEXTURE_DIFFUSE(nd + 1));
  307|    105|                } else if (prop.name == "Texture4" && cnt == 3) {
  ------------------
  |  Branch (307:28): [True: 0, False: 105]
  |  Branch (307:55): [True: 0, False: 0]
  ------------------
  308|       |                    // Irrlicht does not seem to use these channels.
  309|      0|                    ++cnt;
  310|      0|                    s.Set(prop.value);
  311|      0|                    mat->AddProperty(&s, AI_MATKEY_TEXTURE_DIFFUSE(nd + 2));
  312|      0|                }
  313|       |
  314|       |                // Texture mapping options
  315|    129|                if (prop.name == "TextureWrap1" && cnt >= 1) {
  ------------------
  |  Branch (315:21): [True: 21, False: 108]
  |  Branch (315:52): [True: 21, False: 0]
  ------------------
  316|     21|                    int map = ConvertMappingMode(prop.value);
  317|     21|                    mat->AddProperty(&map, 1, AI_MATKEY_MAPPINGMODE_U_DIFFUSE(0));
  318|     21|                    mat->AddProperty(&map, 1, AI_MATKEY_MAPPINGMODE_V_DIFFUSE(0));
  319|    108|                } else if (prop.name == "TextureWrap2" && cnt >= 2) {
  ------------------
  |  Branch (319:28): [True: 21, False: 87]
  |  Branch (319:59): [True: 3, False: 18]
  ------------------
  320|      3|                    int map = ConvertMappingMode(prop.value);
  321|      3|                    if (matFlags & AI_IRRMESH_MAT_lightmap) {
  ------------------
  |  |   30|      3|#define AI_IRRMESH_MAT_lightmap 0x2
  ------------------
  |  Branch (321:25): [True: 3, False: 0]
  ------------------
  322|      3|                        mat->AddProperty(&map, 1, AI_MATKEY_MAPPINGMODE_U_LIGHTMAP(0));
  323|      3|                        mat->AddProperty(&map, 1, AI_MATKEY_MAPPINGMODE_V_LIGHTMAP(0));
  324|      3|                    } else if (matFlags & (AI_IRRMESH_MAT_normalmap_solid)) {
  ------------------
  |  |   39|      0|#define AI_IRRMESH_MAT_normalmap_solid (0x100)
  ------------------
  |  Branch (324:32): [True: 0, False: 0]
  ------------------
  325|      0|                        mat->AddProperty(&map, 1, AI_MATKEY_MAPPINGMODE_U_NORMALS(0));
  326|      0|                        mat->AddProperty(&map, 1, AI_MATKEY_MAPPINGMODE_V_NORMALS(0));
  327|      0|                    } else if (matFlags & AI_IRRMESH_MAT_solid_2layer) {
  ------------------
  |  |   23|      0|#define AI_IRRMESH_MAT_solid_2layer 0x10000
  ------------------
  |  Branch (327:32): [True: 0, False: 0]
  ------------------
  328|      0|                        mat->AddProperty(&map, 1, AI_MATKEY_MAPPINGMODE_U_DIFFUSE(1));
  329|      0|                        mat->AddProperty(&map, 1, AI_MATKEY_MAPPINGMODE_V_DIFFUSE(1));
  330|      0|                    }
  331|    105|                } else if (prop.name == "TextureWrap3" && cnt >= 3) {
  ------------------
  |  Branch (331:28): [True: 21, False: 84]
  |  Branch (331:59): [True: 0, False: 21]
  ------------------
  332|      0|                    int map = ConvertMappingMode(prop.value);
  333|      0|                    mat->AddProperty(&map, 1, AI_MATKEY_MAPPINGMODE_U_DIFFUSE(nd + 1));
  334|      0|                    mat->AddProperty(&map, 1, AI_MATKEY_MAPPINGMODE_V_DIFFUSE(nd + 1));
  335|    105|                } else if (prop.name == "TextureWrap4" && cnt >= 4) {
  ------------------
  |  Branch (335:28): [True: 21, False: 84]
  |  Branch (335:59): [True: 0, False: 21]
  ------------------
  336|      0|                    int map = ConvertMappingMode(prop.value);
  337|      0|                    mat->AddProperty(&map, 1, AI_MATKEY_MAPPINGMODE_U_DIFFUSE(nd + 2));
  338|      0|                    mat->AddProperty(&map, 1, AI_MATKEY_MAPPINGMODE_V_DIFFUSE(nd + 2));
  339|      0|                }
  340|    129|            }
  341|    189|        }
  342|       |        // break;
  343|       |        /*case EXN_ELEMENT_END:
  344|       |
  345|       |                // Assume there are no further nested nodes in <material> elements
  346|       |                if ( !ASSIMP_stricmp(reader->getNodeName(),"material") ||
  347|       |                     !ASSIMP_stricmp(reader->getNodeName(),"attributes"))
  348|       |                {
  349|       |                    // Now process lightmapping flags
  350|       |                    // We should have at least one textur to do that ..
  351|       |                    if (cnt && matFlags & AI_IRRMESH_MAT_lightmap)
  352|       |                    {
  353|       |                        float f = 1.f;
  354|       |                        unsigned int unmasked = matFlags&~AI_IRRMESH_MAT_lightmap;
  355|       |
  356|       |                        // Additive lightmap?
  357|       |                        int op = (unmasked & AI_IRRMESH_MAT_lightmap_add
  358|       |                            ? aiTextureOp_Add : aiTextureOp_Multiply);
  359|       |
  360|       |                        // Handle Irrlicht's lightmapping scaling factor
  361|       |                        if (unmasked & AI_IRRMESH_MAT_lightmap_m2 ||
  362|       |                            unmasked & AI_IRRMESH_MAT_lightmap_light_m2)
  363|       |                        {
  364|       |                            f = 2.f;
  365|       |                        }
  366|       |                        else if (unmasked & AI_IRRMESH_MAT_lightmap_m4 ||
  367|       |                            unmasked & AI_IRRMESH_MAT_lightmap_light_m4)
  368|       |                        {
  369|       |                            f = 4.f;
  370|       |                        }
  371|       |                        mat->AddProperty( &f, 1, AI_MATKEY_TEXBLEND_LIGHTMAP(0));
  372|       |                        mat->AddProperty( &op,1, AI_MATKEY_TEXOP_LIGHTMAP(0));
  373|       |                    }
  374|       |
  375|       |                    return mat;
  376|       |                }
  377|       |            default:
  378|       |
  379|       |                // GCC complains here ...
  380|       |                break;
  381|       |        }
  382|       |    }*/
  383|    871|    }
  384|       |    //ASSIMP_LOG_ERROR("IRRMESH: Unexpected end of file. Material is not complete");
  385|       |
  386|     69|    return mat;
  387|     69|}

_ZN6Assimp12IrrlichtBaseC2Ev:
   61|  1.24k|    IrrlichtBase() {
   62|       |        // empty
   63|  1.24k|    }
_ZN6Assimp19ColorFromARGBPackedEjR9aiColor4tIfE:
  107|  4.13k|inline void ColorFromARGBPacked(uint32_t in, aiColor4D &clr) {
  108|  4.13k|    clr.a = ((in >> 24) & 0xff) / 255.f;
  109|  4.13k|    clr.r = ((in >> 16) & 0xff) / 255.f;
  110|  4.13k|    clr.g = ((in >> 8) & 0xff) / 255.f;
  111|  4.13k|    clr.b = ((in)&0xff) / 255.f;
  112|  4.13k|}
_ZN6Assimp12IrrlichtBaseD2Ev:
   65|  1.24k|    ~IrrlichtBase() = default;

_ZN6Assimp3LWO12AnimResolverC2ERNSt3__14listINS0_8EnvelopeENS2_9allocatorIS4_EEEEd:
   64|  11.0k|        envelopes(_envelopes),
   65|  11.0k|        sample_rate(0.),
   66|       |        envl_x(),
   67|       |        envl_y(),
   68|       |        envl_z(),
   69|       |        end_x(),
   70|       |        end_y(),
   71|       |        end_z(),
   72|       |        flags(),
   73|  11.0k|        sample_delta() {
   74|  11.0k|    trans_x = trans_y = trans_z = nullptr;
   75|  11.0k|    rotat_x = rotat_y = rotat_z = nullptr;
   76|  11.0k|    scale_x = scale_y = scale_z = nullptr;
   77|       |
   78|  11.0k|    first = last = 150392.;
   79|       |
   80|       |    // find transformation envelopes
   81|  12.2k|    for (std::list<LWO::Envelope>::iterator it = envelopes.begin(); it != envelopes.end(); ++it) {
  ------------------
  |  Branch (81:69): [True: 1.19k, False: 11.0k]
  ------------------
   82|       |
   83|  1.19k|        (*it).old_first = 0;
   84|  1.19k|        (*it).old_last = (*it).keys.size() - 1;
   85|       |
   86|  1.19k|        if ((*it).keys.empty()) {
  ------------------
  |  Branch (86:13): [True: 860, False: 336]
  ------------------
   87|    860|            continue;
   88|    860|        }
   89|    336|        if ((int)(*it).type < 1 || (int)(*it).type>EnvelopeType_Unknown) {
  ------------------
  |  Branch (89:13): [True: 0, False: 336]
  |  Branch (89:36): [True: 0, False: 336]
  ------------------
   90|      0|            continue;
   91|      0|        }
   92|    336|        switch ((*it).type) {
   93|       |        // translation
   94|     15|        case LWO::EnvelopeType_Position_X:
  ------------------
  |  Branch (94:9): [True: 15, False: 321]
  ------------------
   95|     15|            trans_x = &*it;
   96|     15|            break;
   97|    270|        case LWO::EnvelopeType_Position_Y:
  ------------------
  |  Branch (97:9): [True: 270, False: 66]
  ------------------
   98|    270|            trans_y = &*it;
   99|    270|            break;
  100|     13|        case LWO::EnvelopeType_Position_Z:
  ------------------
  |  Branch (100:9): [True: 13, False: 323]
  ------------------
  101|     13|            trans_z = &*it;
  102|     13|            break;
  103|       |
  104|       |            // rotation
  105|     14|        case LWO::EnvelopeType_Rotation_Heading:
  ------------------
  |  Branch (105:9): [True: 14, False: 322]
  ------------------
  106|     14|            rotat_x = &*it;
  107|     14|            break;
  108|      1|        case LWO::EnvelopeType_Rotation_Pitch:
  ------------------
  |  Branch (108:9): [True: 1, False: 335]
  ------------------
  109|      1|            rotat_y = &*it;
  110|      1|            break;
  111|      2|        case LWO::EnvelopeType_Rotation_Bank:
  ------------------
  |  Branch (111:9): [True: 2, False: 334]
  ------------------
  112|      2|            rotat_z = &*it;
  113|      2|            break;
  114|       |
  115|       |            // scaling
  116|     12|        case LWO::EnvelopeType_Scaling_X:
  ------------------
  |  Branch (116:9): [True: 12, False: 324]
  ------------------
  117|     12|            scale_x = &*it;
  118|     12|            break;
  119|      4|        case LWO::EnvelopeType_Scaling_Y:
  ------------------
  |  Branch (119:9): [True: 4, False: 332]
  ------------------
  120|      4|            scale_y = &*it;
  121|      4|            break;
  122|      1|        case LWO::EnvelopeType_Scaling_Z:
  ------------------
  |  Branch (122:9): [True: 1, False: 335]
  ------------------
  123|      1|            scale_z = &*it;
  124|      1|            break;
  125|      4|        default:
  ------------------
  |  Branch (125:9): [True: 4, False: 332]
  ------------------
  126|      4|            continue;
  127|    336|        };
  128|       |
  129|       |        // convert from seconds to ticks
  130|    979|        for (std::vector<LWO::Key>::iterator d = (*it).keys.begin(); d != (*it).keys.end(); ++d)
  ------------------
  |  Branch (130:70): [True: 647, False: 332]
  ------------------
  131|    647|            (*d).time *= tick;
  132|       |
  133|       |        // set default animation range (minimum and maximum time value for which we have a keyframe)
  134|    332|        first = std::min(first, (*it).keys.front().time);
  135|    332|        last = std::max(last, (*it).keys.back().time);
  136|    332|    }
  137|       |
  138|       |    // deferred setup of animation range to increase performance.
  139|       |    // typically the application will want to specify its own.
  140|  11.0k|    need_to_setup = true;
  141|  11.0k|}
_ZN6Assimp3LWO12AnimResolver19ClearAnimRangeSetupEv:
  145|  11.0k|void AnimResolver::ClearAnimRangeSetup() {
  146|  12.2k|    for (std::list<LWO::Envelope>::iterator it = envelopes.begin(); it != envelopes.end(); ++it) {
  ------------------
  |  Branch (146:69): [True: 1.19k, False: 11.0k]
  ------------------
  147|       |
  148|  1.19k|        (*it).keys.erase((*it).keys.begin(), (*it).keys.begin() + (*it).old_first);
  149|  1.19k|        (*it).keys.erase((*it).keys.begin() + (*it).old_last + 1, (*it).keys.end());
  150|  1.19k|    }
  151|  11.0k|}
_ZN6Assimp3LWO12AnimResolver20UpdateAnimRangeSetupEv:
  155|  11.3k|void AnimResolver::UpdateAnimRangeSetup() {
  156|       |    // XXX doesn't work yet (hangs if more than one envelope channels needs to be interpolated)
  157|       |
  158|  13.2k|    for (std::list<LWO::Envelope>::iterator it = envelopes.begin(); it != envelopes.end(); ++it) {
  ------------------
  |  Branch (158:69): [True: 1.91k, False: 11.3k]
  ------------------
  159|  1.91k|        if ((*it).keys.empty()) continue;
  ------------------
  |  Branch (159:13): [True: 1.24k, False: 672]
  ------------------
  160|       |
  161|    672|        const double my_first = (*it).keys.front().time;
  162|    672|        const double my_last = (*it).keys.back().time;
  163|       |
  164|    672|        const double delta = my_last - my_first;
  165|    672|        if (delta == 0.0) {
  ------------------
  |  Branch (165:13): [True: 76, False: 596]
  ------------------
  166|     76|            continue;
  167|     76|        }
  168|       |
  169|    596|        const size_t old_size = (*it).keys.size();
  170|    596|        const float value_delta = (*it).keys.back().value - (*it).keys.front().value;
  171|       |
  172|       |        // NOTE: We won't handle reset, linear and constant here.
  173|       |        // See DoInterpolation() for their implementation.
  174|       |
  175|       |        // process pre behavior
  176|    596|        switch ((*it).pre) {
  177|      0|        case LWO::PrePostBehaviour_OffsetRepeat:
  ------------------
  |  Branch (177:9): [True: 0, False: 596]
  ------------------
  178|      0|        case LWO::PrePostBehaviour_Repeat:
  ------------------
  |  Branch (178:9): [True: 0, False: 596]
  ------------------
  179|      0|        case LWO::PrePostBehaviour_Oscillate: {
  ------------------
  |  Branch (179:9): [True: 0, False: 596]
  ------------------
  180|      0|            const double start_time = delta - std::fmod(my_first - first, delta);
  181|      0|            std::vector<LWO::Key>::iterator n = std::find_if((*it).keys.begin(), (*it).keys.end(),
  182|      0|                                                    [start_time](double t) { return start_time > t; });
  183|      0|            std::vector<LWO::Key>::iterator m;
  184|       |
  185|      0|            size_t ofs = 0;
  186|      0|            if (n != (*it).keys.end()) {
  ------------------
  |  Branch (186:17): [True: 0, False: 0]
  ------------------
  187|       |                // copy from here - don't use iterators, insert() would invalidate them
  188|      0|                ofs = (*it).keys.end() - n;
  189|      0|                (*it).keys.insert((*it).keys.begin(), ofs, LWO::Key());
  190|       |
  191|      0|                std::copy((*it).keys.end() - ofs, (*it).keys.end(), (*it).keys.begin());
  192|      0|            }
  193|       |
  194|       |            // do full copies. again, no iterators
  195|      0|            const unsigned int num = (unsigned int)((my_first - first) / delta);
  196|      0|            (*it).keys.resize((*it).keys.size() + num * old_size);
  197|       |
  198|      0|            n = (*it).keys.begin() + ofs;
  199|      0|            bool reverse = false;
  200|      0|            for (unsigned int i = 0; i < num; ++i) {
  ------------------
  |  Branch (200:38): [True: 0, False: 0]
  ------------------
  201|      0|                m = n + old_size * (i + 1);
  202|      0|                std::copy(n, n + old_size, m);
  203|      0|                const bool res = ((*it).pre == LWO::PrePostBehaviour_Oscillate);
  204|      0|                reverse = !reverse;
  205|      0|                if (res && reverse) {
  ------------------
  |  Branch (205:21): [True: 0, False: 0]
  |  Branch (205:28): [True: 0, False: 0]
  ------------------
  206|      0|                    std::reverse(m, m + old_size - 1);
  207|      0|                }
  208|      0|            }
  209|       |
  210|       |            // update time values
  211|      0|            n = (*it).keys.end() - (old_size + 1);
  212|      0|            double cur_minus = delta;
  213|      0|            unsigned int tt = 1;
  214|      0|            for (const double tmp = delta * (num + 1); cur_minus <= tmp; cur_minus += delta, ++tt) {
  ------------------
  |  Branch (214:56): [True: 0, False: 0]
  ------------------
  215|      0|                if (delta == tmp) {
  ------------------
  |  Branch (215:21): [True: 0, False: 0]
  ------------------
  216|      0|                    m = it->keys.begin();
  217|      0|                } else {
  218|      0|                    ptrdiff_t dist = std::distance((*it).keys.begin(), n);
  219|      0|                    if (dist <= static_cast<ptrdiff_t>(old_size)) {
  ------------------
  |  Branch (219:25): [True: 0, False: 0]
  ------------------
  220|       |                        // clamp to begin to avoid seeking before begin
  221|      0|                        m = (*it).keys.begin();
  222|      0|                    } else {
  223|      0|                        m = n - (old_size + 1);
  224|      0|                    }
  225|      0|                }
  226|      0|                for (auto it2 = m; it2 != n; ++it2) {
  ------------------
  |  Branch (226:36): [True: 0, False: 0]
  ------------------
  227|      0|                    it2->time -= cur_minus;
  228|      0|                    if ((*it).pre == LWO::PrePostBehaviour_OffsetRepeat) {
  ------------------
  |  Branch (228:25): [True: 0, False: 0]
  ------------------
  229|      0|                        it2->value += tt * value_delta;
  230|      0|                    }
  231|      0|                }
  232|      0|            }
  233|      0|            break;
  234|      0|        }
  235|    596|        default:
  ------------------
  |  Branch (235:9): [True: 596, False: 0]
  ------------------
  236|       |            // silence compiler warning
  237|    596|            break;
  238|    596|        }
  239|       |
  240|       |        // process post behavior
  241|    596|        switch ((*it).post) {
  242|       |
  243|      0|        case LWO::PrePostBehaviour_OffsetRepeat:
  ------------------
  |  Branch (243:9): [True: 0, False: 596]
  ------------------
  244|      0|        case LWO::PrePostBehaviour_Repeat:
  ------------------
  |  Branch (244:9): [True: 0, False: 596]
  ------------------
  245|      0|        case LWO::PrePostBehaviour_Oscillate:
  ------------------
  |  Branch (245:9): [True: 0, False: 596]
  ------------------
  246|       |
  247|      0|            break;
  248|       |
  249|    596|        default:
  ------------------
  |  Branch (249:9): [True: 596, False: 0]
  ------------------
  250|       |            // silence compiler warning
  251|    596|            break;
  252|    596|        }
  253|    596|    }
  254|  11.3k|}
_ZN6Assimp3LWO12AnimResolver15ExtractBindPoseER12aiMatrix4x4tIfE:
  258|  11.0k|void AnimResolver::ExtractBindPose(aiMatrix4x4 &out) {
  259|       |    // If we have no envelopes, return identity
  260|  11.0k|    if (envelopes.empty()) {
  ------------------
  |  Branch (260:9): [True: 10.5k, False: 520]
  ------------------
  261|  10.5k|        out = aiMatrix4x4();
  262|  10.5k|        return;
  263|  10.5k|    }
  264|    520|    aiVector3D angles, scaling(1.f, 1.f, 1.f), translation;
  265|       |
  266|    520|    if (trans_x) translation.x = trans_x->keys[0].value;
  ------------------
  |  Branch (266:9): [True: 14, False: 506]
  ------------------
  267|    520|    if (trans_y) translation.y = trans_y->keys[0].value;
  ------------------
  |  Branch (267:9): [True: 269, False: 251]
  ------------------
  268|    520|    if (trans_z) translation.z = trans_z->keys[0].value;
  ------------------
  |  Branch (268:9): [True: 12, False: 508]
  ------------------
  269|       |
  270|    520|    if (rotat_x) angles.x = rotat_x->keys[0].value;
  ------------------
  |  Branch (270:9): [True: 13, False: 507]
  ------------------
  271|    520|    if (rotat_y) angles.y = rotat_y->keys[0].value;
  ------------------
  |  Branch (271:9): [True: 1, False: 519]
  ------------------
  272|    520|    if (rotat_z) angles.z = rotat_z->keys[0].value;
  ------------------
  |  Branch (272:9): [True: 2, False: 518]
  ------------------
  273|       |
  274|    520|    if (scale_x) scaling.x = scale_x->keys[0].value;
  ------------------
  |  Branch (274:9): [True: 11, False: 509]
  ------------------
  275|    520|    if (scale_y) scaling.y = scale_y->keys[0].value;
  ------------------
  |  Branch (275:9): [True: 4, False: 516]
  ------------------
  276|    520|    if (scale_z) scaling.z = scale_z->keys[0].value;
  ------------------
  |  Branch (276:9): [True: 1, False: 519]
  ------------------
  277|       |
  278|       |    // build the final matrix
  279|    520|    aiMatrix4x4 s, rx, ry, rz, t;
  280|    520|    aiMatrix4x4::RotationZ(angles.z, rz);
  281|    520|    aiMatrix4x4::RotationX(angles.y, rx);
  282|    520|    aiMatrix4x4::RotationY(angles.x, ry);
  283|    520|    aiMatrix4x4::Translation(translation, t);
  284|    520|    aiMatrix4x4::Scaling(scaling, s);
  285|    520|    out = t * ry * rx * rz * s;
  286|    520|}
_ZN6Assimp3LWO12AnimResolver15DoInterpolationENSt3__111__wrap_iterIPKNS0_3KeyEEEPNS0_8EnvelopeEdRf:
  291|    894|        LWO::Envelope *envl, double time, float &fill) {
  292|    894|    if (envl->keys.size() == 1) {
  ------------------
  |  Branch (292:9): [True: 602, False: 292]
  ------------------
  293|    602|        fill = envl->keys[0].value;
  294|    602|        return;
  295|    602|    }
  296|       |
  297|       |    // check whether we're at the beginning of the animation track
  298|    292|    if (cur == envl->keys.begin()) {
  ------------------
  |  Branch (298:9): [True: 281, False: 11]
  ------------------
  299|       |
  300|       |        // ok ... this depends on pre behaviour now
  301|       |        // we don't need to handle repeat&offset repeat&oszillate here, see UpdateAnimRangeSetup()
  302|    281|        switch (envl->pre) {
  303|      0|        case LWO::PrePostBehaviour_Linear:
  ------------------
  |  Branch (303:9): [True: 0, False: 281]
  ------------------
  304|      0|            DoInterpolation2(cur, cur + 1, time, fill);
  305|      0|            return;
  306|       |
  307|      2|        case LWO::PrePostBehaviour_Reset:
  ------------------
  |  Branch (307:9): [True: 2, False: 279]
  ------------------
  308|      2|            fill = 0.f;
  309|      2|            return;
  310|       |
  311|    279|        default: //case LWO::PrePostBehaviour_Constant:
  ------------------
  |  Branch (311:9): [True: 279, False: 2]
  ------------------
  312|    279|            fill = (*cur).value;
  313|    279|            return;
  314|    281|        }
  315|    281|    }
  316|       |    // check whether we're at the end of the animation track
  317|     11|    else if (cur == envl->keys.end() - 1 && time > envl->keys.rbegin()->time) {
  ------------------
  |  Branch (317:14): [True: 11, False: 0]
  |  Branch (317:14): [True: 1, False: 10]
  |  Branch (317:45): [True: 1, False: 10]
  ------------------
  318|       |        // ok ... this depends on post behaviour now
  319|      1|        switch (envl->post) {
  320|      0|        case LWO::PrePostBehaviour_Linear:
  ------------------
  |  Branch (320:9): [True: 0, False: 1]
  ------------------
  321|      0|            DoInterpolation2(cur, cur - 1, time, fill);
  322|      0|            return;
  323|       |
  324|      0|        case LWO::PrePostBehaviour_Reset:
  ------------------
  |  Branch (324:9): [True: 0, False: 1]
  ------------------
  325|      0|            fill = 0.f;
  326|      0|            return;
  327|       |
  328|      1|        default: //case LWO::PrePostBehaviour_Constant:
  ------------------
  |  Branch (328:9): [True: 1, False: 0]
  ------------------
  329|      1|            fill = (*cur).value;
  330|      1|            return;
  331|      1|        }
  332|      1|    }
  333|       |
  334|       |    // Otherwise do a simple interpolation
  335|     10|    DoInterpolation2(cur - 1, cur, time, fill);
  336|     10|}
_ZN6Assimp3LWO12AnimResolver16DoInterpolation2ENSt3__111__wrap_iterIPKNS0_3KeyEEES7_dRf:
  341|     10|        std::vector<LWO::Key>::const_iterator end, double time, float &fill) {
  342|     10|    switch ((*end).inter) {
  343|       |
  344|      0|    case LWO::IT_STEP:
  ------------------
  |  Branch (344:5): [True: 0, False: 10]
  ------------------
  345|       |        // no interpolation at all - take the value of the last key
  346|      0|        fill = (*beg).value;
  347|      0|        return;
  348|     10|    default:
  ------------------
  |  Branch (348:5): [True: 10, False: 0]
  ------------------
  349|       |
  350|       |        // silence compiler warning
  351|     10|        break;
  352|     10|    }
  353|       |    // linear interpolation - default
  354|     10|    double duration = (*end).time - (*beg).time;
  355|     10|    if (duration > 0.0) {
  ------------------
  |  Branch (355:9): [True: 10, False: 0]
  ------------------
  356|     10|        fill = (*beg).value + ((*end).value - (*beg).value) * (float)(((time - (*beg).time) / duration));
  357|     10|    } else {
  358|      0|        fill = (*beg).value;
  359|      0|    }
  360|     10|}
_ZN6Assimp3LWO12AnimResolver16InterpolateTrackERNSt3__16vectorI11aiVectorKeyNS2_9allocatorIS4_EEEERS4_d:
  374|    592|void AnimResolver::InterpolateTrack(std::vector<aiVectorKey> &out, aiVectorKey &fill, double time) {
  375|       |    // subsample animation track?
  376|    592|    if (flags & AI_LWO_ANIM_FLAG_SAMPLE_ANIMS) {
  ------------------
  |  |  177|    592|#define AI_LWO_ANIM_FLAG_SAMPLE_ANIMS 0x1
  ------------------
  |  Branch (376:9): [True: 0, False: 592]
  ------------------
  377|      0|        SubsampleAnimTrack(out, time, sample_delta);
  378|      0|    }
  379|       |
  380|    592|    fill.mTime = time;
  381|       |
  382|       |    // get x
  383|    592|    if ((*cur_x).time == time) {
  ------------------
  |  Branch (383:9): [True: 286, False: 306]
  ------------------
  384|    286|        fill.mValue.x = (*cur_x).value;
  385|       |
  386|    286|        if (cur_x != envl_x->keys.end() - 1) /* increment x */
  ------------------
  |  Branch (386:13): [True: 13, False: 273]
  ------------------
  387|     13|            ++cur_x;
  388|    273|        else
  389|    273|            end_x = true;
  390|    286|    } else
  391|    306|        DoInterpolation(cur_x, envl_x, time, (float &)fill.mValue.x);
  392|       |
  393|       |    // get y
  394|    592|    if ((*cur_y).time == time) {
  ------------------
  |  Branch (394:9): [True: 317, False: 275]
  ------------------
  395|    317|        fill.mValue.y = (*cur_y).value;
  396|       |
  397|    317|        if (cur_y != envl_y->keys.end() - 1) /* increment y */
  ------------------
  |  Branch (397:13): [True: 285, False: 32]
  ------------------
  398|    285|            ++cur_y;
  399|     32|        else
  400|     32|            end_y = true;
  401|    317|    } else
  402|    275|        DoInterpolation(cur_y, envl_y, time, (float &)fill.mValue.y);
  403|       |
  404|       |    // get z
  405|    592|    if ((*cur_z).time == time) {
  ------------------
  |  Branch (405:9): [True: 279, False: 313]
  ------------------
  406|    279|        fill.mValue.z = (*cur_z).value;
  407|       |
  408|    279|        if (cur_z != envl_z->keys.end() - 1) /* increment z */
  ------------------
  |  Branch (408:13): [True: 1, False: 278]
  ------------------
  409|      1|            ++cur_z;
  410|    278|        else
  411|    278|            end_x = true;
  412|    279|    } else
  413|    313|        DoInterpolation(cur_z, envl_z, time, (float &)fill.mValue.z);
  414|    592|}
_ZN6Assimp3LWO12AnimResolver7GetKeysERNSt3__16vectorI11aiVectorKeyNS2_9allocatorIS4_EEEEPNS0_8EnvelopeESA_SA_j:
  422|    292|        unsigned int _flags) {
  423|    292|    envl_x = _envl_x;
  424|    292|    envl_y = _envl_y;
  425|    292|    envl_z = _envl_z;
  426|    292|    flags = _flags;
  427|       |
  428|       |    // generate default channels if none are given
  429|    292|    LWO::Envelope def_x, def_y, def_z;
  430|    292|    LWO::Key key_dummy;
  431|    292|    key_dummy.time = 0.f;
  432|    292|    if ((envl_x && envl_x->type == LWO::EnvelopeType_Scaling_X) ||
  ------------------
  |  Branch (432:10): [True: 23, False: 269]
  |  Branch (432:20): [True: 0, False: 23]
  ------------------
  433|    292|            (envl_y && envl_y->type == LWO::EnvelopeType_Scaling_Y) ||
  ------------------
  |  Branch (433:14): [True: 274, False: 18]
  |  Branch (433:24): [True: 4, False: 270]
  ------------------
  434|    288|            (envl_z && envl_z->type == LWO::EnvelopeType_Scaling_Z)) {
  ------------------
  |  Branch (434:14): [True: 14, False: 274]
  |  Branch (434:24): [True: 0, False: 14]
  ------------------
  435|      4|        key_dummy.value = 1.f;
  436|      4|    } else
  437|    288|        key_dummy.value = 0.f;
  438|       |
  439|    292|    if (!envl_x) {
  ------------------
  |  Branch (439:9): [True: 269, False: 23]
  ------------------
  440|    269|        envl_x = &def_x;
  441|    269|        envl_x->keys.push_back(key_dummy);
  442|    269|    }
  443|    292|    if (!envl_y) {
  ------------------
  |  Branch (443:9): [True: 18, False: 274]
  ------------------
  444|     18|        envl_y = &def_y;
  445|     18|        envl_y->keys.push_back(key_dummy);
  446|     18|    }
  447|    292|    if (!envl_z) {
  ------------------
  |  Branch (447:9): [True: 278, False: 14]
  ------------------
  448|    278|        envl_z = &def_z;
  449|    278|        envl_z->keys.push_back(key_dummy);
  450|    278|    }
  451|       |
  452|       |    // guess how many keys we'll get
  453|    292|    size_t reserve;
  454|    292|    double sr = 1.;
  455|    292|    if (flags & AI_LWO_ANIM_FLAG_SAMPLE_ANIMS) {
  ------------------
  |  |  177|    292|#define AI_LWO_ANIM_FLAG_SAMPLE_ANIMS 0x1
  ------------------
  |  Branch (455:9): [True: 0, False: 292]
  ------------------
  456|      0|        if (!sample_rate)
  ------------------
  |  Branch (456:13): [True: 0, False: 0]
  ------------------
  457|      0|            sr = 100.f;
  458|      0|        else
  459|      0|            sr = sample_rate;
  460|      0|        sample_delta = 1.f / sr;
  461|       |
  462|      0|        reserve = (size_t)(
  463|      0|                std::max(envl_x->keys.rbegin()->time,
  464|      0|                        std::max(envl_y->keys.rbegin()->time, envl_z->keys.rbegin()->time)) *
  465|      0|                sr);
  466|      0|    } else
  467|    292|        reserve = std::max(envl_x->keys.size(), std::max(envl_x->keys.size(), envl_z->keys.size()));
  468|    292|    out.reserve(reserve + (reserve >> 1));
  469|       |
  470|       |    // Iterate through all three arrays at once - it's tricky, but
  471|       |    // rather interesting to implement.
  472|    292|    cur_x = envl_x->keys.begin();
  473|    292|    cur_y = envl_y->keys.begin();
  474|    292|    cur_z = envl_z->keys.begin();
  475|       |
  476|    292|    end_x = end_y = end_z = false;
  477|    593|    while (true) {
  ------------------
  |  Branch (477:12): [True: 593, Folded]
  ------------------
  478|       |
  479|    593|        aiVectorKey fill;
  480|       |
  481|    593|        if ((*cur_x).time == (*cur_y).time && (*cur_x).time == (*cur_z).time) {
  ------------------
  |  Branch (481:13): [True: 21, False: 572]
  |  Branch (481:47): [True: 1, False: 20]
  ------------------
  482|       |
  483|       |            // we have a keyframe for all of them defined .. this means
  484|       |            // we don't need to interpolate here.
  485|      1|            fill.mTime = (*cur_x).time;
  486|       |
  487|      1|            fill.mValue.x = (*cur_x).value;
  488|      1|            fill.mValue.y = (*cur_y).value;
  489|      1|            fill.mValue.z = (*cur_z).value;
  490|       |
  491|       |            // subsample animation track
  492|      1|            if (flags & AI_LWO_ANIM_FLAG_SAMPLE_ANIMS) {
  ------------------
  |  |  177|      1|#define AI_LWO_ANIM_FLAG_SAMPLE_ANIMS 0x1
  ------------------
  |  Branch (492:17): [True: 0, False: 1]
  ------------------
  493|       |                //SubsampleAnimTrack(out,cur_x, cur_y, cur_z, d, sample_delta);
  494|      0|            }
  495|      1|        }
  496|       |
  497|       |        // Find key with lowest time value
  498|    592|        else if ((*cur_x).time <= (*cur_y).time && !end_x) {
  ------------------
  |  Branch (498:18): [True: 555, False: 37]
  |  Branch (498:52): [True: 282, False: 273]
  ------------------
  499|       |
  500|    282|            if ((*cur_z).time <= (*cur_x).time && !end_z) {
  ------------------
  |  Branch (500:17): [True: 272, False: 10]
  |  Branch (500:51): [True: 260, False: 12]
  ------------------
  501|    260|                InterpolateTrack(out, fill, (*cur_z).time);
  502|    260|            } else {
  503|     22|                InterpolateTrack(out, fill, (*cur_x).time);
  504|     22|            }
  505|    310|        } else if ((*cur_z).time <= (*cur_y).time && !end_y) {
  ------------------
  |  Branch (505:20): [True: 302, False: 8]
  |  Branch (505:54): [True: 302, False: 0]
  ------------------
  506|    302|            InterpolateTrack(out, fill, (*cur_y).time);
  507|    302|        } else if (!end_y) {
  ------------------
  |  Branch (507:20): [True: 3, False: 5]
  ------------------
  508|       |            // welcome on the server, y
  509|      3|            InterpolateTrack(out, fill, (*cur_y).time);
  510|      5|        } else {
  511|       |            // we have reached the end of at least 2 channels,
  512|       |            // only one is remaining. Extrapolate the 2.
  513|      5|            if (end_y) {
  ------------------
  |  Branch (513:17): [True: 5, False: 0]
  ------------------
  514|      5|                InterpolateTrack(out, fill, (end_x ? (*cur_z) : (*cur_x)).time);
  ------------------
  |  Branch (514:46): [True: 1, False: 4]
  ------------------
  515|      5|            } else if (end_x) {
  ------------------
  |  Branch (515:24): [True: 0, False: 0]
  ------------------
  516|      0|                InterpolateTrack(out, fill, (end_z ? (*cur_y) : (*cur_z)).time);
  ------------------
  |  Branch (516:46): [True: 0, False: 0]
  ------------------
  517|      0|            } else { // if (end_z)
  518|      0|                InterpolateTrack(out, fill, (end_y ? (*cur_x) : (*cur_y)).time);
  ------------------
  |  Branch (518:46): [True: 0, False: 0]
  ------------------
  519|      0|            }
  520|      5|        }
  521|    593|        double lasttime = fill.mTime;
  522|    593|        out.push_back(fill);
  523|       |
  524|    593|        if (lasttime >= (*cur_x).time) {
  ------------------
  |  Branch (524:13): [True: 545, False: 48]
  ------------------
  525|    545|            if (cur_x != envl_x->keys.end() - 1)
  ------------------
  |  Branch (525:17): [True: 0, False: 545]
  ------------------
  526|      0|                ++cur_x;
  527|    545|            else
  528|    545|                end_x = true;
  529|    545|        }
  530|    593|        if (lasttime >= (*cur_y).time) {
  ------------------
  |  Branch (530:13): [True: 298, False: 295]
  ------------------
  531|    298|            if (cur_y != envl_y->keys.end() - 1)
  ------------------
  |  Branch (531:17): [True: 1, False: 297]
  ------------------
  532|      1|                ++cur_y;
  533|    297|            else
  534|    297|                end_y = true;
  535|    298|        }
  536|    593|        if (lasttime >= (*cur_z).time) {
  ------------------
  |  Branch (536:13): [True: 577, False: 16]
  ------------------
  537|    577|            if (cur_z != envl_z->keys.end() - 1)
  ------------------
  |  Branch (537:17): [True: 0, False: 577]
  ------------------
  538|      0|                ++cur_z;
  539|    577|            else
  540|    577|                end_z = true;
  541|    577|        }
  542|       |
  543|    593|        if (end_x && end_y && end_z) /* finished? */
  ------------------
  |  Branch (543:13): [True: 566, False: 27]
  |  Branch (543:22): [True: 293, False: 273]
  |  Branch (543:31): [True: 292, False: 1]
  ------------------
  544|    292|            break;
  545|    593|    }
  546|       |
  547|    292|    if (flags & AI_LWO_ANIM_FLAG_START_AT_ZERO) {
  ------------------
  |  |  183|    292|#define AI_LWO_ANIM_FLAG_START_AT_ZERO 0x2
  ------------------
  |  Branch (547:9): [True: 0, False: 292]
  ------------------
  548|      0|        for (std::vector<aiVectorKey>::iterator it = out.begin(); it != out.end(); ++it)
  ------------------
  |  Branch (548:67): [True: 0, False: 0]
  ------------------
  549|      0|            (*it).mTime -= first;
  550|      0|    }
  551|    292|}
_ZN6Assimp3LWO12AnimResolver18ExtractAnimChannelEPP10aiNodeAnimj:
  555|  11.0k|void AnimResolver::ExtractAnimChannel(aiNodeAnim **out, unsigned int /*= 0*/) {
  556|  11.0k|    *out = nullptr;
  557|       |
  558|       |    //FIXME: crashes if more than one component is animated at different timings, to be resolved.
  559|       |
  560|       |    // If we have no envelopes, return nullptr
  561|  11.0k|    if (envelopes.empty()) {
  ------------------
  |  Branch (561:9): [True: 10.5k, False: 520]
  ------------------
  562|  10.5k|        return;
  563|  10.5k|    }
  564|       |
  565|       |    // We won't spawn an animation channel if we don't have at least one envelope with more than one keyframe defined.
  566|    520|    const bool trans = ((trans_x && trans_x->keys.size() > 1) || (trans_y && trans_y->keys.size() > 1) || (trans_z && trans_z->keys.size() > 1));
  ------------------
  |  Branch (566:26): [True: 14, False: 506]
  |  Branch (566:37): [True: 10, False: 4]
  |  Branch (566:67): [True: 265, False: 245]
  |  Branch (566:78): [True: 265, False: 0]
  |  Branch (566:108): [True: 0, False: 245]
  |  Branch (566:119): [True: 0, False: 0]
  ------------------
  567|    520|    const bool rotat = ((rotat_x && rotat_x->keys.size() > 1) || (rotat_y && rotat_y->keys.size() > 1) || (rotat_z && rotat_z->keys.size() > 1));
  ------------------
  |  Branch (567:26): [True: 13, False: 507]
  |  Branch (567:37): [True: 13, False: 0]
  |  Branch (567:67): [True: 0, False: 507]
  |  Branch (567:78): [True: 0, False: 0]
  |  Branch (567:108): [True: 0, False: 507]
  |  Branch (567:119): [True: 0, False: 0]
  ------------------
  568|    520|    const bool scale = ((scale_x && scale_x->keys.size() > 1) || (scale_y && scale_y->keys.size() > 1) || (scale_z && scale_z->keys.size() > 1));
  ------------------
  |  Branch (568:26): [True: 11, False: 509]
  |  Branch (568:37): [True: 0, False: 11]
  |  Branch (568:67): [True: 4, False: 516]
  |  Branch (568:78): [True: 4, False: 0]
  |  Branch (568:108): [True: 1, False: 515]
  |  Branch (568:119): [True: 0, False: 1]
  ------------------
  569|    520|    if (!trans && !rotat && !scale)
  ------------------
  |  Branch (569:9): [True: 245, False: 275]
  |  Branch (569:19): [True: 245, False: 0]
  |  Branch (569:29): [True: 241, False: 4]
  ------------------
  570|    241|        return;
  571|       |
  572|       |    // Allocate the output animation
  573|    279|    aiNodeAnim *anim = *out = new aiNodeAnim();
  574|       |
  575|       |    // Setup default animation setup if necessary
  576|    279|    if (need_to_setup) {
  ------------------
  |  Branch (576:9): [True: 279, False: 0]
  ------------------
  577|    279|        UpdateAnimRangeSetup();
  578|    279|        need_to_setup = false;
  579|    279|    }
  580|       |
  581|       |    // copy translation keys
  582|    279|    if (trans) {
  ------------------
  |  Branch (582:9): [True: 275, False: 4]
  ------------------
  583|    275|        std::vector<aiVectorKey> keys;
  584|    275|        GetKeys(keys, trans_x, trans_y, trans_z, flags);
  585|       |
  586|    275|        anim->mPositionKeys = new aiVectorKey[anim->mNumPositionKeys = static_cast<unsigned int>(keys.size())];
  587|    275|        std::copy(keys.begin(), keys.end(), anim->mPositionKeys);
  588|    275|    }
  589|       |
  590|       |    // copy rotation keys
  591|    279|    if (rotat) {
  ------------------
  |  Branch (591:9): [True: 13, False: 266]
  ------------------
  592|     13|        std::vector<aiVectorKey> keys;
  593|     13|        GetKeys(keys, rotat_x, rotat_y, rotat_z, flags);
  594|       |
  595|     13|        anim->mRotationKeys = new aiQuatKey[anim->mNumRotationKeys = static_cast<unsigned int>(keys.size())];
  596|       |
  597|       |        // convert heading, pitch, bank to quaternion
  598|       |        // mValue.x=Heading=Rot(Y), mValue.y=Pitch=Rot(X), mValue.z=Bank=Rot(Z)
  599|       |        // Lightwave's rotation order is ZXY
  600|     13|        aiVector3D X(1.0, 0.0, 0.0);
  601|     13|        aiVector3D Y(0.0, 1.0, 0.0);
  602|     13|        aiVector3D Z(0.0, 0.0, 1.0);
  603|     31|        for (unsigned int i = 0; i < anim->mNumRotationKeys; ++i) {
  ------------------
  |  Branch (603:34): [True: 18, False: 13]
  ------------------
  604|     18|            aiQuatKey &qk = anim->mRotationKeys[i];
  605|     18|            qk.mTime = keys[i].mTime;
  606|     18|            qk.mValue = aiQuaternion(Y, keys[i].mValue.x) * aiQuaternion(X, keys[i].mValue.y) * aiQuaternion(Z, keys[i].mValue.z);
  607|     18|        }
  608|     13|    }
  609|       |
  610|       |    // copy scaling keys
  611|    279|    if (scale) {
  ------------------
  |  Branch (611:9): [True: 4, False: 275]
  ------------------
  612|      4|        std::vector<aiVectorKey> keys;
  613|      4|        GetKeys(keys, scale_x, scale_y, scale_z, flags);
  614|       |
  615|      4|        anim->mScalingKeys = new aiVectorKey[anim->mNumScalingKeys = static_cast<unsigned int>(keys.size())];
  616|      4|        std::copy(keys.begin(), keys.end(), anim->mScalingKeys);
  617|      4|    }
  618|    279|}

_ZN6Assimp3LWO3KeyC2Ev:
  119|    967|    , inter(IT_LINE)
  120|    967|    , params() {
  121|       |        // empty
  122|    967|    }
_ZN6Assimp3LWO8EnvelopeC2Ev:
  149|  2.33k|    , type(EnvelopeType_Unknown)
  150|  2.33k|    , pre(PrePostBehaviour_Constant)
  151|  2.33k|    , post(PrePostBehaviour_Constant)
  152|  2.33k|    , old_first(0)
  153|  2.33k|    , old_last(0) {
  154|       |        // empty
  155|  2.33k|    }
_ZN6Assimp3LWO12AnimResolver17SetAnimationRangeEdd:
  246|  11.0k|    void SetAnimationRange(double _first, double _last) {
  247|  11.0k|        first = _first;
  248|  11.0k|        last  = _last;
  249|       |
  250|  11.0k|        ClearAnimRangeSetup();
  251|  11.0k|        UpdateAnimRangeSetup();
  252|  11.0k|    }

_ZN6Assimp3LWO4FaceC2Ej:
  323|     21|            surfaceIndex(0), smoothGroup(0), type(_type) {}
_ZN6Assimp3LWO4FaceC2ERKS1_:
  327|  5.73k|            aiFace() {
  328|  5.73k|        *this = f;
  329|  5.73k|    }
_ZN6Assimp3LWO9VMapEntryC2Ej:
  349|     55|            dims(_dims) {}
_ZN6Assimp3LWO9VMapEntry8AllocateEj:
  354|     23|    virtual void Allocate(unsigned int num) {
  355|     23|        if (!rawData.empty())
  ------------------
  |  Branch (355:13): [True: 5, False: 18]
  ------------------
  356|      5|            return; // return if already allocated
  357|       |
  358|     18|        const unsigned int m = num * dims;
  359|     18|        rawData.reserve(m + (m >> 2u)); // 25% as  extra storage for VMADs
  360|     18|        rawData.resize(m, 0.f);
  361|     18|        abAssigned.resize(num, false);
  362|     18|    }
_ZN6Assimp3LWO13VColorChannelC2Ev:
  376|      2|            VMapEntry(4) {}
_ZN6Assimp3LWO13VColorChannel8AllocateEj:
  380|      3|    virtual void Allocate(unsigned int num) {
  381|      3|        if (!rawData.empty())
  ------------------
  |  Branch (381:13): [True: 1, False: 2]
  ------------------
  382|      1|            return; // return if already allocated
  383|       |
  384|      2|        unsigned int m = num * dims;
  385|      2|        rawData.reserve(m + (m >> 2u)); // 25% as  extra storage for VMADs
  386|      2|        rawData.resize(m);
  387|       |
  388|    438|        for (aiColor4D *p = (aiColor4D *)&rawData[0]; p < (aiColor4D *)&rawData[m - 1]; ++p)
  ------------------
  |  Branch (388:55): [True: 436, False: 2]
  ------------------
  389|    436|            p->a = 1.f;
  390|       |
  391|      2|        abAssigned.resize(num, false);
  392|      2|    }
_ZN6Assimp3LWO9UVChannelC2Ev:
  400|      8|            VMapEntry(2) {}
_ZN6Assimp3LWO13WeightChannelC2Ev:
  408|      6|            VMapEntry(1) {}
_ZN6Assimp3LWO13NormalChannelC2Ev:
  416|     39|            VMapEntry(3) {}
_ZN6Assimp3LWO7TextureC2Ev:
  458|      2|            mClipIdx(UINT_MAX), mStrength(1.0f), type(), mUVChannelIndex("unknown"), mRealUVIndex(UINT_MAX), enabled(true), blendType(Additive), bCanUse(true), mapMode(UV), majorAxis(AXIS_X), wrapAmountH(1.0f), wrapAmountW(1.0f), wrapModeWidth(REPEAT), wrapModeHeight(REPEAT), ordinal("\x00") {}
_ZN6Assimp3LWO4ClipC2Ev:
  512|      2|            type(UNSUPPORTED), clipRef(), idx(0), negate(false) {}
_ZN6Assimp3LWO7SurfaceC2Ev:
  549|     15|            mColor(0.78431f, 0.78431f, 0.78431f), bDoubleSided(false), mDiffuseValue(1.f), mSpecularValue(0.f), mTransparency(0.f), mGlossiness(0.4f), mLuminosity(0.f), mColorHighlights(0.f), mMaximumSmoothAngle(0.f) // 0 == not specified, no smoothing
  550|       |            ,
  551|     15|            mVCMap(),
  552|       |            mVCMapType(AI_LWO_RGBA),
  553|     15|            mIOR(1.f) // vakuum
  554|       |            ,
  555|     15|            mBumpIntensity(1.f),
  556|     15|            mWireframe(false),
  557|     15|            mAdditiveTransparency(0.f) {}
_ZN6Assimp3LWO5LayerC2Ev:
  654|     39|            mFaceIDXOfs(0), mPointIDXOfs(0), mParent(0x0), mIndex(0xffff), skip(false) {}
_ZN6Assimp3LWO9VMapEntryD2Ev:
  351|    115|    virtual ~VMapEntry() = default;
_ZN6Assimp3LWO4FaceaSERKS1_:
  341|  5.73k|    Face &operator=(const LWO::Face &f) = default;

_ZNK6Assimp11LWOImporter7CanReadERKNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEPNS_8IOSystemEb:
   82|    395|bool LWOImporter::CanRead(const std::string &file, IOSystem *pIOHandler, bool /*checkSig*/) const {
   83|    395|    static constexpr uint32_t tokens[] = {
   84|    395|        AI_LWO_FOURCC_LWOB,
  ------------------
  |  |   65|    395|#define AI_LWO_FOURCC_LWOB AI_IFF_FOURCC('L', 'W', 'O', 'B')
  |  |  ------------------
  |  |  |  |   50|    395|#define AI_IFF_FOURCC(a,b,c,d) ((uint32_t) (((uint8_t)a << 24u) | \
  |  |  |  |   51|    395|    ((uint8_t)b << 16u) | ((uint8_t)c << 8u) | ((uint8_t)d)))
  |  |  ------------------
  ------------------
   85|    395|        AI_LWO_FOURCC_LWO2,
  ------------------
  |  |   66|    395|#define AI_LWO_FOURCC_LWO2 AI_IFF_FOURCC('L', 'W', 'O', '2')
  |  |  ------------------
  |  |  |  |   50|    395|#define AI_IFF_FOURCC(a,b,c,d) ((uint32_t) (((uint8_t)a << 24u) | \
  |  |  |  |   51|    395|    ((uint8_t)b << 16u) | ((uint8_t)c << 8u) | ((uint8_t)d)))
  |  |  ------------------
  ------------------
   86|    395|        AI_LWO_FOURCC_LXOB
  ------------------
  |  |   68|    395|#define AI_LWO_FOURCC_LXOB AI_IFF_FOURCC('L', 'X', 'O', 'B')
  |  |  ------------------
  |  |  |  |   50|    395|#define AI_IFF_FOURCC(a,b,c,d) ((uint32_t) (((uint8_t)a << 24u) | \
  |  |  |  |   51|    395|    ((uint8_t)b << 16u) | ((uint8_t)c << 8u) | ((uint8_t)d)))
  |  |  ------------------
  ------------------
   87|    395|    };
   88|       |    return CheckMagicToken(pIOHandler, file, tokens, AI_COUNT_OF(tokens), 8);
   89|    395|}
_ZN6Assimp11LWOImporter15SetupPropertiesEPKNS_8ImporterE:
   93|     15|void LWOImporter::SetupProperties(const Importer *pImp) {
   94|     15|    configSpeedFlag = (0 != pImp->GetPropertyInteger(AI_CONFIG_FAVOUR_SPEED, 0) ? true : false);
  ------------------
  |  Branch (94:24): [True: 0, False: 15]
  ------------------
   95|     15|    configLayerIndex = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_LWO_ONE_LAYER_ONLY, UINT_MAX);
   96|       |    configLayerName = pImp->GetPropertyString(AI_CONFIG_IMPORT_LWO_ONE_LAYER_ONLY, "");
   97|     15|}
_ZNK6Assimp11LWOImporter7GetInfoEv:
  101|    649|const aiImporterDesc *LWOImporter::GetInfo() const {
  102|    649|    return &desc;
  103|    649|}
_ZN6Assimp11LWOImporter14InternReadFileERKNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEP7aiScenePNS_8IOSystemE:
  109|     15|        IOSystem *pIOHandler) {
  110|     15|    std::unique_ptr<IOStream> file(pIOHandler->Open(pFile, "rb"));
  111|       |
  112|       |    // Check whether we can read from the file
  113|     15|    if (file == nullptr) {
  ------------------
  |  Branch (113:9): [True: 0, False: 15]
  ------------------
  114|      0|        throw DeadlyImportError("Failed to open LWO file ", pFile, ".");
  115|      0|    }
  116|       |
  117|     15|    if ((this->fileSize = (unsigned int)file->FileSize()) < 12) {
  ------------------
  |  Branch (117:9): [True: 0, False: 15]
  ------------------
  118|      0|        throw DeadlyImportError("LWO: The file is too small to contain the IFF header");
  119|      0|    }
  120|       |
  121|       |    // Allocate storage and copy the contents of the file to a memory buffer
  122|     15|    std::vector<uint8_t> mBuffer(fileSize);
  123|     15|    file->Read(&mBuffer[0], 1, fileSize);
  124|     15|    mScene = pScene;
  125|       |
  126|       |    // Determine the type of the file
  127|     15|    uint32_t fileType;
  128|     15|    const char *sz = IFF::ReadHeader(&mBuffer[0], fileType);
  129|     15|    if (sz) {
  ------------------
  |  Branch (129:9): [True: 0, False: 15]
  ------------------
  130|      0|        throw DeadlyImportError(sz);
  131|      0|    }
  132|       |
  133|     15|    mFileBuffer = &mBuffer[0] + 12;
  134|     15|    mFileBufferEnd = &mBuffer[0] + fileSize;
  135|     15|    fileSize -= 12;
  136|       |
  137|       |    // Initialize some members with their default values
  138|     15|    hasNamedLayer = false;
  139|       |
  140|       |    // Create temporary storage on the stack but store pointers to it in the class
  141|       |    // instance. Therefore everything will be destructed properly if an exception
  142|       |    // is thrown and we needn't take care of that.
  143|     15|    LayerList _mLayers;
  144|     15|    SurfaceList _mSurfaces;
  145|     15|    TagList _mTags;
  146|     15|    TagMappingTable _mMapping;
  147|       |
  148|     15|    mLayers = &_mLayers;
  149|     15|    mTags = &_mTags;
  150|     15|    mMapping = &_mMapping;
  151|     15|    mSurfaces = &_mSurfaces;
  152|       |
  153|       |    // Allocate a default layer (layer indices are 1-based from now)
  154|     15|    mLayers->push_back(Layer());
  155|     15|    mCurLayer = &mLayers->back();
  156|     15|    mCurLayer->mName = "<LWODefault>";
  157|     15|    mCurLayer->mIndex = 1;
  158|       |
  159|       |    // old lightwave file format (prior to v6)
  160|     15|    mIsLWO2 = false;
  161|     15|    mIsLWO3 = false;
  162|     15|    mIsLXOB = false;
  163|       |
  164|     15|    if (AI_LWO_FOURCC_LWOB == fileType) {
  ------------------
  |  |   65|     15|#define AI_LWO_FOURCC_LWOB AI_IFF_FOURCC('L', 'W', 'O', 'B')
  |  |  ------------------
  |  |  |  |   50|     15|#define AI_IFF_FOURCC(a,b,c,d) ((uint32_t) (((uint8_t)a << 24u) | \
  |  |  |  |   51|     15|    ((uint8_t)b << 16u) | ((uint8_t)c << 8u) | ((uint8_t)d)))
  |  |  ------------------
  ------------------
  |  Branch (164:9): [True: 0, False: 15]
  ------------------
  165|      0|        ASSIMP_LOG_INFO("LWO file format: LWOB (<= LightWave 5.5)");
  166|       |
  167|      0|        LoadLWOBFile();
  168|     15|    } else if (AI_LWO_FOURCC_LWO2 == fileType) {
  ------------------
  |  |   66|     15|#define AI_LWO_FOURCC_LWO2 AI_IFF_FOURCC('L', 'W', 'O', '2')
  |  |  ------------------
  |  |  |  |   50|     15|#define AI_IFF_FOURCC(a,b,c,d) ((uint32_t) (((uint8_t)a << 24u) | \
  |  |  |  |   51|     15|    ((uint8_t)b << 16u) | ((uint8_t)c << 8u) | ((uint8_t)d)))
  |  |  ------------------
  ------------------
  |  Branch (168:16): [True: 8, False: 7]
  ------------------
  169|       |        // New lightwave format
  170|      8|        ASSIMP_LOG_INFO("LWO file format: LWO2 (>= LightWave 6)");
  171|      8|    } else if ( AI_LWO_FOURCC_LWO3 == fileType ) {
  ------------------
  |  |   67|      7|#define AI_LWO_FOURCC_LWO3 AI_IFF_FOURCC('L', 'W', 'O', '3')
  |  |  ------------------
  |  |  |  |   50|      7|#define AI_IFF_FOURCC(a,b,c,d) ((uint32_t) (((uint8_t)a << 24u) | \
  |  |  |  |   51|      7|    ((uint8_t)b << 16u) | ((uint8_t)c << 8u) | ((uint8_t)d)))
  |  |  ------------------
  ------------------
  |  Branch (171:17): [True: 0, False: 7]
  ------------------
  172|      0|        ASSIMP_LOG_INFO("LWO file format: LWO3 (>= LightWave 2018)");
  173|      7|    } else if (AI_LWO_FOURCC_LXOB == fileType) {
  ------------------
  |  |   68|      7|#define AI_LWO_FOURCC_LXOB AI_IFF_FOURCC('L', 'X', 'O', 'B')
  |  |  ------------------
  |  |  |  |   50|      7|#define AI_IFF_FOURCC(a,b,c,d) ((uint32_t) (((uint8_t)a << 24u) | \
  |  |  |  |   51|      7|    ((uint8_t)b << 16u) | ((uint8_t)c << 8u) | ((uint8_t)d)))
  |  |  ------------------
  ------------------
  |  Branch (173:16): [True: 7, False: 0]
  ------------------
  174|       |        // MODO file format
  175|      7|        mIsLXOB = true;
  176|      7|        ASSIMP_LOG_INFO("LWO file format: LXOB (Modo)");
  177|      7|    }
  178|      0|    else {
  179|      0|        char szBuff[5];
  180|      0|        szBuff[0] = (char)(fileType >> 24u);
  181|      0|        szBuff[1] = (char)(fileType >> 16u);
  182|      0|        szBuff[2] = (char)(fileType >> 8u);
  183|      0|        szBuff[3] = (char)(fileType);
  184|      0|        szBuff[4] = '\0';
  185|      0|        throw DeadlyImportError("Unknown LWO sub format: ", szBuff);
  186|      0|    }
  187|       |
  188|     15|    if (AI_LWO_FOURCC_LWOB != fileType) {   //
  ------------------
  |  |   65|     15|#define AI_LWO_FOURCC_LWOB AI_IFF_FOURCC('L', 'W', 'O', 'B')
  |  |  ------------------
  |  |  |  |   50|     15|#define AI_IFF_FOURCC(a,b,c,d) ((uint32_t) (((uint8_t)a << 24u) | \
  |  |  |  |   51|     15|    ((uint8_t)b << 16u) | ((uint8_t)c << 8u) | ((uint8_t)d)))
  |  |  ------------------
  ------------------
  |  Branch (188:9): [True: 15, False: 0]
  ------------------
  189|     15|        if( AI_LWO_FOURCC_LWO3 == fileType ) {
  ------------------
  |  |   67|     15|#define AI_LWO_FOURCC_LWO3 AI_IFF_FOURCC('L', 'W', 'O', '3')
  |  |  ------------------
  |  |  |  |   50|     15|#define AI_IFF_FOURCC(a,b,c,d) ((uint32_t) (((uint8_t)a << 24u) | \
  |  |  |  |   51|     15|    ((uint8_t)b << 16u) | ((uint8_t)c << 8u) | ((uint8_t)d)))
  |  |  ------------------
  ------------------
  |  Branch (189:13): [True: 0, False: 15]
  ------------------
  190|      0|            mIsLWO3 = true;
  191|     15|        } else {
  192|     15|            mIsLWO2 = true;
  193|     15|        }
  194|       |
  195|     15|        LoadLWO2File();
  196|       |
  197|       |        // The newer lightwave format allows the user to configure the
  198|       |        // loader that just one layer is used. If this is the case
  199|       |        // we need to check now whether the requested layer has been found.
  200|     15|        if (UINT_MAX != configLayerIndex) {
  ------------------
  |  Branch (200:13): [True: 0, False: 15]
  ------------------
  201|      0|            unsigned int layerCount = 0;
  202|      0|            for (std::list<LWO::Layer>::iterator itLayers = mLayers->begin(); itLayers != mLayers->end(); ++itLayers)
  ------------------
  |  Branch (202:79): [True: 0, False: 0]
  ------------------
  203|      0|                if (!itLayers->skip)
  ------------------
  |  Branch (203:21): [True: 0, False: 0]
  ------------------
  204|      0|                    layerCount++;
  205|      0|            if (layerCount != 2)
  ------------------
  |  Branch (205:17): [True: 0, False: 0]
  ------------------
  206|      0|                throw DeadlyImportError("LWO2: The requested layer was not found");
  207|      0|        }
  208|       |
  209|     15|        if (configLayerName.length() && !hasNamedLayer) {
  ------------------
  |  Branch (209:13): [True: 0, False: 15]
  |  Branch (209:41): [True: 0, False: 0]
  ------------------
  210|      0|            throw DeadlyImportError("LWO2: Unable to find the requested layer: ", configLayerName);
  211|      0|        }
  212|     15|    }
  213|       |
  214|       |    // now, as we have loaded all data, we can resolve cross-referenced tags and clips
  215|     15|    ResolveTags();
  216|     15|    ResolveClips();
  217|       |
  218|       |    // now process all layers and build meshes and nodes
  219|     15|    std::vector<aiMesh *> apcMeshes;
  220|     15|    std::map<uint16_t, aiNode *> apcNodes;
  221|       |
  222|     15|    apcMeshes.reserve(mLayers->size() * std::min(((unsigned int)mSurfaces->size() / 2u), 1u));
  223|       |
  224|     15|    unsigned int iDefaultSurface = UINT_MAX; // index of the default surface
  225|     25|    for (LWO::Layer &layer : *mLayers) {
  ------------------
  |  Branch (225:28): [True: 25, False: 15]
  ------------------
  226|     25|        if (layer.skip)
  ------------------
  |  Branch (226:13): [True: 0, False: 25]
  ------------------
  227|      0|            continue;
  228|       |
  229|       |        // I don't know whether there could be dummy layers, but it would be possible
  230|     25|        const unsigned int meshStart = (unsigned int)apcMeshes.size();
  231|     25|        if (!layer.mFaces.empty() && !layer.mTempPoints.empty()) {
  ------------------
  |  Branch (231:13): [True: 17, False: 8]
  |  Branch (231:38): [True: 17, False: 0]
  ------------------
  232|       |
  233|       |            // now sort all faces by the surfaces assigned to them
  234|     17|            std::vector<SortedRep> pSorted(mSurfaces->size() + 1);
  235|       |
  236|     17|            unsigned int i = 0;
  237|  3.24k|            for (FaceList::iterator it = layer.mFaces.begin(), end = layer.mFaces.end(); it != end; ++it, ++i) {
  ------------------
  |  Branch (237:90): [True: 3.22k, False: 17]
  ------------------
  238|       |                // Check whether we support this face's type
  239|  3.22k|                if ((*it).type != AI_LWO_FACE && (*it).type != AI_LWO_PTCH &&
  ------------------
  |  |  117|  3.22k|#define AI_LWO_FACE AI_IFF_FOURCC('F', 'A', 'C', 'E')
  |  |  ------------------
  |  |  |  |   50|  6.45k|#define AI_IFF_FOURCC(a,b,c,d) ((uint32_t) (((uint8_t)a << 24u) | \
  |  |  |  |   51|  6.45k|    ((uint8_t)b << 16u) | ((uint8_t)c << 8u) | ((uint8_t)d)))
  |  |  ------------------
  ------------------
                              if ((*it).type != AI_LWO_FACE && (*it).type != AI_LWO_PTCH &&
  ------------------
  |  |  119|      0|#define AI_LWO_PTCH AI_IFF_FOURCC('P', 'T', 'C', 'H')
  |  |  ------------------
  |  |  |  |   50|  3.22k|#define AI_IFF_FOURCC(a,b,c,d) ((uint32_t) (((uint8_t)a << 24u) | \
  |  |  |  |   51|  3.22k|    ((uint8_t)b << 16u) | ((uint8_t)c << 8u) | ((uint8_t)d)))
  |  |  ------------------
  ------------------
  |  Branch (239:21): [True: 0, False: 3.22k]
  |  Branch (239:50): [True: 0, False: 0]
  ------------------
  240|  3.22k|                        (*it).type != AI_LWO_BONE && (*it).type != AI_LWO_SUBD) {
  ------------------
  |  |  121|      0|#define AI_LWO_BONE AI_IFF_FOURCC('B', 'O', 'N', 'E')
  |  |  ------------------
  |  |  |  |   50|  3.22k|#define AI_IFF_FOURCC(a,b,c,d) ((uint32_t) (((uint8_t)a << 24u) | \
  |  |  |  |   51|  3.22k|    ((uint8_t)b << 16u) | ((uint8_t)c << 8u) | ((uint8_t)d)))
  |  |  ------------------
  ------------------
                                      (*it).type != AI_LWO_BONE && (*it).type != AI_LWO_SUBD) {
  ------------------
  |  |  122|      0|#define AI_LWO_SUBD AI_IFF_FOURCC('S', 'U', 'B', 'D')
  |  |  ------------------
  |  |  |  |   50|      0|#define AI_IFF_FOURCC(a,b,c,d) ((uint32_t) (((uint8_t)a << 24u) | \
  |  |  |  |   51|      0|    ((uint8_t)b << 16u) | ((uint8_t)c << 8u) | ((uint8_t)d)))
  |  |  ------------------
  ------------------
  |  Branch (240:25): [True: 0, False: 0]
  |  Branch (240:54): [True: 0, False: 0]
  ------------------
  241|      0|                    continue;
  242|      0|                }
  243|       |
  244|  3.22k|                unsigned int idx = (*it).surfaceIndex;
  245|  3.22k|                if (idx >= mTags->size()) {
  ------------------
  |  Branch (245:21): [True: 0, False: 3.22k]
  ------------------
  246|      0|                    ASSIMP_LOG_WARN("LWO: Invalid face surface index");
  247|      0|                    idx = UINT_MAX;
  248|      0|                }
  249|  3.22k|                if (UINT_MAX == idx || UINT_MAX == (idx = _mMapping[idx])) {
  ------------------
  |  Branch (249:21): [True: 0, False: 3.22k]
  |  Branch (249:40): [True: 1.54k, False: 1.68k]
  ------------------
  250|  1.54k|                    if (UINT_MAX == iDefaultSurface) {
  ------------------
  |  Branch (250:25): [True: 3, False: 1.53k]
  ------------------
  251|      3|                        iDefaultSurface = (unsigned int)mSurfaces->size();
  252|      3|                        mSurfaces->push_back(LWO::Surface());
  253|      3|                        LWO::Surface &surf = mSurfaces->back();
  254|      3|                        surf.mColor.r = surf.mColor.g = surf.mColor.b = 0.6f;
  255|      3|                        surf.mName = "LWODefaultSurface";
  256|      3|                    }
  257|  1.54k|                    idx = iDefaultSurface;
  258|  1.54k|                }
  259|  3.22k|                pSorted[idx].push_back(i);
  260|  3.22k|            }
  261|     17|            if (UINT_MAX == iDefaultSurface) {
  ------------------
  |  Branch (261:17): [True: 12, False: 5]
  ------------------
  262|     12|                pSorted.erase(pSorted.end() - 1);
  263|     12|            }
  264|     61|            for (unsigned int j = 0; j < mSurfaces->size(); ++j) {
  ------------------
  |  Branch (264:38): [True: 44, False: 17]
  ------------------
  265|     44|                SortedRep &sorted = pSorted[j];
  266|     44|                if (sorted.empty())
  ------------------
  |  Branch (266:21): [True: 26, False: 18]
  ------------------
  267|     26|                    continue;
  268|       |
  269|       |                // generate the mesh
  270|     18|                aiMesh *mesh = new aiMesh();
  271|     18|                apcMeshes.push_back(mesh);
  272|     18|                mesh->mNumFaces = (unsigned int)sorted.size();
  273|       |
  274|       |                // count the number of vertices
  275|     18|                SortedRep::const_iterator it = sorted.begin(), end = sorted.end();
  276|  3.24k|                for (; it != end; ++it) {
  ------------------
  |  Branch (276:24): [True: 3.22k, False: 18]
  ------------------
  277|  3.22k|                    mesh->mNumVertices += layer.mFaces[*it].mNumIndices;
  278|  3.22k|                }
  279|       |
  280|     18|                aiVector3D *nrm = nullptr, *pv = mesh->mVertices = new aiVector3D[mesh->mNumVertices];
  281|     18|                aiFace *pf = mesh->mFaces = new aiFace[mesh->mNumFaces];
  282|     18|                mesh->mMaterialIndex = j;
  283|       |
  284|       |                // find out which vertex color channels and which texture coordinate
  285|       |                // channels are really required by the material attached to this mesh
  286|     18|                unsigned int vUVChannelIndices[AI_MAX_NUMBER_OF_TEXTURECOORDS];
  287|     18|                unsigned int vVColorIndices[AI_MAX_NUMBER_OF_COLOR_SETS];
  288|       |
  289|     18|#ifdef ASSIMP_BUILD_DEBUG
  290|    162|                for (unsigned int mui = 0; mui < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++mui) {
  ------------------
  |  Branch (290:44): [True: 144, False: 18]
  ------------------
  291|    144|                    vUVChannelIndices[mui] = UINT_MAX;
  292|    144|                }
  293|    162|                for (unsigned int mui = 0; mui < AI_MAX_NUMBER_OF_COLOR_SETS; ++mui) {
  ------------------
  |  Branch (293:44): [True: 144, False: 18]
  ------------------
  294|    144|                    vVColorIndices[mui] = UINT_MAX;
  295|    144|                }
  296|     18|#endif
  297|       |
  298|     18|                FindUVChannels(_mSurfaces[j], sorted, layer, vUVChannelIndices);
  299|     18|                FindVCChannels(_mSurfaces[j], sorted, layer, vVColorIndices);
  300|       |
  301|       |                // allocate storage for UV and CV channels
  302|     18|                aiVector3D *pvUV[AI_MAX_NUMBER_OF_TEXTURECOORDS];
  303|     22|                for (unsigned int mui = 0; mui < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++mui) {
  ------------------
  |  Branch (303:44): [True: 22, False: 0]
  ------------------
  304|     22|                    if (UINT_MAX == vUVChannelIndices[mui]) {
  ------------------
  |  Branch (304:25): [True: 18, False: 4]
  ------------------
  305|     18|                        break;
  306|     18|                    }
  307|       |
  308|      4|                    pvUV[mui] = mesh->mTextureCoords[mui] = new aiVector3D[mesh->mNumVertices];
  309|       |
  310|       |                    // LightWave doesn't support more than 2 UV components (?)
  311|      4|                    mesh->mNumUVComponents[0] = 2;
  312|      4|                }
  313|       |
  314|     18|                if (layer.mNormals.name.length()) {
  ------------------
  |  Branch (314:21): [True: 2, False: 16]
  ------------------
  315|      2|                    nrm = mesh->mNormals = new aiVector3D[mesh->mNumVertices];
  316|      2|                }
  317|       |
  318|     18|                aiColor4D *pvVC[AI_MAX_NUMBER_OF_COLOR_SETS];
  319|     20|                for (unsigned int mui = 0; mui < AI_MAX_NUMBER_OF_COLOR_SETS; ++mui) {
  ------------------
  |  Branch (319:44): [True: 20, False: 0]
  ------------------
  320|     20|                    if (UINT_MAX == vVColorIndices[mui]) {
  ------------------
  |  Branch (320:25): [True: 18, False: 2]
  ------------------
  321|     18|                        break;
  322|     18|                    }
  323|      2|                    pvVC[mui] = mesh->mColors[mui] = new aiColor4D[mesh->mNumVertices];
  324|      2|                }
  325|       |
  326|       |                // we would not need this extra array, but the code is much cleaner if we use it
  327|     18|                std::vector<unsigned int> &smoothingGroups = layer.mPointReferrers;
  328|     18|                smoothingGroups.erase(smoothingGroups.begin(), smoothingGroups.end());
  329|     18|                smoothingGroups.resize(mesh->mNumFaces, 0);
  330|       |
  331|       |                // now convert all faces
  332|     18|                unsigned int vert = 0;
  333|     18|                std::vector<unsigned int>::iterator outIt = smoothingGroups.begin();
  334|  3.24k|                for (it = sorted.begin(); it != end; ++it, ++outIt) {
  ------------------
  |  Branch (334:43): [True: 3.22k, False: 18]
  ------------------
  335|  3.22k|                    const LWO::Face &face = layer.mFaces[*it];
  336|  3.22k|                    *outIt = face.smoothGroup;
  337|       |
  338|       |                    // copy all vertices
  339|  15.8k|                    for (unsigned int q = 0; q < face.mNumIndices; ++q, ++vert) {
  ------------------
  |  Branch (339:46): [True: 12.6k, False: 3.22k]
  ------------------
  340|  12.6k|                        unsigned int idx = face.mIndices[q];
  341|  12.6k|                        *pv++ = layer.mTempPoints[idx] /*- layer.mPivot*/;
  342|       |
  343|       |                        // process UV coordinates
  344|  20.3k|                        for (unsigned int w = 0; w < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++w) {
  ------------------
  |  Branch (344:50): [True: 20.3k, False: 0]
  ------------------
  345|  20.3k|                            if (UINT_MAX == vUVChannelIndices[w]) {
  ------------------
  |  Branch (345:33): [True: 12.6k, False: 7.71k]
  ------------------
  346|  12.6k|                                break;
  347|  12.6k|                            }
  348|  7.71k|                            aiVector3D *&pp = pvUV[w];
  349|  7.71k|                            const aiVector2D &src = ((aiVector2D *)&layer.mUVChannels[vUVChannelIndices[w]].rawData[0])[idx];
  350|  7.71k|                            pp->x = src.x;
  351|  7.71k|                            pp->y = src.y;
  352|  7.71k|                            pp++;
  353|  7.71k|                        }
  354|       |
  355|       |                        // process normals (MODO extension)
  356|  12.6k|                        if (nrm) {
  ------------------
  |  Branch (356:29): [True: 2.20k, False: 10.4k]
  ------------------
  357|  2.20k|                            *nrm = ((aiVector3D *)&layer.mNormals.rawData[0])[idx];
  358|  2.20k|                            nrm->z *= -1.f;
  359|  2.20k|                            ++nrm;
  360|  2.20k|                        }
  361|       |
  362|       |                        // process vertex colors
  363|  14.2k|                        for (unsigned int w = 0; w < AI_MAX_NUMBER_OF_COLOR_SETS; ++w) {
  ------------------
  |  Branch (363:50): [True: 14.2k, False: 0]
  ------------------
  364|  14.2k|                            if (UINT_MAX == vVColorIndices[w]) {
  ------------------
  |  Branch (364:33): [True: 12.6k, False: 1.64k]
  ------------------
  365|  12.6k|                                break;
  366|  12.6k|                            }
  367|  1.64k|                            *pvVC[w] = ((aiColor4D *)&layer.mVColorChannels[vVColorIndices[w]].rawData[0])[idx];
  368|       |
  369|       |                            // If a RGB color map is explicitly requested delete the
  370|       |                            // alpha channel - it could theoretically be != 1.
  371|  1.64k|                            if (_mSurfaces[j].mVCMapType == AI_LWO_RGB)
  ------------------
  |  |  243|  1.64k|#define AI_LWO_RGB AI_IFF_FOURCC('R', 'G', 'B', ' ')
  |  |  ------------------
  |  |  |  |   50|  1.64k|#define AI_IFF_FOURCC(a,b,c,d) ((uint32_t) (((uint8_t)a << 24u) | \
  |  |  |  |   51|  1.64k|    ((uint8_t)b << 16u) | ((uint8_t)c << 8u) | ((uint8_t)d)))
  |  |  ------------------
  ------------------
  |  Branch (371:33): [True: 1.64k, False: 0]
  ------------------
  372|  1.64k|                                pvVC[w]->a = 1.f;
  373|       |
  374|  1.64k|                            pvVC[w]++;
  375|  1.64k|                        }
  376|       |
  377|  12.6k|                        face.mIndices[q] = vert;
  378|  12.6k|                    }
  379|  3.22k|                    pf->mIndices = face.mIndices;
  380|  3.22k|                    pf->mNumIndices = face.mNumIndices;
  381|  3.22k|                    unsigned int **facePtr = (unsigned int **)&face.mIndices;
  382|  3.22k|                    *facePtr = nullptr; // HACK: make sure it won't be deleted
  383|  3.22k|                    pf++;
  384|  3.22k|                }
  385|       |
  386|     18|                if (!mesh->mNormals) {
  ------------------
  |  Branch (386:21): [True: 16, False: 2]
  ------------------
  387|       |                    // Compute normal vectors for the mesh - we can't use our GenSmoothNormal-
  388|       |                    // Step here since it wouldn't handle smoothing groups correctly for LWO.
  389|       |                    // So we use a separate implementation.
  390|     16|                    ComputeNormals(mesh, smoothingGroups, _mSurfaces[j]);
  391|     16|                } else {
  392|      2|                    ASSIMP_LOG_VERBOSE_DEBUG("LWO2: No need to compute normals, they're already there");
  393|      2|                }
  394|     18|            }
  395|     17|        }
  396|       |
  397|       |        // Generate nodes to render the mesh. Store the source layer in the mParent member of the nodes
  398|     25|        unsigned int num = static_cast<unsigned int>(apcMeshes.size() - meshStart);
  399|     25|        if (layer.mName != "<LWODefault>" || num > 0) {
  ------------------
  |  Branch (399:13): [True: 17, False: 8]
  |  Branch (399:46): [True: 0, False: 8]
  ------------------
  400|     17|            std::unique_ptr<aiNode> pcNode(new aiNode());
  401|     17|            pcNode->mName.Set(layer.mName);
  402|     17|            pcNode->mParent = (aiNode *)&layer;
  403|     17|            pcNode->mNumMeshes = num;
  404|       |
  405|     17|            if (pcNode->mNumMeshes) {
  ------------------
  |  Branch (405:17): [True: 17, False: 0]
  ------------------
  406|     17|                pcNode->mMeshes = new unsigned int[pcNode->mNumMeshes];
  407|     35|                for (unsigned int p = 0; p < pcNode->mNumMeshes; ++p)
  ------------------
  |  Branch (407:42): [True: 18, False: 17]
  ------------------
  408|     18|                    pcNode->mMeshes[p] = p + meshStart;
  409|     17|            }
  410|     17|            ASSIMP_LOG_DEBUG("insert apcNode for layer ", layer.mIndex, " \"", layer.mName, "\"");
  411|     17|            apcNodes[layer.mIndex] = pcNode.release();
  412|     17|        }
  413|     25|    }
  414|       |
  415|     15|    if (apcNodes.empty() || apcMeshes.empty())
  ------------------
  |  Branch (415:9): [True: 7, False: 8]
  |  Branch (415:29): [True: 0, False: 8]
  ------------------
  416|      0|        throw DeadlyImportError("LWO: No meshes loaded");
  417|       |
  418|       |    // The RemoveRedundantMaterials step will clean this up later
  419|     15|    pScene->mMaterials = new aiMaterial *[pScene->mNumMaterials = (unsigned int)mSurfaces->size()];
  420|       |
  421|     30|    for (unsigned int mat = 0; mat < pScene->mNumMaterials; ++mat) {
  ------------------
  |  Branch (421:32): [True: 15, False: 15]
  ------------------
  422|     15|        aiMaterial *pcMat = new aiMaterial();
  423|     15|        pScene->mMaterials[mat] = pcMat;
  424|     15|        ConvertMaterial((*mSurfaces)[mat], pcMat);
  425|     15|    }
  426|       |
  427|       |    // copy the meshes to the output structure
  428|     15|    pScene->mMeshes = new aiMesh *[pScene->mNumMeshes = (unsigned int)apcMeshes.size()];
  429|     15|    ::memcpy(pScene->mMeshes, &apcMeshes[0], pScene->mNumMeshes * sizeof(void *));
  430|       |
  431|       |    // generate the final node graph
  432|     15|    GenerateNodeGraph(apcNodes);
  433|     15|}
_ZN6Assimp11LWOImporter14ComputeNormalsEP6aiMeshRKNSt3__16vectorIjNS3_9allocatorIjEEEERKNS_3LWO7SurfaceE:
  437|     16|        const LWO::Surface &surface) {
  438|       |    // Allocate output storage
  439|     16|    mesh->mNormals = new aiVector3D[mesh->mNumVertices];
  440|       |
  441|       |    // First generate per-face normals
  442|     16|    aiVector3D *out;
  443|     16|    std::vector<aiVector3D> faceNormals;
  444|       |
  445|       |    // ... in some cases that's already enough
  446|     16|    if (!surface.mMaximumSmoothAngle)
  ------------------
  |  Branch (446:9): [True: 6, False: 10]
  ------------------
  447|      6|        out = mesh->mNormals;
  448|     10|    else {
  449|     10|        faceNormals.resize(mesh->mNumVertices);
  450|     10|        out = &faceNormals[0];
  451|     10|    }
  452|       |
  453|     16|    aiFace *begin = mesh->mFaces, *const end = mesh->mFaces + mesh->mNumFaces;
  454|  2.66k|    for (; begin != end; ++begin) {
  ------------------
  |  Branch (454:12): [True: 2.65k, False: 16]
  ------------------
  455|  2.65k|        aiFace &face = *begin;
  456|       |
  457|  2.65k|        if (face.mNumIndices < 3) {
  ------------------
  |  Branch (457:13): [True: 0, False: 2.65k]
  ------------------
  458|      0|            continue;
  459|      0|        }
  460|       |
  461|       |        // LWO doc: "the normal is defined as the cross product of the first and last edges"
  462|  2.65k|        aiVector3D *pV1 = mesh->mVertices + face.mIndices[0];
  463|  2.65k|        aiVector3D *pV2 = mesh->mVertices + face.mIndices[1];
  464|  2.65k|        aiVector3D *pV3 = mesh->mVertices + face.mIndices[face.mNumIndices - 1];
  465|       |
  466|  2.65k|        aiVector3D vNor = ((*pV2 - *pV1) ^ (*pV3 - *pV1)).Normalize();
  467|  13.0k|        for (unsigned int i = 0; i < face.mNumIndices; ++i)
  ------------------
  |  Branch (467:34): [True: 10.4k, False: 2.65k]
  ------------------
  468|  10.4k|            out[face.mIndices[i]] = vNor;
  469|  2.65k|    }
  470|     16|    if (!surface.mMaximumSmoothAngle) return;
  ------------------
  |  Branch (470:9): [True: 6, False: 10]
  ------------------
  471|     10|    const float posEpsilon = ComputePositionEpsilon(mesh);
  472|       |
  473|       |    // Now generate the spatial sort tree
  474|     10|    SGSpatialSort sSort;
  475|     10|    std::vector<unsigned int>::const_iterator it = smoothingGroups.begin();
  476|    633|    for (begin = mesh->mFaces; begin != end; ++begin, ++it) {
  ------------------
  |  Branch (476:32): [True: 623, False: 10]
  ------------------
  477|    623|        aiFace &face = *begin;
  478|  3.02k|        for (unsigned int i = 0; i < face.mNumIndices; ++i) {
  ------------------
  |  Branch (478:34): [True: 2.39k, False: 623]
  ------------------
  479|  2.39k|            unsigned int tt = face.mIndices[i];
  480|  2.39k|            sSort.Add(mesh->mVertices[tt], tt, *it);
  481|  2.39k|        }
  482|    623|    }
  483|       |    // Sort everything - this takes O(nlogn) time
  484|     10|    sSort.Prepare();
  485|     10|    std::vector<unsigned int> poResult;
  486|     10|    poResult.reserve(20);
  487|       |
  488|       |    // Generate vertex normals. We have O(logn) for the binary lookup, which we need
  489|       |    // for n elements, thus the EXPECTED complexity is O(nlogn)
  490|     10|    if (surface.mMaximumSmoothAngle < 3.f && !configSpeedFlag) {
  ------------------
  |  Branch (490:9): [True: 10, False: 0]
  |  Branch (490:46): [True: 10, False: 0]
  ------------------
  491|     10|        const float fLimit = std::cos(surface.mMaximumSmoothAngle);
  492|       |
  493|    633|        for (begin = mesh->mFaces, it = smoothingGroups.begin(); begin != end; ++begin, ++it) {
  ------------------
  |  Branch (493:66): [True: 623, False: 10]
  ------------------
  494|    623|            const aiFace &face = *begin;
  495|    623|            unsigned int *beginIdx = face.mIndices, *const endIdx = face.mIndices + face.mNumIndices;
  496|  3.02k|            for (; beginIdx != endIdx; ++beginIdx) {
  ------------------
  |  Branch (496:20): [True: 2.39k, False: 623]
  ------------------
  497|  2.39k|                unsigned int idx = *beginIdx;
  498|  2.39k|                sSort.FindPositions(mesh->mVertices[idx], *it, posEpsilon, poResult, true);
  499|       |
  500|  2.39k|                aiVector3D vNormals;
  501|  13.6k|                 for (std::vector<unsigned int>::const_iterator a = poResult.begin(); a != poResult.end(); ++a) {
  ------------------
  |  Branch (501:87): [True: 11.2k, False: 2.39k]
  ------------------
  502|  11.2k|                    const aiVector3D &v = faceNormals[*a];
  503|  11.2k|                    if (v * faceNormals[idx] < fLimit)
  ------------------
  |  Branch (503:25): [True: 96, False: 11.1k]
  ------------------
  504|     96|                        continue;
  505|  11.1k|                    vNormals += v;
  506|  11.1k|                }
  507|  2.39k|                mesh->mNormals[idx] = vNormals.Normalize();
  508|  2.39k|            }
  509|    623|        }
  510|     10|    }
  511|       |    // faster code path in case there is no smooth angle
  512|      0|    else {
  513|      0|        std::vector<bool> vertexDone(mesh->mNumVertices, false);
  514|      0|        for (begin = mesh->mFaces, it = smoothingGroups.begin(); begin != end; ++begin, ++it) {
  ------------------
  |  Branch (514:66): [True: 0, False: 0]
  ------------------
  515|      0|            const aiFace &face = *begin;
  516|      0|            unsigned int *beginIdx = face.mIndices, *const endIdx = face.mIndices + face.mNumIndices;
  517|      0|            for (; beginIdx != endIdx; ++beginIdx) {
  ------------------
  |  Branch (517:20): [True: 0, False: 0]
  ------------------
  518|      0|                unsigned int idx = *beginIdx;
  519|      0|                if (vertexDone[idx])
  ------------------
  |  Branch (519:21): [True: 0, False: 0]
  ------------------
  520|      0|                    continue;
  521|      0|                sSort.FindPositions(mesh->mVertices[idx], *it, posEpsilon, poResult, true);
  522|       |
  523|      0|                aiVector3D vNormals;
  524|      0|                 for (std::vector<unsigned int>::const_iterator a = poResult.begin(); a != poResult.end(); ++a) {
  ------------------
  |  Branch (524:87): [True: 0, False: 0]
  ------------------
  525|      0|                    const aiVector3D &v = faceNormals[*a];
  526|      0|                    vNormals += v;
  527|      0|                }
  528|      0|                vNormals.Normalize();
  529|      0|                for (std::vector<unsigned int>::const_iterator a = poResult.begin(); a != poResult.end(); ++a) {
  ------------------
  |  Branch (529:86): [True: 0, False: 0]
  ------------------
  530|      0|                    mesh->mNormals[*a] = vNormals;
  531|      0|                    vertexDone[*a] = true;
  532|      0|                }
  533|      0|            }
  534|      0|        }
  535|      0|    }
  536|     10|    GeometryUtils::normalizeVectorArray(mesh->mNormals, mesh->mNormals, mesh->mNumVertices);
  537|     10|}
_ZN6Assimp11LWOImporter17GenerateNodeGraphERNSt3__13mapItP6aiNodeNS1_4lessItEENS1_9allocatorINS1_4pairIKtS4_EEEEEE:
  540|      8|void LWOImporter::GenerateNodeGraph(std::map<uint16_t, aiNode *> &apcNodes) {
  541|       |    // now generate the final nodegraph - generate a root node and attach children
  542|      8|    aiNode *root = mScene->mRootNode = new aiNode();
  543|      8|    root->mName.Set("<LWORoot>");
  544|       |
  545|      8|    ASSIMP_LOG_DEBUG("apcNodes initial size: ", apcNodes.size());
  546|      8|    if (!apcNodes.empty()) {
  ------------------
  |  Branch (546:9): [True: 8, False: 0]
  ------------------
  547|      8|        ASSIMP_LOG_DEBUG("first apcNode is: ", apcNodes.begin()->first, " \"", apcNodes.begin()->second->mName.C_Str(), "\"");
  548|      8|    }
  549|       |
  550|       |    //Set parent of all children, inserting pivots
  551|      8|    {
  552|      8|        std::map<uint16_t, aiNode *> mapPivot;
  553|     25|        for (auto itapcNodes = apcNodes.begin(); itapcNodes != apcNodes.end(); ++itapcNodes) {
  ------------------
  |  Branch (553:50): [True: 17, False: 8]
  ------------------
  554|       |
  555|       |            //Get the parent index
  556|     17|            LWO::Layer *nodeLayer = (LWO::Layer *)(itapcNodes->second->mParent);
  557|     17|            uint16_t parentIndex = nodeLayer->mParent;
  558|       |
  559|       |            //Create pivot node, store it into the pivot map, and set the parent as the pivot
  560|     17|            std::unique_ptr<aiNode> pivotNode(new aiNode());
  561|     17|            pivotNode->mName.Set("Pivot-" + std::string(itapcNodes->second->mName.data));
  562|     17|            itapcNodes->second->mParent = pivotNode.get();
  563|       |
  564|       |            //Look for the parent node to attach the pivot to
  565|     17|            if (apcNodes.find(parentIndex) != apcNodes.end()) {
  ------------------
  |  Branch (565:17): [True: 9, False: 8]
  ------------------
  566|      9|                pivotNode->mParent = apcNodes[parentIndex];
  567|      9|            } else {
  568|       |                //If not, attach to the root node
  569|      8|                pivotNode->mParent = root;
  570|      8|            }
  571|       |
  572|       |            //Set the node and the pivot node transformation
  573|     17|            itapcNodes->second->mTransformation.a4 = -nodeLayer->mPivot.x;
  574|     17|            itapcNodes->second->mTransformation.b4 = -nodeLayer->mPivot.y;
  575|     17|            itapcNodes->second->mTransformation.c4 = -nodeLayer->mPivot.z;
  576|     17|            pivotNode->mTransformation.a4 = nodeLayer->mPivot.x;
  577|     17|            pivotNode->mTransformation.b4 = nodeLayer->mPivot.y;
  578|     17|            pivotNode->mTransformation.c4 = nodeLayer->mPivot.z;
  579|     17|            uint16_t pivotNodeId = static_cast<uint16_t>(-(itapcNodes->first + 2));
  580|     17|            ASSIMP_LOG_DEBUG("insert pivot node: ", pivotNodeId);
  581|     17|            auto oldNodeIt = mapPivot.find(pivotNodeId);
  582|     17|            if (oldNodeIt != mapPivot.end()) {
  ------------------
  |  Branch (582:17): [True: 0, False: 17]
  ------------------
  583|      0|                ASSIMP_LOG_ERROR("attempted to insert pivot node which already exists in pivot map ", pivotNodeId, " \"", pivotNode->mName.C_Str(), "\"");
  584|     17|            } else {
  585|     17|                mapPivot.emplace(pivotNodeId, pivotNode.release());
  586|     17|            }
  587|     17|        }
  588|       |
  589|      8|        ASSIMP_LOG_DEBUG("pivot nodes: ", mapPivot.size());
  590|       |        //Merge pivot map into node map
  591|     25|        for (auto itMapPivot = mapPivot.begin(); itMapPivot != mapPivot.end();) {
  ------------------
  |  Branch (591:50): [True: 17, False: 8]
  ------------------
  592|     17|            uint16_t pivotNodeId = itMapPivot->first;
  593|     17|            auto oldApcNodeIt = apcNodes.find(pivotNodeId);
  594|     17|            if (oldApcNodeIt != apcNodes.end()) {
  ------------------
  |  Branch (594:17): [True: 0, False: 17]
  ------------------
  595|      0|                ASSIMP_LOG_ERROR("attempted to insert pivot node which already exists in apc nodes ", pivotNodeId, " \"", itMapPivot->second->mName.C_Str(), "\"");
  596|     17|            } else {
  597|     17|                apcNodes.emplace(pivotNodeId, itMapPivot->second);
  598|     17|            }
  599|     17|            itMapPivot->second = nullptr;
  600|     17|            itMapPivot = mapPivot.erase(itMapPivot);
  601|     17|        }
  602|      8|        ASSIMP_LOG_DEBUG("total nodes: ", apcNodes.size());
  603|      8|    }
  604|       |
  605|       |    //Set children of all parents
  606|      8|    apcNodes[(uint16_t)-1] = root;
  607|     50|    for (auto itMapParentNodes = apcNodes.begin(); itMapParentNodes != apcNodes.end(); ++itMapParentNodes) {
  ------------------
  |  Branch (607:52): [True: 42, False: 8]
  ------------------
  608|    330|        for (auto itMapChildNodes = apcNodes.begin(); itMapChildNodes != apcNodes.end(); ++itMapChildNodes) {
  ------------------
  |  Branch (608:55): [True: 288, False: 42]
  ------------------
  609|    288|            if ((itMapParentNodes->first != itMapChildNodes->first) && (itMapParentNodes->second == itMapChildNodes->second->mParent)) {
  ------------------
  |  Branch (609:17): [True: 246, False: 42]
  |  Branch (609:72): [True: 34, False: 212]
  ------------------
  610|     34|                ++(itMapParentNodes->second->mNumChildren);
  611|     34|            }
  612|    288|        }
  613|     42|        if (itMapParentNodes->second->mNumChildren) {
  ------------------
  |  Branch (613:13): [True: 31, False: 11]
  ------------------
  614|     31|            itMapParentNodes->second->mChildren = new aiNode *[itMapParentNodes->second->mNumChildren];
  615|     31|            uint16_t p = 0;
  616|    250|            for (auto itMapChildNodes = apcNodes.begin(); itMapChildNodes != apcNodes.end(); ++itMapChildNodes) {
  ------------------
  |  Branch (616:59): [True: 219, False: 31]
  ------------------
  617|    219|                if ((itMapParentNodes->first != itMapChildNodes->first) && (itMapParentNodes->second == itMapChildNodes->second->mParent)) {
  ------------------
  |  Branch (617:21): [True: 188, False: 31]
  |  Branch (617:76): [True: 34, False: 154]
  ------------------
  618|     34|                    itMapParentNodes->second->mChildren[p++] = itMapChildNodes->second;
  619|     34|                }
  620|    219|            }
  621|     31|        }
  622|     42|    }
  623|       |
  624|      8|    if (!mScene->mRootNode->mNumChildren) {
  ------------------
  |  Branch (624:9): [True: 0, False: 8]
  ------------------
  625|      0|        ASSIMP_LOG_DEBUG("All apcNodes:");
  626|      0|        for (auto nodeIt = apcNodes.begin(); nodeIt != apcNodes.end(); ) {
  ------------------
  |  Branch (626:46): [True: 0, False: 0]
  ------------------
  627|      0|            ASSIMP_LOG_DEBUG("Node ", nodeIt->first, " \"", nodeIt->second->mName.C_Str(), "\"");
  628|      0|            nodeIt->second = nullptr;
  629|      0|            nodeIt = apcNodes.erase(nodeIt);
  630|      0|        }
  631|      0|        throw DeadlyImportError("LWO: Unable to build a valid node graph");
  632|      0|    }
  633|       |
  634|       |    // Remove a single root node with no meshes assigned to it ...
  635|      8|    if (1 == mScene->mRootNode->mNumChildren) {
  ------------------
  |  Branch (635:9): [True: 8, False: 0]
  ------------------
  636|      8|        aiNode *pc = mScene->mRootNode->mChildren[0];
  637|      8|        pc->mParent = mScene->mRootNode->mChildren[0] = nullptr;
  638|      8|        delete mScene->mRootNode;
  639|      8|        mScene->mRootNode = pc;
  640|      8|    }
  641|       |
  642|       |    // convert the whole stuff to RH with CCW winding
  643|      8|    MakeLeftHandedProcess maker;
  644|      8|    maker.Execute(mScene);
  645|       |
  646|      8|    FlipWindingOrderProcess flipper;
  647|      8|    flipper.Execute(mScene);
  648|      8|}
_ZN6Assimp11LWOImporter11ResolveTagsEv:
  651|      8|void LWOImporter::ResolveTags() {
  652|       |    // --- this function is used for both LWO2 and LWOB
  653|      8|    mMapping->resize(mTags->size(), UINT_MAX);
  654|     28|    for (unsigned int a = 0; a < mTags->size(); ++a) {
  ------------------
  |  Branch (654:30): [True: 20, False: 8]
  ------------------
  655|       |
  656|     20|        const std::string &c = (*mTags)[a];
  657|     40|        for (unsigned int i = 0; i < mSurfaces->size(); ++i) {
  ------------------
  |  Branch (657:34): [True: 32, False: 8]
  ------------------
  658|       |
  659|     32|            const std::string &d = (*mSurfaces)[i].mName;
  660|     32|            if (!ASSIMP_stricmp(c, d)) {
  ------------------
  |  Branch (660:17): [True: 12, False: 20]
  ------------------
  661|       |
  662|     12|                (*mMapping)[a] = i;
  663|     12|                break;
  664|     12|            }
  665|     32|        }
  666|     20|    }
  667|      8|}
_ZN6Assimp11LWOImporter12ResolveClipsEv:
  670|      8|void LWOImporter::ResolveClips() {
  671|     10|    for (unsigned int i = 0; i < mClips.size(); ++i) {
  ------------------
  |  Branch (671:30): [True: 2, False: 8]
  ------------------
  672|       |
  673|      2|        Clip &clip = mClips[i];
  674|      2|        if (Clip::REF == clip.type) {
  ------------------
  |  Branch (674:13): [True: 0, False: 2]
  ------------------
  675|       |
  676|      0|            if (clip.clipRef >= mClips.size()) {
  ------------------
  |  Branch (676:17): [True: 0, False: 0]
  ------------------
  677|      0|                ASSIMP_LOG_ERROR("LWO2: Clip referrer index is out of range");
  678|      0|                clip.clipRef = 0;
  679|      0|            }
  680|       |
  681|      0|            Clip &dest = mClips[clip.clipRef];
  682|      0|            if (Clip::REF == dest.type) {
  ------------------
  |  Branch (682:17): [True: 0, False: 0]
  ------------------
  683|      0|                ASSIMP_LOG_ERROR("LWO2: Clip references another clip reference");
  684|      0|                clip.type = Clip::UNSUPPORTED;
  685|      0|            }
  686|       |
  687|      0|            else {
  688|      0|                clip.path = dest.path;
  689|      0|                clip.type = dest.type;
  690|      0|            }
  691|      0|        }
  692|      2|    }
  693|      8|}
_ZN6Assimp11LWOImporter17AdjustTexturePathERNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEE:
  696|      2|void LWOImporter::AdjustTexturePath(std::string &out) {
  697|       |    // --- this function is used for both LWO2 and LWOB
  698|      2|    if (!mIsLWO2 && !mIsLWO3 && ::strstr(out.c_str(), "(sequence)")) {
  ------------------
  |  Branch (698:9): [True: 0, False: 2]
  |  Branch (698:21): [True: 0, False: 0]
  |  Branch (698:33): [True: 0, False: 0]
  ------------------
  699|       |
  700|       |        // remove the (sequence) and append 000
  701|      0|        ASSIMP_LOG_INFO("LWOB: Sequence of animated texture found. It will be ignored");
  702|      0|        out = out.substr(0, out.length() - 10) + "000";
  703|      0|    }
  704|       |
  705|       |    // format: drive:path/file - we just need to insert a slash after the drive
  706|      2|    std::string::size_type n = out.find_first_of(':');
  707|      2|    if (std::string::npos != n) {
  ------------------
  |  Branch (707:9): [True: 1, False: 1]
  ------------------
  708|      1|        out.insert(n + 1, "/");
  709|      1|    }
  710|      2|}
_ZN6Assimp11LWOImporter11LoadLWOTagsEj:
  713|     15|void LWOImporter::LoadLWOTags(unsigned int size) {
  714|       |    // --- this function is used for both LWO2 and LWOB
  715|       |
  716|     15|    const char *szCur = (const char *)mFileBuffer, *szLast = szCur;
  717|     15|    const char *const szEnd = szLast + size;
  718|    251|    while (szCur < szEnd) {
  ------------------
  |  Branch (718:12): [True: 236, False: 15]
  ------------------
  719|    236|        if (!(*szCur)) {
  ------------------
  |  Branch (719:13): [True: 32, False: 204]
  ------------------
  720|     32|            const size_t len = (size_t)(szCur - szLast);
  721|       |            // FIX: skip empty-sized tags
  722|     32|            if (len)
  ------------------
  |  Branch (722:17): [True: 32, False: 0]
  ------------------
  723|     32|                mTags->push_back(std::string(szLast, len));
  724|     32|            szCur += (len & 0x1 ? 1 : 2);
  ------------------
  |  Branch (724:23): [True: 29, False: 3]
  ------------------
  725|     32|            szLast = szCur;
  726|     32|        }
  727|    236|        szCur++;
  728|    236|    }
  729|     15|}
_ZN6Assimp11LWOImporter13LoadLWOPointsEj:
  732|     24|void LWOImporter::LoadLWOPoints(unsigned int length) {
  733|       |    // --- this function is used for both LWO2 and LWOB but for
  734|       |    // LWO2 we need to allocate 25% more storage - it could be we'll
  735|       |    // need to duplicate some points later.
  736|     24|    const size_t vertexLen = 12;
  737|     24|    if ((length % vertexLen) != 0) {
  ------------------
  |  Branch (737:9): [True: 0, False: 24]
  ------------------
  738|      0|        throw DeadlyImportError("LWO2: Points chunk length is not multiple of vertexLen (12)");
  739|      0|    }
  740|     24|    unsigned int regularSize = (unsigned int)mCurLayer->mTempPoints.size() + length / 12;
  741|     24|    if (mIsLWO2 || mIsLWO3) {
  ------------------
  |  Branch (741:9): [True: 24, False: 0]
  |  Branch (741:20): [True: 0, False: 0]
  ------------------
  742|     24|        mCurLayer->mTempPoints.reserve(regularSize + (regularSize >> 2u));
  743|     24|        mCurLayer->mTempPoints.resize(regularSize);
  744|       |
  745|       |        // initialize all point referrers with the default values
  746|     24|        mCurLayer->mPointReferrers.reserve(regularSize + (regularSize >> 2u));
  747|     24|        mCurLayer->mPointReferrers.resize(regularSize, UINT_MAX);
  748|     24|    } else
  749|      0|        mCurLayer->mTempPoints.resize(regularSize);
  750|       |
  751|       |        // perform endianness conversions
  752|     24|#ifndef AI_BUILD_BIG_ENDIAN
  753|  26.5k|    for (unsigned int i = 0; i<length >> 2; ++i)
  ------------------
  |  Branch (753:30): [True: 26.5k, False: 24]
  ------------------
  754|  26.5k|        ByteSwap::Swap4(mFileBuffer + (i << 2));
  755|     24|#endif
  756|     24|    ::memcpy(&mCurLayer->mTempPoints[0], mFileBuffer, length);
  757|     24|}
_ZN6Assimp11LWOImporter16LoadLWO2PolygonsEj:
  760|     21|void LWOImporter::LoadLWO2Polygons(unsigned int length) {
  761|     21|    LE_NCONST uint16_t *const end = (LE_NCONST uint16_t *)(mFileBuffer + length);
  762|     21|    const uint32_t type = GetU4();
  763|       |
  764|       |    // Determine the type of the polygons
  765|     21|    switch (type) {
  766|       |            // read unsupported stuff too (although we won't process it)
  767|      0|        case AI_LWO_MBAL:
  ------------------
  |  |  120|      0|#define AI_LWO_MBAL AI_IFF_FOURCC('M', 'B', 'A', 'L')
  |  |  ------------------
  |  |  |  |   50|      0|#define AI_IFF_FOURCC(a,b,c,d) ((uint32_t) (((uint8_t)a << 24u) | \
  |  |  |  |   51|      0|    ((uint8_t)b << 16u) | ((uint8_t)c << 8u) | ((uint8_t)d)))
  |  |  ------------------
  ------------------
  |  Branch (767:9): [True: 0, False: 21]
  ------------------
  768|      0|            ASSIMP_LOG_WARN("LWO2: Encountered unsupported primitive chunk (METABALL)");
  769|      0|            break;
  770|      0|        case AI_LWO_CURV:
  ------------------
  |  |  118|      0|#define AI_LWO_CURV AI_IFF_FOURCC('C', 'U', 'R', 'V')
  |  |  ------------------
  |  |  |  |   50|      0|#define AI_IFF_FOURCC(a,b,c,d) ((uint32_t) (((uint8_t)a << 24u) | \
  |  |  |  |   51|      0|    ((uint8_t)b << 16u) | ((uint8_t)c << 8u) | ((uint8_t)d)))
  |  |  ------------------
  ------------------
  |  Branch (770:9): [True: 0, False: 21]
  ------------------
  771|      0|            ASSIMP_LOG_WARN("LWO2: Encountered unsupported primitive chunk (SPLINE)");
  772|      0|            ;
  773|      0|            break;
  774|       |
  775|       |            // These are ok with no restrictions
  776|      0|        case AI_LWO_PTCH:
  ------------------
  |  |  119|      0|#define AI_LWO_PTCH AI_IFF_FOURCC('P', 'T', 'C', 'H')
  |  |  ------------------
  |  |  |  |   50|      0|#define AI_IFF_FOURCC(a,b,c,d) ((uint32_t) (((uint8_t)a << 24u) | \
  |  |  |  |   51|      0|    ((uint8_t)b << 16u) | ((uint8_t)c << 8u) | ((uint8_t)d)))
  |  |  ------------------
  ------------------
  |  Branch (776:9): [True: 0, False: 21]
  ------------------
  777|     21|        case AI_LWO_FACE:
  ------------------
  |  |  117|     21|#define AI_LWO_FACE AI_IFF_FOURCC('F', 'A', 'C', 'E')
  |  |  ------------------
  |  |  |  |   50|     21|#define AI_IFF_FOURCC(a,b,c,d) ((uint32_t) (((uint8_t)a << 24u) | \
  |  |  |  |   51|     21|    ((uint8_t)b << 16u) | ((uint8_t)c << 8u) | ((uint8_t)d)))
  |  |  ------------------
  ------------------
  |  Branch (777:9): [True: 21, False: 0]
  ------------------
  778|     21|        case AI_LWO_BONE:
  ------------------
  |  |  121|     21|#define AI_LWO_BONE AI_IFF_FOURCC('B', 'O', 'N', 'E')
  |  |  ------------------
  |  |  |  |   50|     21|#define AI_IFF_FOURCC(a,b,c,d) ((uint32_t) (((uint8_t)a << 24u) | \
  |  |  |  |   51|     21|    ((uint8_t)b << 16u) | ((uint8_t)c << 8u) | ((uint8_t)d)))
  |  |  ------------------
  ------------------
  |  Branch (778:9): [True: 0, False: 21]
  ------------------
  779|     21|        case AI_LWO_SUBD:
  ------------------
  |  |  122|     21|#define AI_LWO_SUBD AI_IFF_FOURCC('S', 'U', 'B', 'D')
  |  |  ------------------
  |  |  |  |   50|     21|#define AI_IFF_FOURCC(a,b,c,d) ((uint32_t) (((uint8_t)a << 24u) | \
  |  |  |  |   51|     21|    ((uint8_t)b << 16u) | ((uint8_t)c << 8u) | ((uint8_t)d)))
  |  |  ------------------
  ------------------
  |  Branch (779:9): [True: 0, False: 21]
  ------------------
  780|     21|            break;
  781|      0|        default:
  ------------------
  |  Branch (781:9): [True: 0, False: 21]
  ------------------
  782|       |
  783|       |            // hm!? wtf is this? ok ...
  784|      0|            ASSIMP_LOG_ERROR("LWO2: Ignoring unknown polygon type.");
  785|      0|            break;
  786|     21|    }
  787|       |
  788|       |    // first find out how many faces and vertices we'll finally need
  789|     21|    uint16_t *cursor = (uint16_t *)mFileBuffer;
  790|       |
  791|     21|    unsigned int iNumFaces = 0, iNumVertices = 0;
  792|     21|    CountVertsAndFacesLWO2(iNumVertices, iNumFaces, cursor, end);
  793|       |
  794|       |    // allocate the output array and copy face indices
  795|     21|    if (iNumFaces) {
  ------------------
  |  Branch (795:9): [True: 21, False: 0]
  ------------------
  796|     21|        cursor = (uint16_t *)mFileBuffer;
  797|       |
  798|     21|        mCurLayer->mFaces.resize(iNumFaces, LWO::Face(type));
  799|     21|        FaceList::iterator it = mCurLayer->mFaces.begin();
  800|     21|        CopyFaceIndicesLWO2(it, cursor, end);
  801|     21|    }
  802|     21|}
_ZN6Assimp11LWOImporter22CountVertsAndFacesLWO2ERjS1_RPtPKtj:
  806|     21|        uint16_t *&cursor, const uint16_t *const end, unsigned int max) {
  807|  5.75k|    while (cursor < end && max--) {
  ------------------
  |  Branch (807:12): [True: 5.73k, False: 21]
  |  Branch (807:28): [True: 5.73k, False: 0]
  ------------------
  808|  5.73k|        uint16_t numIndices;
  809|  5.73k|        ::memcpy(&numIndices, cursor++, 2);
  810|  5.73k|        AI_LSWAP2(numIndices);
  811|  5.73k|        numIndices &= 0x03FF;
  812|       |
  813|  5.73k|        verts += numIndices;
  814|  5.73k|        ++faces;
  815|       |
  816|  31.7k|        for (uint16_t i = 0; i < numIndices; i++) {
  ------------------
  |  Branch (816:30): [True: 26.0k, False: 5.73k]
  ------------------
  817|  26.0k|            ReadVSizedIntLWO2((uint8_t *&)cursor);
  818|  26.0k|        }
  819|  5.73k|    }
  820|     21|}
_ZN6Assimp11LWOImporter19CopyFaceIndicesLWO2ERNSt3__111__wrap_iterIPNS_3LWO4FaceEEERPtPKt:
  825|     21|        const uint16_t *const end) {
  826|  5.74k|    while (cursor < end) {
  ------------------
  |  Branch (826:12): [True: 5.72k, False: 20]
  ------------------
  827|  5.72k|        LWO::Face &face = *it++;
  828|  5.72k|        uint16_t numIndices;
  829|  5.72k|        ::memcpy(&numIndices, cursor++, 2);
  830|  5.72k|        AI_LSWAP2(numIndices);
  831|  5.72k|        face.mNumIndices = numIndices & 0x03FF;
  832|       |
  833|  5.72k|        if (face.mNumIndices) /* byte swapping has already been done */
  ------------------
  |  Branch (833:13): [True: 5.72k, False: 1]
  ------------------
  834|  5.72k|        {
  835|  5.72k|            face.mIndices = new unsigned int[face.mNumIndices];
  836|  28.5k|            for (unsigned int i = 0; i < face.mNumIndices; i++) {
  ------------------
  |  Branch (836:38): [True: 22.7k, False: 5.72k]
  ------------------
  837|  22.7k|                face.mIndices[i] = ReadVSizedIntLWO2((uint8_t *&)cursor) + mCurLayer->mPointIDXOfs;
  838|  22.7k|                if (face.mIndices[i] > mCurLayer->mTempPoints.size()) {
  ------------------
  |  Branch (838:21): [True: 23, False: 22.7k]
  ------------------
  839|     23|                    ASSIMP_LOG_WARN("LWO2: Failure evaluating face record, index is out of range");
  840|     23|                    face.mIndices[i] = (unsigned int)mCurLayer->mTempPoints.size() - 1;
  841|     23|                }
  842|  22.7k|            }
  843|  5.72k|        } else
  844|      1|            throw DeadlyImportError("LWO2: Encountered invalid face record with zero indices");
  845|  5.72k|    }
  846|     21|}
_ZN6Assimp11LWOImporter19LoadLWO2PolygonTagsEj:
  849|     36|void LWOImporter::LoadLWO2PolygonTags(unsigned int length) {
  850|     36|    LE_NCONST uint8_t *const end = mFileBuffer + length;
  851|       |
  852|     36|    AI_LWO_VALIDATE_CHUNK_LENGTH(length, PTAG, 4);
  ------------------
  |  |  631|     36|    if (length < size) {                                              \
  |  |  ------------------
  |  |  |  Branch (631:9): [True: 0, False: 36]
  |  |  ------------------
  |  |  632|      0|        throw DeadlyImportError("LWO: " #name " chunk is too small"); \
  |  |  633|      0|    }
  ------------------
  853|     36|    uint32_t type = GetU4();
  854|       |
  855|     36|    if (type != AI_LWO_SURF && type != AI_LWO_SMGP)
  ------------------
  |  |  125|     36|#define AI_LWO_SURF AI_IFF_FOURCC('S', 'U', 'R', 'F')
  |  |  ------------------
  |  |  |  |   50|     72|#define AI_IFF_FOURCC(a,b,c,d) ((uint32_t) (((uint8_t)a << 24u) | \
  |  |  |  |   51|     72|    ((uint8_t)b << 16u) | ((uint8_t)c << 8u) | ((uint8_t)d)))
  |  |  ------------------
  ------------------
                  if (type != AI_LWO_SURF && type != AI_LWO_SMGP)
  ------------------
  |  |  127|     20|#define AI_LWO_SMGP AI_IFF_FOURCC('S', 'M', 'G', 'P')
  |  |  ------------------
  |  |  |  |   50|     20|#define AI_IFF_FOURCC(a,b,c,d) ((uint32_t) (((uint8_t)a << 24u) | \
  |  |  |  |   51|     20|    ((uint8_t)b << 16u) | ((uint8_t)c << 8u) | ((uint8_t)d)))
  |  |  ------------------
  ------------------
  |  Branch (855:9): [True: 20, False: 16]
  |  Branch (855:32): [True: 20, False: 0]
  ------------------
  856|     20|        return;
  857|       |
  858|  1.99k|    while (mFileBuffer < end) {
  ------------------
  |  Branch (858:12): [True: 1.97k, False: 16]
  ------------------
  859|  1.97k|        unsigned int i = ReadVSizedIntLWO2(mFileBuffer) + mCurLayer->mFaceIDXOfs;
  860|  1.97k|        unsigned int j = GetU2();
  861|       |
  862|  1.97k|        if (i >= mCurLayer->mFaces.size()) {
  ------------------
  |  Branch (862:13): [True: 32, False: 1.94k]
  ------------------
  863|     32|            ASSIMP_LOG_WARN("LWO2: face index in PTAG is out of range");
  864|     32|            continue;
  865|     32|        }
  866|       |
  867|  1.94k|        switch (type) {
  ------------------
  |  Branch (867:17): [True: 1.94k, False: 0]
  ------------------
  868|       |
  869|  1.94k|            case AI_LWO_SURF:
  ------------------
  |  |  125|  1.94k|#define AI_LWO_SURF AI_IFF_FOURCC('S', 'U', 'R', 'F')
  |  |  ------------------
  |  |  |  |   50|  1.94k|#define AI_IFF_FOURCC(a,b,c,d) ((uint32_t) (((uint8_t)a << 24u) | \
  |  |  |  |   51|  1.94k|    ((uint8_t)b << 16u) | ((uint8_t)c << 8u) | ((uint8_t)d)))
  |  |  ------------------
  ------------------
  |  Branch (869:13): [True: 1.94k, False: 0]
  ------------------
  870|  1.94k|                mCurLayer->mFaces[i].surfaceIndex = j;
  871|  1.94k|                break;
  872|      0|            case AI_LWO_SMGP: /* is that really used? */
  ------------------
  |  |  127|      0|#define AI_LWO_SMGP AI_IFF_FOURCC('S', 'M', 'G', 'P')
  |  |  ------------------
  |  |  |  |   50|      0|#define AI_IFF_FOURCC(a,b,c,d) ((uint32_t) (((uint8_t)a << 24u) | \
  |  |  |  |   51|      0|    ((uint8_t)b << 16u) | ((uint8_t)c << 8u) | ((uint8_t)d)))
  |  |  ------------------
  ------------------
  |  Branch (872:13): [True: 0, False: 1.94k]
  ------------------
  873|      0|                mCurLayer->mFaces[i].smoothGroup = j;
  874|      0|                break;
  875|  1.94k|        };
  876|  1.94k|    }
  877|     16|}
_ZN6Assimp11LWOImporter17LoadLWO2VertexMapEjb:
  948|     29|void LWOImporter::LoadLWO2VertexMap(unsigned int length, bool perPoly) {
  949|     29|    LE_NCONST uint8_t *const end = mFileBuffer + length;
  950|       |
  951|     29|    AI_LWO_VALIDATE_CHUNK_LENGTH(length, VMAP, 6);
  ------------------
  |  |  631|     29|    if (length < size) {                                              \
  |  |  ------------------
  |  |  |  Branch (631:9): [True: 0, False: 29]
  |  |  ------------------
  |  |  632|      0|        throw DeadlyImportError("LWO: " #name " chunk is too small"); \
  |  |  633|      0|    }
  ------------------
  952|     29|    unsigned int type = GetU4();
  953|     29|    unsigned int dims = GetU2();
  954|       |
  955|     29|    VMapEntry *base;
  956|       |
  957|       |    // read the name of the vertex map
  958|     29|    std::string name;
  959|     29|    GetS0(name, length);
  960|       |
  961|     29|    switch (type) {
  962|     13|        case AI_LWO_TXUV:
  ------------------
  |  |  242|     13|#define AI_LWO_TXUV AI_IFF_FOURCC('T', 'X', 'U', 'V')
  |  |  ------------------
  |  |  |  |   50|     13|#define AI_IFF_FOURCC(a,b,c,d) ((uint32_t) (((uint8_t)a << 24u) | \
  |  |  |  |   51|     13|    ((uint8_t)b << 16u) | ((uint8_t)c << 8u) | ((uint8_t)d)))
  |  |  ------------------
  ------------------
  |  Branch (962:9): [True: 13, False: 16]
  ------------------
  963|     13|            if (dims != 2) {
  ------------------
  |  Branch (963:17): [True: 0, False: 13]
  ------------------
  964|      0|                ASSIMP_LOG_WARN("LWO2: Skipping UV channel \'", name, "\' with !2 components");
  965|      0|                return;
  966|      0|            }
  967|     13|            base = FindEntry(mCurLayer->mUVChannels, name, perPoly);
  968|     13|            break;
  969|      6|        case AI_LWO_WGHT:
  ------------------
  |  |  245|      6|#define AI_LWO_WGHT AI_IFF_FOURCC('W', 'G', 'H', 'T')
  |  |  ------------------
  |  |  |  |   50|      6|#define AI_IFF_FOURCC(a,b,c,d) ((uint32_t) (((uint8_t)a << 24u) | \
  |  |  |  |   51|      6|    ((uint8_t)b << 16u) | ((uint8_t)c << 8u) | ((uint8_t)d)))
  |  |  ------------------
  ------------------
  |  Branch (969:9): [True: 6, False: 23]
  ------------------
  970|      6|        case AI_LWO_MNVW:
  ------------------
  |  |  247|      6|#define AI_LWO_MNVW AI_IFF_FOURCC('M', 'N', 'V', 'W')
  |  |  ------------------
  |  |  |  |   50|      6|#define AI_IFF_FOURCC(a,b,c,d) ((uint32_t) (((uint8_t)a << 24u) | \
  |  |  |  |   51|      6|    ((uint8_t)b << 16u) | ((uint8_t)c << 8u) | ((uint8_t)d)))
  |  |  ------------------
  ------------------
  |  Branch (970:9): [True: 0, False: 29]
  ------------------
  971|      6|            if (dims != 1) {
  ------------------
  |  Branch (971:17): [True: 0, False: 6]
  ------------------
  972|      0|                ASSIMP_LOG_WARN("LWO2: Skipping Weight Channel \'", name, "\' with !1 components");
  973|      0|                return;
  974|      0|            }
  975|      6|            base = FindEntry((type == AI_LWO_WGHT ? mCurLayer->mWeightChannels : mCurLayer->mSWeightChannels), name, perPoly);
  ------------------
  |  |  245|      6|#define AI_LWO_WGHT AI_IFF_FOURCC('W', 'G', 'H', 'T')
  |  |  ------------------
  |  |  |  |   50|      6|#define AI_IFF_FOURCC(a,b,c,d) ((uint32_t) (((uint8_t)a << 24u) | \
  |  |  |  |   51|      6|    ((uint8_t)b << 16u) | ((uint8_t)c << 8u) | ((uint8_t)d)))
  |  |  ------------------
  ------------------
  |  Branch (975:31): [True: 6, False: 0]
  ------------------
  976|      6|            break;
  977|      0|        case AI_LWO_RGB:
  ------------------
  |  |  243|      0|#define AI_LWO_RGB AI_IFF_FOURCC('R', 'G', 'B', ' ')
  |  |  ------------------
  |  |  |  |   50|      0|#define AI_IFF_FOURCC(a,b,c,d) ((uint32_t) (((uint8_t)a << 24u) | \
  |  |  |  |   51|      0|    ((uint8_t)b << 16u) | ((uint8_t)c << 8u) | ((uint8_t)d)))
  |  |  ------------------
  ------------------
  |  Branch (977:9): [True: 0, False: 29]
  ------------------
  978|      3|        case AI_LWO_RGBA:
  ------------------
  |  |  244|      3|#define AI_LWO_RGBA AI_IFF_FOURCC('R', 'G', 'B', 'A')
  |  |  ------------------
  |  |  |  |   50|      3|#define AI_IFF_FOURCC(a,b,c,d) ((uint32_t) (((uint8_t)a << 24u) | \
  |  |  |  |   51|      3|    ((uint8_t)b << 16u) | ((uint8_t)c << 8u) | ((uint8_t)d)))
  |  |  ------------------
  ------------------
  |  Branch (978:9): [True: 3, False: 26]
  ------------------
  979|      3|            if (dims != 3 && dims != 4) {
  ------------------
  |  Branch (979:17): [True: 3, False: 0]
  |  Branch (979:30): [True: 0, False: 3]
  ------------------
  980|      0|                ASSIMP_LOG_WARN("LWO2: Skipping Color Map \'", name, "\' with a dimension > 4 or < 3");
  981|      0|                return;
  982|      0|            }
  983|      3|            base = FindEntry(mCurLayer->mVColorChannels, name, perPoly);
  984|      3|            break;
  985|       |
  986|      7|        case AI_LWO_MODO_NORM:
  ------------------
  |  |  304|      7|#define AI_LWO_MODO_NORM AI_IFF_FOURCC('N', 'O', 'R', 'M')
  |  |  ------------------
  |  |  |  |   50|      7|#define AI_IFF_FOURCC(a,b,c,d) ((uint32_t) (((uint8_t)a << 24u) | \
  |  |  |  |   51|      7|    ((uint8_t)b << 16u) | ((uint8_t)c << 8u) | ((uint8_t)d)))
  |  |  ------------------
  ------------------
  |  Branch (986:9): [True: 7, False: 22]
  ------------------
  987|       |            /*  This is a non-standard extension chunk used by Luxology's MODO.
  988|       |         *  It stores per-vertex normals. This VMAP exists just once, has
  989|       |         *  3 dimensions and is btw extremely beautiful.
  990|       |         */
  991|      7|            if (name != "vert_normals" || dims != 3 || mCurLayer->mNormals.name.length())
  ------------------
  |  Branch (991:17): [True: 0, False: 7]
  |  Branch (991:43): [True: 0, False: 7]
  |  Branch (991:56): [True: 3, False: 4]
  ------------------
  992|      3|                return;
  993|       |
  994|      7|            ASSIMP_LOG_INFO("Processing non-standard extension: MODO VMAP.NORM.vert_normals");
  995|       |
  996|      4|            mCurLayer->mNormals.name = name;
  997|      4|            base = &mCurLayer->mNormals;
  998|      4|            break;
  999|       |
 1000|      0|        case AI_LWO_PICK: /* these VMAPs are just silently dropped */
  ------------------
  |  |  250|      0|#define AI_LWO_PICK AI_IFF_FOURCC('P', 'I', 'C', 'K')
  |  |  ------------------
  |  |  |  |   50|      0|#define AI_IFF_FOURCC(a,b,c,d) ((uint32_t) (((uint8_t)a << 24u) | \
  |  |  |  |   51|      0|    ((uint8_t)b << 16u) | ((uint8_t)c << 8u) | ((uint8_t)d)))
  |  |  ------------------
  ------------------
  |  Branch (1000:9): [True: 0, False: 29]
  ------------------
 1001|      0|        case AI_LWO_MORF:
  ------------------
  |  |  248|      0|#define AI_LWO_MORF AI_IFF_FOURCC('M', 'O', 'R', 'F')
  |  |  ------------------
  |  |  |  |   50|      0|#define AI_IFF_FOURCC(a,b,c,d) ((uint32_t) (((uint8_t)a << 24u) | \
  |  |  |  |   51|      0|    ((uint8_t)b << 16u) | ((uint8_t)c << 8u) | ((uint8_t)d)))
  |  |  ------------------
  ------------------
  |  Branch (1001:9): [True: 0, False: 29]
  ------------------
 1002|      0|        case AI_LWO_SPOT:
  ------------------
  |  |  249|      0|#define AI_LWO_SPOT AI_IFF_FOURCC('S', 'P', 'O', 'T')
  |  |  ------------------
  |  |  |  |   50|      0|#define AI_IFF_FOURCC(a,b,c,d) ((uint32_t) (((uint8_t)a << 24u) | \
  |  |  |  |   51|      0|    ((uint8_t)b << 16u) | ((uint8_t)c << 8u) | ((uint8_t)d)))
  |  |  ------------------
  ------------------
  |  Branch (1002:9): [True: 0, False: 29]
  ------------------
 1003|      0|            return;
 1004|       |
 1005|      0|        default:
  ------------------
  |  Branch (1005:9): [True: 0, False: 29]
  ------------------
 1006|      0|            if (name == "APS.Level") {
  ------------------
  |  Branch (1006:17): [True: 0, False: 0]
  ------------------
 1007|       |                // XXX handle this (seems to be subdivision-related).
 1008|      0|            }
 1009|      0|            ASSIMP_LOG_WARN("LWO2: Skipping unknown VMAP/VMAD channel \'", name, "\'");
 1010|      0|            return;
 1011|     29|    };
 1012|     26|    base->Allocate((unsigned int)mCurLayer->mTempPoints.size());
 1013|       |
 1014|       |    // now read all entries in the map
 1015|     26|    type = std::min(dims, base->dims);
 1016|     26|    const unsigned int diff = (dims - type) << 2u;
 1017|       |
 1018|     26|    LWO::FaceList &list = mCurLayer->mFaces;
 1019|     26|    LWO::PointList &pointList = mCurLayer->mTempPoints;
 1020|     26|    LWO::ReferrerList &refList = mCurLayer->mPointReferrers;
 1021|       |
 1022|     26|    const unsigned int numPoints = (unsigned int)pointList.size();
 1023|     26|    const unsigned int numFaces = (unsigned int)list.size();
 1024|       |
 1025|  10.4k|    while (mFileBuffer < end) {
  ------------------
  |  Branch (1025:12): [True: 10.4k, False: 26]
  ------------------
 1026|       |
 1027|  10.4k|        unsigned int idx = ReadVSizedIntLWO2(mFileBuffer) + mCurLayer->mPointIDXOfs;
 1028|  10.4k|        if (idx >= numPoints) {
  ------------------
  |  Branch (1028:13): [True: 1.35k, False: 9.05k]
  ------------------
 1029|  1.35k|            ASSIMP_LOG_WARN("LWO2: Failure evaluating VMAP/VMAD entry \'", name, "\', vertex index is out of range");
 1030|  1.35k|            mFileBuffer += base->dims << 2u;
 1031|  1.35k|            continue;
 1032|  1.35k|        }
 1033|  9.05k|        if (perPoly) {
  ------------------
  |  Branch (1033:13): [True: 454, False: 8.60k]
  ------------------
 1034|    454|            unsigned int polyIdx = ReadVSizedIntLWO2(mFileBuffer) + mCurLayer->mFaceIDXOfs;
 1035|    454|            if (base->abAssigned[idx]) {
  ------------------
  |  Branch (1035:17): [True: 454, False: 0]
  ------------------
 1036|       |                // we have already a VMAP entry for this vertex - thus
 1037|       |                // we need to duplicate the corresponding polygon.
 1038|    454|                if (polyIdx >= numFaces) {
  ------------------
  |  Branch (1038:21): [True: 0, False: 454]
  ------------------
 1039|      0|                    ASSIMP_LOG_WARN("LWO2: Failure evaluating VMAD entry \'", name, "\', polygon index is out of range");
 1040|      0|                    mFileBuffer += base->dims << 2u;
 1041|      0|                    continue;
 1042|      0|                }
 1043|       |
 1044|    454|                LWO::Face &src = list[polyIdx];
 1045|       |
 1046|       |                // generate a new unique vertex for the corresponding index - but only
 1047|       |                // if we can find the index in the face
 1048|    454|                bool had = false;
 1049|  4.31k|                for (unsigned int i = 0; i < src.mNumIndices; ++i) {
  ------------------
  |  Branch (1049:42): [True: 3.86k, False: 454]
  ------------------
 1050|       |
 1051|  3.86k|                    unsigned int srcIdx = src.mIndices[i], tmp = idx;
 1052|  4.23k|                    do {
 1053|  4.23k|                        if (tmp == srcIdx)
  ------------------
  |  Branch (1053:29): [True: 454, False: 3.78k]
  ------------------
 1054|    454|                            break;
 1055|  4.23k|                    } while ((tmp = refList[tmp]) != UINT_MAX);
  ------------------
  |  Branch (1055:30): [True: 376, False: 3.40k]
  ------------------
 1056|  3.86k|                    if (tmp == UINT_MAX) {
  ------------------
  |  Branch (1056:25): [True: 3.40k, False: 454]
  ------------------
 1057|  3.40k|                        continue;
 1058|  3.40k|                    }
 1059|       |
 1060|    454|                    had = true;
 1061|    454|                    refList.resize(refList.size() + 1, UINT_MAX);
 1062|       |
 1063|    454|                    idx = (unsigned int)pointList.size();
 1064|    454|                    src.mIndices[i] = (unsigned int)pointList.size();
 1065|       |
 1066|       |                    // store the index of the new vertex in the old vertex
 1067|       |                    // so we get a single linked list we can traverse in
 1068|       |                    // only one direction
 1069|    454|                    AddToSingleLinkedList(refList, srcIdx, src.mIndices[i]);
 1070|    454|                    pointList.push_back(pointList[srcIdx]);
 1071|       |
 1072|    454|                    CreateNewEntry(mCurLayer->mVColorChannels, srcIdx);
 1073|    454|                    CreateNewEntry(mCurLayer->mUVChannels, srcIdx);
 1074|    454|                    CreateNewEntry(mCurLayer->mWeightChannels, srcIdx);
 1075|    454|                    CreateNewEntry(mCurLayer->mSWeightChannels, srcIdx);
 1076|    454|                    CreateNewEntry(mCurLayer->mNormals, srcIdx);
 1077|    454|                }
 1078|    454|                if (!had) {
  ------------------
  |  Branch (1078:21): [True: 0, False: 454]
  ------------------
 1079|      0|                    ASSIMP_LOG_WARN("LWO2: Failure evaluating VMAD entry \'", name, "\', vertex index wasn't found in that polygon");
 1080|      0|                    ai_assert(had);
 1081|      0|                }
 1082|    454|            }
 1083|    454|        }
 1084|       |
 1085|  9.05k|        std::unique_ptr<float[]> temp(new float[type]);
 1086|  27.5k|        for (unsigned int l = 0; l < type; ++l)
  ------------------
  |  Branch (1086:34): [True: 18.4k, False: 9.05k]
  ------------------
 1087|  18.4k|            temp[l] = GetF4();
 1088|       |
 1089|  9.05k|        DoRecursiveVMAPAssignment(base, type, idx, temp.get());
 1090|  9.05k|        mFileBuffer += diff;
 1091|  9.05k|    }
 1092|     26|}
_ZN6Assimp11LWOImporter12LoadLWO2ClipEj:
 1096|      2|void LWOImporter::LoadLWO2Clip(unsigned int length) {
 1097|      2|    AI_LWO_VALIDATE_CHUNK_LENGTH(length, CLIP, 10);
  ------------------
  |  |  631|      2|    if (length < size) {                                              \
  |  |  ------------------
  |  |  |  Branch (631:9): [True: 0, False: 2]
  |  |  ------------------
  |  |  632|      0|        throw DeadlyImportError("LWO: " #name " chunk is too small"); \
  |  |  633|      0|    }
  ------------------
 1098|       |
 1099|      2|    mClips.emplace_back();
 1100|      2|    LWO::Clip &clip = mClips.back();
 1101|       |
 1102|       |    // first - get the index of the clip
 1103|      2|    clip.idx = GetU4();
 1104|       |
 1105|      2|    IFF::SubChunkHeader head = IFF::LoadSubChunk(mFileBuffer);
 1106|      2|    switch (head.type) {
 1107|      2|        case AI_LWO_STIL:
  ------------------
  |  |  142|      2|#define AI_LWO_STIL AI_IFF_FOURCC('S', 'T', 'I', 'L')
  |  |  ------------------
  |  |  |  |   50|      2|#define AI_IFF_FOURCC(a,b,c,d) ((uint32_t) (((uint8_t)a << 24u) | \
  |  |  |  |   51|      2|    ((uint8_t)b << 16u) | ((uint8_t)c << 8u) | ((uint8_t)d)))
  |  |  ------------------
  ------------------
  |  Branch (1107:9): [True: 2, False: 0]
  ------------------
 1108|      2|            AI_LWO_VALIDATE_CHUNK_LENGTH(head.length, STIL, 1);
  ------------------
  |  |  631|      2|    if (length < size) {                                              \
  |  |  ------------------
  |  |  |  Branch (631:9): [True: 0, False: 2]
  |  |  ------------------
  |  |  632|      0|        throw DeadlyImportError("LWO: " #name " chunk is too small"); \
  |  |  633|      0|    }
  ------------------
 1109|       |
 1110|       |            // "Normal" texture
 1111|      2|            GetS0(clip.path, head.length);
 1112|      2|            clip.type = Clip::STILL;
 1113|      2|            break;
 1114|       |
 1115|      0|        case AI_LWO_ISEQ:
  ------------------
  |  |  143|      0|#define AI_LWO_ISEQ AI_IFF_FOURCC('I', 'S', 'E', 'Q')
  |  |  ------------------
  |  |  |  |   50|      0|#define AI_IFF_FOURCC(a,b,c,d) ((uint32_t) (((uint8_t)a << 24u) | \
  |  |  |  |   51|      0|    ((uint8_t)b << 16u) | ((uint8_t)c << 8u) | ((uint8_t)d)))
  |  |  ------------------
  ------------------
  |  Branch (1115:9): [True: 0, False: 2]
  ------------------
 1116|      0|            AI_LWO_VALIDATE_CHUNK_LENGTH(head.length, ISEQ, 16);
  ------------------
  |  |  631|      0|    if (length < size) {                                              \
  |  |  ------------------
  |  |  |  Branch (631:9): [True: 0, False: 0]
  |  |  ------------------
  |  |  632|      0|        throw DeadlyImportError("LWO: " #name " chunk is too small"); \
  |  |  633|      0|    }
  ------------------
 1117|       |            // Image sequence. We'll later take the first.
 1118|      0|            {
 1119|      0|                uint8_t digits = GetU1();
 1120|      0|                mFileBuffer++;
 1121|      0|                int16_t offset = GetU2();
 1122|      0|                mFileBuffer += 4;
 1123|      0|                int16_t start = GetU2();
 1124|      0|                mFileBuffer += 4;
 1125|       |
 1126|      0|                std::string s;
 1127|      0|                std::ostringstream ss;
 1128|      0|                GetS0(s, head.length);
 1129|       |
 1130|      0|                head.length -= (uint16_t)s.length() + 1;
 1131|      0|                ss << s;
 1132|      0|                ss << std::setw(digits) << offset + start;
 1133|      0|                GetS0(s, head.length);
 1134|      0|                ss << s;
 1135|      0|                clip.path = ss.str();
 1136|      0|                clip.type = Clip::SEQ;
 1137|      0|            }
 1138|      0|            break;
 1139|       |
 1140|      0|        case AI_LWO_STCC:
  ------------------
  |  |  146|      0|#define AI_LWO_STCC AI_IFF_FOURCC('S', 'T', 'C', 'C')
  |  |  ------------------
  |  |  |  |   50|      0|#define AI_IFF_FOURCC(a,b,c,d) ((uint32_t) (((uint8_t)a << 24u) | \
  |  |  |  |   51|      0|    ((uint8_t)b << 16u) | ((uint8_t)c << 8u) | ((uint8_t)d)))
  |  |  ------------------
  ------------------
  |  Branch (1140:9): [True: 0, False: 2]
  ------------------
 1141|      0|            ASSIMP_LOG_WARN("LWO2: Color shifted images are not supported");
 1142|      0|            break;
 1143|       |
 1144|      0|        case AI_LWO_ANIM:
  ------------------
  |  |  144|      0|#define AI_LWO_ANIM AI_IFF_FOURCC('A', 'N', 'I', 'M')
  |  |  ------------------
  |  |  |  |   50|      0|#define AI_IFF_FOURCC(a,b,c,d) ((uint32_t) (((uint8_t)a << 24u) | \
  |  |  |  |   51|      0|    ((uint8_t)b << 16u) | ((uint8_t)c << 8u) | ((uint8_t)d)))
  |  |  ------------------
  ------------------
  |  Branch (1144:9): [True: 0, False: 2]
  ------------------
 1145|      0|            ASSIMP_LOG_WARN("LWO2: Animated textures are not supported");
 1146|      0|            break;
 1147|       |
 1148|      0|        case AI_LWO_XREF:
  ------------------
  |  |  145|      0|#define AI_LWO_XREF AI_IFF_FOURCC('X', 'R', 'E', 'F')
  |  |  ------------------
  |  |  |  |   50|      0|#define AI_IFF_FOURCC(a,b,c,d) ((uint32_t) (((uint8_t)a << 24u) | \
  |  |  |  |   51|      0|    ((uint8_t)b << 16u) | ((uint8_t)c << 8u) | ((uint8_t)d)))
  |  |  ------------------
  ------------------
  |  Branch (1148:9): [True: 0, False: 2]
  ------------------
 1149|      0|            AI_LWO_VALIDATE_CHUNK_LENGTH(head.length, XREF, 4);
  ------------------
  |  |  631|      0|    if (length < size) {                                              \
  |  |  ------------------
  |  |  |  Branch (631:9): [True: 0, False: 0]
  |  |  ------------------
  |  |  632|      0|        throw DeadlyImportError("LWO: " #name " chunk is too small"); \
  |  |  633|      0|    }
  ------------------
 1150|       |
 1151|       |            // Just a cross-reference to another CLIp
 1152|      0|            clip.type = Clip::REF;
 1153|      0|            clip.clipRef = GetU4();
 1154|      0|            break;
 1155|       |
 1156|      0|        case AI_LWO_NEGA:
  ------------------
  |  |  153|      0|#define AI_LWO_NEGA AI_IFF_FOURCC('N', 'E', 'G', 'A')
  |  |  ------------------
  |  |  |  |   50|      0|#define AI_IFF_FOURCC(a,b,c,d) ((uint32_t) (((uint8_t)a << 24u) | \
  |  |  |  |   51|      0|    ((uint8_t)b << 16u) | ((uint8_t)c << 8u) | ((uint8_t)d)))
  |  |  ------------------
  ------------------
  |  Branch (1156:9): [True: 0, False: 2]
  ------------------
 1157|      0|            AI_LWO_VALIDATE_CHUNK_LENGTH(head.length, NEGA, 2);
  ------------------
  |  |  631|      0|    if (length < size) {                                              \
  |  |  ------------------
  |  |  |  Branch (631:9): [True: 0, False: 0]
  |  |  ------------------
  |  |  632|      0|        throw DeadlyImportError("LWO: " #name " chunk is too small"); \
  |  |  633|      0|    }
  ------------------
 1158|      0|            clip.negate = (0 != GetU2());
 1159|      0|            break;
 1160|       |
 1161|      0|        default:
  ------------------
  |  Branch (1161:9): [True: 0, False: 2]
  ------------------
 1162|       |            ASSIMP_LOG_WARN("LWO2: Encountered unknown CLIP sub-chunk");
 1163|      2|    }
 1164|      2|}
_ZN6Assimp11LWOImporter12LoadLWO2FileEv:
 1446|     15|void LWOImporter::LoadLWO2File() {
 1447|     15|    bool skip = false;
 1448|       |
 1449|     15|    LE_NCONST uint8_t *const end = mFileBuffer + fileSize;
 1450|     15|    unsigned int iUnnamed = 0;
 1451|       |
 1452|    284|    while (true) {
  ------------------
  |  Branch (1452:12): [True: 284, Folded]
  ------------------
 1453|    284|        if (mFileBuffer + sizeof(IFF::ChunkHeader) > end) break;
  ------------------
  |  Branch (1453:13): [True: 8, False: 276]
  ------------------
 1454|       |
 1455|    276|        IFF::ChunkHeader head = IFF::LoadChunk(mFileBuffer);
 1456|       |
 1457|    276|        int bufOffset = 0;
 1458|    276|        if( head.type == AI_IFF_FOURCC_FORM ) { // not chunk, it's a form
  ------------------
  |  |   54|    276|#define AI_IFF_FOURCC_FORM AI_IFF_FOURCC('F','O','R','M')
  |  |  ------------------
  |  |  |  |   50|    276|#define AI_IFF_FOURCC(a,b,c,d) ((uint32_t) (((uint8_t)a << 24u) | \
  |  |  |  |   51|    276|    ((uint8_t)b << 16u) | ((uint8_t)c << 8u) | ((uint8_t)d)))
  |  |  ------------------
  ------------------
  |  Branch (1458:13): [True: 0, False: 276]
  ------------------
 1459|      0|            mFileBuffer -= 8;
 1460|      0|            head = IFF::LoadForm(mFileBuffer);
 1461|      0|            bufOffset = 4;
 1462|      0|        }
 1463|       |
 1464|    276|        if (mFileBuffer + head.length > end) {
  ------------------
  |  Branch (1464:13): [True: 6, False: 270]
  ------------------
 1465|      6|            throw DeadlyImportError("LWO2: Chunk length points behind the file");
 1466|      6|        }
 1467|    270|        uint8_t *const next = mFileBuffer + head.length;
 1468|    270|        mFileBuffer += bufOffset;
 1469|    270|        if (!head.length) {
  ------------------
  |  Branch (1469:13): [True: 0, False: 270]
  ------------------
 1470|      0|            mFileBuffer = next;
 1471|      0|            continue;
 1472|      0|        }
 1473|       |
 1474|    270|        switch (head.type) {
  ------------------
  |  Branch (1474:17): [True: 163, False: 107]
  ------------------
 1475|       |                // new layer
 1476|     24|            case AI_LWO_LAYR: {
  ------------------
  |  |  101|     24|#define AI_LWO_LAYR AI_IFF_FOURCC('L', 'A', 'Y', 'R')
  |  |  ------------------
  |  |  |  |   50|     24|#define AI_IFF_FOURCC(a,b,c,d) ((uint32_t) (((uint8_t)a << 24u) | \
  |  |  |  |   51|     24|    ((uint8_t)b << 16u) | ((uint8_t)c << 8u) | ((uint8_t)d)))
  |  |  ------------------
  ------------------
  |  Branch (1476:13): [True: 24, False: 246]
  ------------------
 1477|       |                // add a new layer to the list ....
 1478|     24|                mLayers->push_back(LWO::Layer());
 1479|     24|                LWO::Layer &layer = mLayers->back();
 1480|     24|                mCurLayer = &layer;
 1481|       |
 1482|     24|                AI_LWO_VALIDATE_CHUNK_LENGTH(head.length, LAYR, 16);
  ------------------
  |  |  631|     24|    if (length < size) {                                              \
  |  |  ------------------
  |  |  |  Branch (631:9): [True: 0, False: 24]
  |  |  ------------------
  |  |  632|      0|        throw DeadlyImportError("LWO: " #name " chunk is too small"); \
  |  |  633|      0|    }
  ------------------
 1483|       |
 1484|       |                // layer index.
 1485|     24|                layer.mIndex = GetU2();
 1486|       |
 1487|       |                // Continue loading this layer or ignore it? Check the layer index property
 1488|     24|                if (UINT_MAX != configLayerIndex && (configLayerIndex - 1) != layer.mIndex) {
  ------------------
  |  Branch (1488:21): [True: 0, False: 24]
  |  Branch (1488:53): [True: 0, False: 0]
  ------------------
 1489|      0|                    skip = true;
 1490|      0|                } else
 1491|     24|                    skip = false;
 1492|       |
 1493|       |                // pivot point
 1494|     24|                mFileBuffer += 2; /* unknown */
 1495|     24|                mCurLayer->mPivot.x = GetF4();
 1496|     24|                mCurLayer->mPivot.y = GetF4();
 1497|     24|                mCurLayer->mPivot.z = GetF4();
 1498|     24|                GetS0(layer.mName, head.length - 16);
 1499|       |
 1500|       |                // if the name is empty, generate a default name
 1501|     24|                if (layer.mName.empty()) {
  ------------------
  |  Branch (1501:21): [True: 12, False: 12]
  ------------------
 1502|     12|                    char buffer[128]; // should be sufficiently large
 1503|     12|                    ::ai_snprintf(buffer, 128, "Layer_%i", iUnnamed++);
 1504|     12|                    layer.mName = buffer;
 1505|     12|                }
 1506|       |
 1507|       |                // load this layer or ignore it? Check the layer name property
 1508|     24|                if (configLayerName.length() && configLayerName != layer.mName) {
  ------------------
  |  Branch (1508:21): [True: 0, False: 24]
  |  Branch (1508:49): [True: 0, False: 0]
  ------------------
 1509|      0|                    skip = true;
 1510|      0|                } else
 1511|     24|                    hasNamedLayer = true;
 1512|       |
 1513|       |                // optional: parent of this layer
 1514|     24|                if (mFileBuffer + 2 <= next)
  ------------------
  |  Branch (1514:21): [True: 16, False: 8]
  ------------------
 1515|     16|                    layer.mParent = GetU2();
 1516|      8|                else
 1517|      8|                    layer.mParent = (uint16_t) -1;
 1518|       |
 1519|       |                // Set layer skip parameter
 1520|     24|                layer.skip = skip;
 1521|       |
 1522|     24|                break;
 1523|     24|            }
 1524|       |                // vertex list
 1525|     24|            case AI_LWO_PNTS: {
  ------------------
  |  |  103|     24|#define AI_LWO_PNTS AI_IFF_FOURCC('P', 'N', 'T', 'S')
  |  |  ------------------
  |  |  |  |   50|     24|#define AI_IFF_FOURCC(a,b,c,d) ((uint32_t) (((uint8_t)a << 24u) | \
  |  |  |  |   51|     24|    ((uint8_t)b << 16u) | ((uint8_t)c << 8u) | ((uint8_t)d)))
  |  |  ------------------
  ------------------
  |  Branch (1525:13): [True: 24, False: 246]
  ------------------
 1526|     24|                if (skip)
  ------------------
  |  Branch (1526:21): [True: 0, False: 24]
  ------------------
 1527|      0|                    break;
 1528|       |
 1529|     24|                unsigned int old = (unsigned int)mCurLayer->mTempPoints.size();
 1530|     24|                LoadLWOPoints(head.length);
 1531|     24|                mCurLayer->mPointIDXOfs = old;
 1532|     24|                break;
 1533|     24|            }
 1534|       |                // vertex tags
 1535|      9|            case AI_LWO_VMAD:
  ------------------
  |  |  106|      9|#define AI_LWO_VMAD AI_IFF_FOURCC('V', 'M', 'A', 'D')
  |  |  ------------------
  |  |  |  |   50|      9|#define AI_IFF_FOURCC(a,b,c,d) ((uint32_t) (((uint8_t)a << 24u) | \
  |  |  |  |   51|      9|    ((uint8_t)b << 16u) | ((uint8_t)c << 8u) | ((uint8_t)d)))
  |  |  ------------------
  ------------------
  |  Branch (1535:13): [True: 9, False: 261]
  ------------------
 1536|      9|                if (mCurLayer->mFaces.empty()) {
  ------------------
  |  Branch (1536:21): [True: 0, False: 9]
  ------------------
 1537|      0|                    ASSIMP_LOG_WARN("LWO2: Unexpected VMAD chunk");
 1538|      0|                    break;
 1539|      0|                }
 1540|       |                // --- intentionally no break here
 1541|       |                // fallthrough
 1542|     29|            case AI_LWO_VMAP: {
  ------------------
  |  |  214|     29|#define AI_LWO_VMAP AI_IFF_FOURCC('V', 'M', 'A', 'P')
  |  |  ------------------
  |  |  |  |   50|     29|#define AI_IFF_FOURCC(a,b,c,d) ((uint32_t) (((uint8_t)a << 24u) | \
  |  |  |  |   51|     29|    ((uint8_t)b << 16u) | ((uint8_t)c << 8u) | ((uint8_t)d)))
  |  |  ------------------
  ------------------
  |  Branch (1542:13): [True: 20, False: 250]
  ------------------
 1543|     29|                if (skip)
  ------------------
  |  Branch (1543:21): [True: 0, False: 29]
  ------------------
 1544|      0|                    break;
 1545|       |
 1546|     29|                if (mCurLayer->mTempPoints.empty())
  ------------------
  |  Branch (1546:21): [True: 0, False: 29]
  ------------------
 1547|     29|                    ASSIMP_LOG_WARN("LWO2: Unexpected VMAP chunk");
 1548|     29|                else
 1549|     29|                    LoadLWO2VertexMap(head.length, head.type == AI_LWO_VMAD);
  ------------------
  |  |  106|     29|#define AI_LWO_VMAD AI_IFF_FOURCC('V', 'M', 'A', 'D')
  |  |  ------------------
  |  |  |  |   50|     29|#define AI_IFF_FOURCC(a,b,c,d) ((uint32_t) (((uint8_t)a << 24u) | \
  |  |  |  |   51|     29|    ((uint8_t)b << 16u) | ((uint8_t)c << 8u) | ((uint8_t)d)))
  |  |  ------------------
  ------------------
 1550|     29|                break;
 1551|     29|            }
 1552|       |                // face list
 1553|     21|            case AI_LWO_POLS: {
  ------------------
  |  |  107|     21|#define AI_LWO_POLS AI_IFF_FOURCC('P', 'O', 'L', 'S')
  |  |  ------------------
  |  |  |  |   50|     21|#define AI_IFF_FOURCC(a,b,c,d) ((uint32_t) (((uint8_t)a << 24u) | \
  |  |  |  |   51|     21|    ((uint8_t)b << 16u) | ((uint8_t)c << 8u) | ((uint8_t)d)))
  |  |  ------------------
  ------------------
  |  Branch (1553:13): [True: 21, False: 249]
  ------------------
 1554|     21|                if (skip)
  ------------------
  |  Branch (1554:21): [True: 0, False: 21]
  ------------------
 1555|      0|                    break;
 1556|       |
 1557|     21|                unsigned int old = (unsigned int)mCurLayer->mFaces.size();
 1558|     21|                LoadLWO2Polygons(head.length);
 1559|     21|                mCurLayer->mFaceIDXOfs = old;
 1560|     21|                break;
 1561|     21|            }
 1562|       |                // polygon tags
 1563|     36|            case AI_LWO_PTAG: {
  ------------------
  |  |  108|     36|#define AI_LWO_PTAG AI_IFF_FOURCC('P', 'T', 'A', 'G')
  |  |  ------------------
  |  |  |  |   50|     36|#define AI_IFF_FOURCC(a,b,c,d) ((uint32_t) (((uint8_t)a << 24u) | \
  |  |  |  |   51|     36|    ((uint8_t)b << 16u) | ((uint8_t)c << 8u) | ((uint8_t)d)))
  |  |  ------------------
  ------------------
  |  Branch (1563:13): [True: 36, False: 234]
  ------------------
 1564|     36|                if (skip)
  ------------------
  |  Branch (1564:21): [True: 0, False: 36]
  ------------------
 1565|      0|                    break;
 1566|       |
 1567|     36|                if (mCurLayer->mFaces.empty()) {
  ------------------
  |  Branch (1567:21): [True: 0, False: 36]
  ------------------
 1568|      0|                    ASSIMP_LOG_WARN("LWO2: Unexpected PTAG");
 1569|     36|                } else {
 1570|     36|                    LoadLWO2PolygonTags(head.length);
 1571|     36|                }
 1572|     36|                break;
 1573|     36|            }
 1574|       |                // list of tags
 1575|     15|            case AI_LWO_TAGS: {
  ------------------
  |  |  102|     15|#define AI_LWO_TAGS AI_IFF_FOURCC('T', 'A', 'G', 'S')
  |  |  ------------------
  |  |  |  |   50|     15|#define AI_IFF_FOURCC(a,b,c,d) ((uint32_t) (((uint8_t)a << 24u) | \
  |  |  |  |   51|     15|    ((uint8_t)b << 16u) | ((uint8_t)c << 8u) | ((uint8_t)d)))
  |  |  ------------------
  ------------------
  |  Branch (1575:13): [True: 15, False: 255]
  ------------------
 1576|     15|                if (!mTags->empty()) {
  ------------------
  |  Branch (1576:21): [True: 0, False: 15]
  ------------------
 1577|      0|                    ASSIMP_LOG_WARN("LWO2: SRFS chunk encountered twice");
 1578|     15|                } else {
 1579|     15|                    LoadLWOTags(head.length);
 1580|     15|                }
 1581|     15|                break;
 1582|     36|            }
 1583|       |
 1584|       |                // surface chunk
 1585|     12|            case AI_LWO_SURF: {
  ------------------
  |  |  125|     12|#define AI_LWO_SURF AI_IFF_FOURCC('S', 'U', 'R', 'F')
  |  |  ------------------
  |  |  |  |   50|     12|#define AI_IFF_FOURCC(a,b,c,d) ((uint32_t) (((uint8_t)a << 24u) | \
  |  |  |  |   51|     12|    ((uint8_t)b << 16u) | ((uint8_t)c << 8u) | ((uint8_t)d)))
  |  |  ------------------
  ------------------
  |  Branch (1585:13): [True: 12, False: 258]
  ------------------
 1586|     12|                if( mIsLWO3 )
  ------------------
  |  Branch (1586:21): [True: 0, False: 12]
  ------------------
 1587|      0|                    LoadLWO3Surface(head.length);
 1588|     12|                else
 1589|     12|                    LoadLWO2Surface(head.length);
 1590|       |
 1591|     12|                break;
 1592|     36|            }
 1593|       |
 1594|       |                // clip chunk
 1595|      2|            case AI_LWO_CLIP: {
  ------------------
  |  |  110|      2|#define AI_LWO_CLIP AI_IFF_FOURCC('C', 'L', 'I', 'P')
  |  |  ------------------
  |  |  |  |   50|      2|#define AI_IFF_FOURCC(a,b,c,d) ((uint32_t) (((uint8_t)a << 24u) | \
  |  |  |  |   51|      2|    ((uint8_t)b << 16u) | ((uint8_t)c << 8u) | ((uint8_t)d)))
  |  |  ------------------
  ------------------
  |  Branch (1595:13): [True: 2, False: 268]
  ------------------
 1596|      2|                if( mIsLWO3 )
  ------------------
  |  Branch (1596:21): [True: 0, False: 2]
  ------------------
 1597|      0|                    LoadLWO3Clip(head.length);
 1598|      2|                else
 1599|      2|                    LoadLWO2Clip(head.length);
 1600|      2|                break;
 1601|     36|            }
 1602|       |
 1603|       |                // envelope chunk
 1604|      0|            case AI_LWO_ENVL: {
  ------------------
  |  |  109|      0|#define AI_LWO_ENVL AI_IFF_FOURCC('E', 'N', 'V', 'L')
  |  |  ------------------
  |  |  |  |   50|      0|#define AI_IFF_FOURCC(a,b,c,d) ((uint32_t) (((uint8_t)a << 24u) | \
  |  |  |  |   51|      0|    ((uint8_t)b << 16u) | ((uint8_t)c << 8u) | ((uint8_t)d)))
  |  |  ------------------
  ------------------
  |  Branch (1604:13): [True: 0, False: 270]
  ------------------
 1605|      0|                if( mIsLWO3 )
  ------------------
  |  Branch (1605:21): [True: 0, False: 0]
  ------------------
 1606|      0|                    LoadLWO3Envelope(head.length);
 1607|      0|                else
 1608|      0|                    LoadLWO2Envelope(head.length);
 1609|      0|                break;
 1610|     36|            }
 1611|    270|        }
 1612|    269|        mFileBuffer = next;
 1613|    269|    }
 1614|     15|}
_Z21AddToSingleLinkedListRNSt3__16vectorIjNS_9allocatorIjEEEEjj:
  938|    728|inline void AddToSingleLinkedList(ReferrerList &refList, unsigned int srcIdx, unsigned int destIdx) {
  939|    728|    if (UINT_MAX == refList[srcIdx]) {
  ------------------
  |  Branch (939:9): [True: 454, False: 274]
  ------------------
  940|    454|        refList[srcIdx] = destIdx;
  941|    454|        return;
  942|    454|    }
  943|    274|    AddToSingleLinkedList(refList, refList[srcIdx], destIdx);
  944|    274|}
_ZN6Assimp11LWOImporter25DoRecursiveVMAPAssignmentEPNS_3LWO9VMapEntryEjjPf:
  919|  9.05k|        unsigned int idx, float *data) {
  920|  9.05k|    ai_assert(nullptr != data);
  921|  9.05k|    LWO::ReferrerList &refList = mCurLayer->mPointReferrers;
  922|  9.05k|    unsigned int i;
  923|       |
  924|  9.05k|    if (idx >= base->abAssigned.size()) {
  ------------------
  |  Branch (924:9): [True: 0, False: 9.05k]
  ------------------
  925|      0|        throw DeadlyImportError("Bad index");
  926|      0|    }
  927|  9.05k|    base->abAssigned[idx] = true;
  928|  27.5k|    for (i = 0; i < numRead; ++i) {
  ------------------
  |  Branch (928:17): [True: 18.4k, False: 9.05k]
  ------------------
  929|  18.4k|        base->rawData[idx * base->dims + i] = data[i];
  930|  18.4k|    }
  931|       |
  932|  9.05k|    if (UINT_MAX != (i = refList[idx])) {
  ------------------
  |  Branch (932:9): [True: 0, False: 9.05k]
  ------------------
  933|      0|        DoRecursiveVMAPAssignment(base, numRead, i, data);
  934|      0|    }
  935|  9.05k|}
_Z9FindEntryIN6Assimp3LWO9UVChannelEEPNS1_9VMapEntryERNSt3__16vectorIT_NS5_9allocatorIS7_EEEERKNS5_12basic_stringIcNS5_11char_traitsIcEENS8_IcEEEEb:
  881|     13|VMapEntry *FindEntry(std::vector<T> &list, const std::string &name, bool perPoly) {
  882|     13|    for (auto &elem : list) {
  ------------------
  |  Branch (882:21): [True: 7, False: 8]
  ------------------
  883|      7|        if (elem.name == name) {
  ------------------
  |  Branch (883:13): [True: 5, False: 2]
  ------------------
  884|      5|            if (!perPoly) {
  ------------------
  |  Branch (884:17): [True: 0, False: 5]
  ------------------
  885|      0|                ASSIMP_LOG_WARN("LWO2: Found two VMAP sections with equal names");
  886|      0|            }
  887|      5|            return &elem;
  888|      5|        }
  889|      7|    }
  890|      8|    list.push_back(T());
  891|      8|    VMapEntry *p = &list.back();
  892|      8|    p->name = name;
  893|      8|    return p;
  894|     13|}
_Z9FindEntryIN6Assimp3LWO13WeightChannelEEPNS1_9VMapEntryERNSt3__16vectorIT_NS5_9allocatorIS7_EEEERKNS5_12basic_stringIcNS5_11char_traitsIcEENS8_IcEEEEb:
  881|      6|VMapEntry *FindEntry(std::vector<T> &list, const std::string &name, bool perPoly) {
  882|      6|    for (auto &elem : list) {
  ------------------
  |  Branch (882:21): [True: 3, False: 6]
  ------------------
  883|      3|        if (elem.name == name) {
  ------------------
  |  Branch (883:13): [True: 0, False: 3]
  ------------------
  884|      0|            if (!perPoly) {
  ------------------
  |  Branch (884:17): [True: 0, False: 0]
  ------------------
  885|      0|                ASSIMP_LOG_WARN("LWO2: Found two VMAP sections with equal names");
  886|      0|            }
  887|      0|            return &elem;
  888|      0|        }
  889|      3|    }
  890|      6|    list.push_back(T());
  891|      6|    VMapEntry *p = &list.back();
  892|      6|    p->name = name;
  893|      6|    return p;
  894|      6|}
_Z9FindEntryIN6Assimp3LWO13VColorChannelEEPNS1_9VMapEntryERNSt3__16vectorIT_NS5_9allocatorIS7_EEEERKNS5_12basic_stringIcNS5_11char_traitsIcEENS8_IcEEEEb:
  881|      3|VMapEntry *FindEntry(std::vector<T> &list, const std::string &name, bool perPoly) {
  882|      3|    for (auto &elem : list) {
  ------------------
  |  Branch (882:21): [True: 3, False: 2]
  ------------------
  883|      3|        if (elem.name == name) {
  ------------------
  |  Branch (883:13): [True: 1, False: 2]
  ------------------
  884|      1|            if (!perPoly) {
  ------------------
  |  Branch (884:17): [True: 0, False: 1]
  ------------------
  885|      0|                ASSIMP_LOG_WARN("LWO2: Found two VMAP sections with equal names");
  886|      0|            }
  887|      1|            return &elem;
  888|      1|        }
  889|      3|    }
  890|      2|    list.push_back(T());
  891|      2|    VMapEntry *p = &list.back();
  892|      2|    p->name = name;
  893|      2|    return p;
  894|      3|}
_Z14CreateNewEntryIN6Assimp3LWO13VColorChannelEEvRNSt3__16vectorIT_NS3_9allocatorIS5_EEEEj:
  911|    454|inline void CreateNewEntry(std::vector<T> &list, unsigned int srcIdx) {
  912|    460|    for (auto &elem : list) {
  ------------------
  |  Branch (912:21): [True: 460, False: 454]
  ------------------
  913|    460|        CreateNewEntry(elem, srcIdx);
  914|    460|    }
  915|    454|}
_Z14CreateNewEntryIN6Assimp3LWO13VColorChannelEEvRT_j:
  898|    460|inline void CreateNewEntry(T &chan, unsigned int srcIdx) {
  899|    460|    if (!chan.name.length())
  ------------------
  |  Branch (899:9): [True: 0, False: 460]
  ------------------
  900|      0|        return;
  901|       |
  902|    460|    chan.abAssigned[srcIdx] = true;
  903|    460|    chan.abAssigned.resize(chan.abAssigned.size() + 1, false);
  904|       |
  905|  2.30k|    for (unsigned int a = 0; a < chan.dims; ++a)
  ------------------
  |  Branch (905:30): [True: 1.84k, False: 460]
  ------------------
  906|  1.84k|        chan.rawData.push_back(chan.rawData[srcIdx * chan.dims + a]);
  907|    460|}
_Z14CreateNewEntryIN6Assimp3LWO9UVChannelEEvRNSt3__16vectorIT_NS3_9allocatorIS5_EEEEj:
  911|    454|inline void CreateNewEntry(std::vector<T> &list, unsigned int srcIdx) {
  912|    684|    for (auto &elem : list) {
  ------------------
  |  Branch (912:21): [True: 684, False: 454]
  ------------------
  913|    684|        CreateNewEntry(elem, srcIdx);
  914|    684|    }
  915|    454|}
_Z14CreateNewEntryIN6Assimp3LWO9UVChannelEEvRT_j:
  898|    684|inline void CreateNewEntry(T &chan, unsigned int srcIdx) {
  899|    684|    if (!chan.name.length())
  ------------------
  |  Branch (899:9): [True: 0, False: 684]
  ------------------
  900|      0|        return;
  901|       |
  902|    684|    chan.abAssigned[srcIdx] = true;
  903|    684|    chan.abAssigned.resize(chan.abAssigned.size() + 1, false);
  904|       |
  905|  2.05k|    for (unsigned int a = 0; a < chan.dims; ++a)
  ------------------
  |  Branch (905:30): [True: 1.36k, False: 684]
  ------------------
  906|  1.36k|        chan.rawData.push_back(chan.rawData[srcIdx * chan.dims + a]);
  907|    684|}
_Z14CreateNewEntryIN6Assimp3LWO13WeightChannelEEvRNSt3__16vectorIT_NS3_9allocatorIS5_EEEEj:
  911|    908|inline void CreateNewEntry(std::vector<T> &list, unsigned int srcIdx) {
  912|    908|    for (auto &elem : list) {
  ------------------
  |  Branch (912:21): [True: 0, False: 908]
  ------------------
  913|      0|        CreateNewEntry(elem, srcIdx);
  914|      0|    }
  915|    908|}
_Z14CreateNewEntryIN6Assimp3LWO13NormalChannelEEvRT_j:
  898|    454|inline void CreateNewEntry(T &chan, unsigned int srcIdx) {
  899|    454|    if (!chan.name.length())
  ------------------
  |  Branch (899:9): [True: 454, False: 0]
  ------------------
  900|    454|        return;
  901|       |
  902|      0|    chan.abAssigned[srcIdx] = true;
  903|      0|    chan.abAssigned.resize(chan.abAssigned.size() + 1, false);
  904|       |
  905|      0|    for (unsigned int a = 0; a < chan.dims; ++a)
  ------------------
  |  Branch (905:30): [True: 0, False: 0]
  ------------------
  906|      0|        chan.rawData.push_back(chan.rawData[srcIdx * chan.dims + a]);
  907|      0|}

_ZN6Assimp11LWOImporterC2Ev:
   77|    624|    LWOImporter() = default;
_ZN6Assimp11LWOImporter5GetF4Ev:
  405|  18.6k|inline float LWOImporter::GetF4() {
  406|  18.6k|    float f;
  407|  18.6k|    ::memcpy(&f, mFileBuffer, 4);
  408|  18.6k|    mFileBuffer += 4;
  409|       |    AI_LSWAP4(f);
  410|  18.6k|    return f;
  411|  18.6k|}
_ZN6Assimp11LWOImporter5GetU4Ev:
  432|     91|inline uint32_t LWOImporter::GetU4() {
  433|     91|    uint32_t f;
  434|     91|    ::memcpy(&f, mFileBuffer, 4);
  435|     91|    mFileBuffer += 4;
  436|       |    AI_LSWAP4(f);
  437|     91|    return f;
  438|     91|}
_ZN6Assimp11LWOImporter5GetU2Ev:
  441|  2.06k|inline uint16_t LWOImporter::GetU2() {
  442|  2.06k|    uint16_t f;
  443|  2.06k|    ::memcpy(&f, mFileBuffer, 2);
  444|  2.06k|    mFileBuffer += 2;
  445|       |    AI_LSWAP2(f);
  446|  2.06k|    return f;
  447|  2.06k|}
_ZN6Assimp11LWOImporter17ReadVSizedIntLWO2ERPh:
  455|  61.6k|inline int LWOImporter::ReadVSizedIntLWO2(uint8_t *&inout) {
  456|  61.6k|    int i;
  457|  61.6k|    int c = *inout;
  458|  61.6k|    inout++;
  459|  61.6k|    if (c != 0xFF) {
  ------------------
  |  Branch (459:9): [True: 61.6k, False: 11]
  ------------------
  460|  61.6k|        i = c << 8;
  461|  61.6k|        c = *inout;
  462|  61.6k|        inout++;
  463|  61.6k|        i |= c;
  464|  61.6k|    } else {
  465|     11|        c = *inout;
  466|     11|        inout++;
  467|     11|        i = c << 16;
  468|     11|        c = *inout;
  469|     11|        inout++;
  470|     11|        i |= c << 8;
  471|     11|        c = *inout;
  472|     11|        inout++;
  473|     11|        i |= c;
  474|     11|    }
  475|  61.6k|    return i;
  476|  61.6k|}
_ZN6Assimp11LWOImporter5GetS0ERNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEj:
  479|     84|inline void LWOImporter::GetS0(std::string &out, unsigned int max) {
  480|     84|    unsigned int iCursor = 0;
  481|     84|    const char *sz = (const char *)mFileBuffer;
  482|    809|    while (mFileBuffer < mFileBufferEnd && *mFileBuffer) {
  ------------------
  |  Branch (482:12): [True: 809, False: 0]
  |  Branch (482:44): [True: 725, False: 84]
  ------------------
  483|    725|        if (++iCursor > max) {
  ------------------
  |  Branch (483:13): [True: 0, False: 725]
  ------------------
  484|      0|            ASSIMP_LOG_WARN("LWO: Invalid file, string is too long");
  485|      0|            break;
  486|      0|        }
  487|    725|        ++mFileBuffer;
  488|    725|    }
  489|     84|    size_t len = (size_t)((const char *)mFileBuffer - sz);
  490|     84|    out = std::string(sz, len);
  491|       |
  492|     84|    const size_t skip = (len & 0x1 ? 1u : 2u);
  ------------------
  |  Branch (492:26): [True: 37, False: 47]
  ------------------
  493|     84|    const size_t remaining = static_cast<size_t>(mFileBufferEnd - mFileBuffer);
  494|     84|    if (remaining < skip) {
  ------------------
  |  Branch (494:9): [True: 0, False: 84]
  ------------------
  495|      0|        mFileBuffer = mFileBufferEnd;
  496|     84|    } else {
  497|     84|        mFileBuffer += skip;
  498|     84|    }
  499|     84|}
_ZN6Assimp11LWOImporterD2Ev:
   82|    624|    ~LWOImporter() override = default;

_ZN6Assimp11LWOImporter14HandleTexturesEP10aiMaterialRKNSt3__14listINS_3LWO7TextureENS3_9allocatorIS6_EEEE13aiTextureType:
   79|    103|bool LWOImporter::HandleTextures(aiMaterial *pcMat, const TextureList &in, aiTextureType type) {
   80|    103|    ai_assert(nullptr != pcMat);
   81|       |
   82|    103|    unsigned int cur = 0, temp = 0;
   83|    103|    aiString s;
   84|    103|    bool ret = false;
   85|       |
   86|    103|    for (const auto &texture : in) {
  ------------------
  |  Branch (86:30): [True: 2, False: 103]
  ------------------
   87|      2|        if (!texture.enabled || !texture.bCanUse)
  ------------------
  |  Branch (87:13): [True: 0, False: 2]
  |  Branch (87:33): [True: 0, False: 2]
  ------------------
   88|      0|            continue;
   89|      2|        ret = true;
   90|       |
   91|       |        // Convert lightwave's mapping modes to ours. We let them
   92|       |        // as they are, the GenUVcoords step will compute UV
   93|       |        // channels if they're not there.
   94|       |
   95|      2|        aiTextureMapping mapping = aiTextureMapping_OTHER;
   96|      2|        switch (texture.mapMode) {
   97|      0|            case LWO::Texture::Planar:
  ------------------
  |  Branch (97:13): [True: 0, False: 2]
  ------------------
   98|      0|                mapping = aiTextureMapping_PLANE;
   99|      0|                break;
  100|      0|            case LWO::Texture::Cylindrical:
  ------------------
  |  Branch (100:13): [True: 0, False: 2]
  ------------------
  101|      0|                mapping = aiTextureMapping_CYLINDER;
  102|      0|                break;
  103|      0|            case LWO::Texture::Spherical:
  ------------------
  |  Branch (103:13): [True: 0, False: 2]
  ------------------
  104|      0|                mapping = aiTextureMapping_SPHERE;
  105|      0|                break;
  106|      0|            case LWO::Texture::Cubic:
  ------------------
  |  Branch (106:13): [True: 0, False: 2]
  ------------------
  107|      0|                mapping = aiTextureMapping_BOX;
  108|      0|                break;
  109|      0|            case LWO::Texture::FrontProjection:
  ------------------
  |  Branch (109:13): [True: 0, False: 2]
  ------------------
  110|      0|                ASSIMP_LOG_ERROR("LWO2: Unsupported texture mapping: FrontProjection");
  111|      0|                mapping = aiTextureMapping_OTHER;
  112|      0|                break;
  113|      2|            case LWO::Texture::UV: {
  ------------------
  |  Branch (113:13): [True: 2, False: 0]
  ------------------
  114|      2|                if (UINT_MAX == texture.mRealUVIndex) {
  ------------------
  |  Branch (114:21): [True: 0, False: 2]
  ------------------
  115|       |                    // We have no UV index for this texture, so we can't display it
  116|      0|                    continue;
  117|      0|                }
  118|       |
  119|       |                // add the UV source index
  120|      2|                temp = texture.mRealUVIndex;
  121|      2|                pcMat->AddProperty<int>((int *)&temp, 1, AI_MATKEY_UVWSRC(type, cur));
  122|       |
  123|      2|                mapping = aiTextureMapping_UV;
  124|      2|            } break;
  125|      0|            default:
  ------------------
  |  Branch (125:13): [True: 0, False: 2]
  ------------------
  126|      0|                ai_assert(false);
  127|      2|        };
  128|       |
  129|      2|        if (mapping != aiTextureMapping_UV) {
  ------------------
  |  Branch (129:13): [True: 0, False: 2]
  ------------------
  130|       |            // Setup the main axis
  131|      0|            aiVector3D v;
  132|      0|            switch (texture.majorAxis) {
  133|      0|                case Texture::AXIS_X:
  ------------------
  |  Branch (133:17): [True: 0, False: 0]
  ------------------
  134|      0|                    v = aiVector3D(1.0, 0.0, 0.0);
  135|      0|                    break;
  136|      0|                case Texture::AXIS_Y:
  ------------------
  |  Branch (136:17): [True: 0, False: 0]
  ------------------
  137|      0|                    v = aiVector3D(0.0, 1.0, 0.0);
  138|      0|                    break;
  139|      0|                default: // case Texture::AXIS_Z:
  ------------------
  |  Branch (139:17): [True: 0, False: 0]
  ------------------
  140|      0|                    v = aiVector3D(0.0, 0.0, 1.0);
  141|      0|                    break;
  142|      0|            }
  143|       |
  144|      0|            pcMat->AddProperty(&v, 1, AI_MATKEY_TEXMAP_AXIS(type, cur));
  145|       |
  146|       |            // Setup UV scalings for cylindric and spherical projections
  147|      0|            if (mapping == aiTextureMapping_CYLINDER || mapping == aiTextureMapping_SPHERE) {
  ------------------
  |  Branch (147:17): [True: 0, False: 0]
  |  Branch (147:57): [True: 0, False: 0]
  ------------------
  148|      0|                aiUVTransform trafo;
  149|      0|                trafo.mScaling.x = texture.wrapAmountW;
  150|      0|                trafo.mScaling.y = texture.wrapAmountH;
  151|       |
  152|      0|                static_assert(sizeof(aiUVTransform) / sizeof(ai_real) == 5, "sizeof(aiUVTransform)/sizeof(ai_real) == 5");
  153|      0|                pcMat->AddProperty(&trafo, 1, AI_MATKEY_UVTRANSFORM(type, cur));
  154|      0|            }
  155|      0|            ASSIMP_LOG_VERBOSE_DEBUG("LWO2: Setting up non-UV mapping");
  156|      0|        }
  157|       |
  158|       |        // The older LWOB format does not use indirect references to clips.
  159|       |        // The file name of a texture is directly specified in the tex chunk.
  160|      2|        if (mIsLWO2 || mIsLWO3) {
  ------------------
  |  Branch (160:13): [True: 2, False: 0]
  |  Branch (160:24): [True: 0, False: 0]
  ------------------
  161|       |            // find the corresponding clip (take the last one if multiple
  162|       |            // share the same index)
  163|      2|            ClipList::iterator end = mClips.end(), candidate = end;
  164|      2|            temp = texture.mClipIdx;
  165|      4|            for (ClipList::iterator clip = mClips.begin(); clip != end; ++clip) {
  ------------------
  |  Branch (165:60): [True: 2, False: 2]
  ------------------
  166|      2|                if ((*clip).idx == temp) {
  ------------------
  |  Branch (166:21): [True: 2, False: 0]
  ------------------
  167|      2|                    candidate = clip;
  168|      2|                }
  169|      2|            }
  170|      2|            if (candidate == end) {
  ------------------
  |  Branch (170:17): [True: 0, False: 2]
  ------------------
  171|      0|                ASSIMP_LOG_ERROR("LWO2: Clip index is out of bounds");
  172|      0|                temp = 0;
  173|       |
  174|       |                // fixme: apparently some LWO files shipping with Doom3 don't
  175|       |                // have clips at all ... check whether that's true or whether
  176|       |                // it's a bug in the loader.
  177|       |
  178|      0|                s.Set("$texture.png");
  179|       |
  180|       |                //continue;
  181|      2|            } else {
  182|      2|                if (Clip::UNSUPPORTED == (*candidate).type) {
  ------------------
  |  Branch (182:21): [True: 0, False: 2]
  ------------------
  183|      0|                    ASSIMP_LOG_ERROR("LWO2: Clip type is not supported");
  184|      0|                    continue;
  185|      0|                }
  186|      2|                AdjustTexturePath((*candidate).path);
  187|      2|                s.Set((*candidate).path);
  188|       |
  189|       |                // Additional image settings
  190|      2|                int flags = 0;
  191|      2|                if ((*candidate).negate) {
  ------------------
  |  Branch (191:21): [True: 0, False: 2]
  ------------------
  192|      0|                    flags |= aiTextureFlags_Invert;
  193|      0|                }
  194|      2|                pcMat->AddProperty(&flags, 1, AI_MATKEY_TEXFLAGS(type, cur));
  195|      2|            }
  196|      2|        } else {
  197|      0|            std::string ss = texture.mFileName;
  198|      0|            if (!ss.length()) {
  ------------------
  |  Branch (198:17): [True: 0, False: 0]
  ------------------
  199|      0|                ASSIMP_LOG_WARN("LWOB: Empty file name");
  200|      0|                continue;
  201|      0|            }
  202|      0|            AdjustTexturePath(ss);
  203|      0|            s.Set(ss);
  204|      0|        }
  205|      2|        pcMat->AddProperty(&s, AI_MATKEY_TEXTURE(type, cur));
  206|       |
  207|       |        // add the blend factor
  208|      2|        pcMat->AddProperty<float>(&texture.mStrength, 1, AI_MATKEY_TEXBLEND(type, cur));
  209|       |
  210|       |        // add the blend operation
  211|      2|        switch (texture.blendType) {
  212|      2|            case LWO::Texture::Normal:
  ------------------
  |  Branch (212:13): [True: 2, False: 0]
  ------------------
  213|      2|            case LWO::Texture::Multiply:
  ------------------
  |  Branch (213:13): [True: 0, False: 2]
  ------------------
  214|      2|                temp = (unsigned int)aiTextureOp_Multiply;
  215|      2|                break;
  216|       |
  217|      0|            case LWO::Texture::Subtractive:
  ------------------
  |  Branch (217:13): [True: 0, False: 2]
  ------------------
  218|      0|            case LWO::Texture::Difference:
  ------------------
  |  Branch (218:13): [True: 0, False: 2]
  ------------------
  219|      0|                temp = (unsigned int)aiTextureOp_Subtract;
  220|      0|                break;
  221|       |
  222|      0|            case LWO::Texture::Divide:
  ------------------
  |  Branch (222:13): [True: 0, False: 2]
  ------------------
  223|      0|                temp = (unsigned int)aiTextureOp_Divide;
  224|      0|                break;
  225|       |
  226|      0|            case LWO::Texture::Additive:
  ------------------
  |  Branch (226:13): [True: 0, False: 2]
  ------------------
  227|      0|                temp = (unsigned int)aiTextureOp_Add;
  228|      0|                break;
  229|       |
  230|      0|            default:
  ------------------
  |  Branch (230:13): [True: 0, False: 2]
  ------------------
  231|      0|                temp = (unsigned int)aiTextureOp_Multiply;
  232|      0|                ASSIMP_LOG_WARN("LWO2: Unsupported texture blend mode: alpha or displacement");
  233|      2|        }
  234|       |        // Setup texture operation
  235|      2|        pcMat->AddProperty<int>((int *)&temp, 1, AI_MATKEY_TEXOP(type, cur));
  236|       |
  237|       |        // setup the mapping mode
  238|      2|        int mapping_ = static_cast<int>(mapping);
  239|      2|        pcMat->AddProperty<int>(&mapping_, 1, AI_MATKEY_MAPPING(type, cur));
  240|       |
  241|       |        // add the u-wrapping
  242|      2|        temp = (unsigned int)GetMapMode(texture.wrapModeWidth);
  243|      2|        pcMat->AddProperty<int>((int *)&temp, 1, AI_MATKEY_MAPPINGMODE_U(type, cur));
  244|       |
  245|       |        // add the v-wrapping
  246|      2|        temp = (unsigned int)GetMapMode(texture.wrapModeHeight);
  247|      2|        pcMat->AddProperty<int>((int *)&temp, 1, AI_MATKEY_MAPPINGMODE_V(type, cur));
  248|       |
  249|      2|        ++cur;
  250|      2|    }
  251|    103|    return ret;
  252|    103|}
_ZN6Assimp11LWOImporter15ConvertMaterialERKNS_3LWO7SurfaceEP10aiMaterial:
  255|     15|void LWOImporter::ConvertMaterial(const LWO::Surface &surf, aiMaterial *pcMat) {
  256|       |    // copy the name of the surface
  257|     15|    aiString st;
  258|     15|    st.Set(surf.mName);
  259|     15|    pcMat->AddProperty(&st, AI_MATKEY_NAME);
  260|       |
  261|     15|    const int i = surf.bDoubleSided ? 1 : 0;
  ------------------
  |  Branch (261:19): [True: 0, False: 15]
  ------------------
  262|     15|    pcMat->AddProperty(&i, 1, AI_MATKEY_TWOSIDED);
  263|       |
  264|       |    // add the refraction index and the bump intensity
  265|     15|    pcMat->AddProperty(&surf.mIOR, 1, AI_MATKEY_REFRACTI);
  266|     15|    pcMat->AddProperty(&surf.mBumpIntensity, 1, AI_MATKEY_BUMPSCALING);
  267|       |
  268|     15|    aiShadingMode m;
  269|     15|    if (surf.mSpecularValue && surf.mGlossiness) {
  ------------------
  |  Branch (269:9): [True: 1, False: 14]
  |  Branch (269:32): [True: 1, False: 0]
  ------------------
  270|      1|        float fGloss;
  271|      1|        if (mIsLWO2 || mIsLWO3) {
  ------------------
  |  Branch (271:13): [True: 1, False: 0]
  |  Branch (271:24): [True: 0, False: 0]
  ------------------
  272|      1|            fGloss = std::pow(surf.mGlossiness * ai_real(10.0) + ai_real(2.0), ai_real(2.0));
  273|      1|        } else {
  274|      0|            if (16.0 >= surf.mGlossiness)
  ------------------
  |  Branch (274:17): [True: 0, False: 0]
  ------------------
  275|      0|                fGloss = 6.0;
  276|      0|            else if (64.0 >= surf.mGlossiness)
  ------------------
  |  Branch (276:22): [True: 0, False: 0]
  ------------------
  277|      0|                fGloss = 20.0;
  278|      0|            else if (256.0 >= surf.mGlossiness)
  ------------------
  |  Branch (278:22): [True: 0, False: 0]
  ------------------
  279|      0|                fGloss = 50.0;
  280|      0|            else
  281|      0|                fGloss = 80.0;
  282|      0|        }
  283|       |
  284|      1|        pcMat->AddProperty(&surf.mSpecularValue, 1, AI_MATKEY_SHININESS_STRENGTH);
  285|      1|        pcMat->AddProperty(&fGloss, 1, AI_MATKEY_SHININESS);
  286|      1|        m = aiShadingMode_Phong;
  287|      1|    } else
  288|     14|        m = aiShadingMode_Gouraud;
  289|       |
  290|       |    // specular color
  291|     15|    aiColor3D clr = lerp(aiColor3D(1.0, 1.0, 1.0), surf.mColor, surf.mColorHighlights);
  292|     15|    pcMat->AddProperty(&clr, 1, AI_MATKEY_COLOR_SPECULAR);
  293|     15|    pcMat->AddProperty(&surf.mSpecularValue, 1, AI_MATKEY_SHININESS_STRENGTH);
  294|       |
  295|       |    // emissive color
  296|       |    // luminosity is not really the same but it affects the surface in a similar way. Some scaling looks good.
  297|     15|    clr.g = clr.b = clr.r = surf.mLuminosity * ai_real(0.8);
  298|     15|    pcMat->AddProperty<aiColor3D>(&clr, 1, AI_MATKEY_COLOR_EMISSIVE);
  299|       |
  300|       |    // opacity ... either additive or default-blended, please
  301|     15|    if (0.0 != surf.mAdditiveTransparency) {
  ------------------
  |  Branch (301:9): [True: 0, False: 15]
  ------------------
  302|      0|        const int add = aiBlendMode_Additive;
  303|      0|        pcMat->AddProperty(&surf.mAdditiveTransparency, 1, AI_MATKEY_OPACITY);
  304|      0|        pcMat->AddProperty(&add, 1, AI_MATKEY_BLEND_FUNC);
  305|     15|    } else if (10e10f != surf.mTransparency) {
  ------------------
  |  Branch (305:16): [True: 15, False: 0]
  ------------------
  306|     15|        const int def = aiBlendMode_Default;
  307|     15|        const float f = 1.0f - surf.mTransparency;
  308|     15|        pcMat->AddProperty(&f, 1, AI_MATKEY_OPACITY);
  309|     15|        pcMat->AddProperty(&def, 1, AI_MATKEY_BLEND_FUNC);
  310|     15|    }
  311|       |
  312|       |    // ADD TEXTURES to the material
  313|       |    // TODO: find out how we can handle COLOR textures correctly...
  314|     15|    bool b = HandleTextures(pcMat, surf.mColorTextures, aiTextureType_DIFFUSE);
  315|     15|    b = (b || HandleTextures(pcMat, surf.mDiffuseTextures, aiTextureType_DIFFUSE));
  ------------------
  |  Branch (315:10): [True: 2, False: 13]
  |  Branch (315:15): [True: 0, False: 13]
  ------------------
  316|     15|    HandleTextures(pcMat, surf.mSpecularTextures, aiTextureType_SPECULAR);
  317|     15|    HandleTextures(pcMat, surf.mGlossinessTextures, aiTextureType_SHININESS);
  318|     15|    HandleTextures(pcMat, surf.mBumpTextures, aiTextureType_HEIGHT);
  319|     15|    HandleTextures(pcMat, surf.mOpacityTextures, aiTextureType_OPACITY);
  320|     15|    HandleTextures(pcMat, surf.mReflectionTextures, aiTextureType_REFLECTION);
  321|       |
  322|       |    // Now we need to know which shader to use .. iterate through the shader list of
  323|       |    // the surface and  search for a name which we know ...
  324|     15|    for (const auto &shader : surf.mShaders) {
  ------------------
  |  Branch (324:29): [True: 0, False: 15]
  ------------------
  325|      0|        if (shader.functionName == "LW_SuperCelShader" || shader.functionName == "AH_CelShader") {
  ------------------
  |  Branch (325:13): [True: 0, False: 0]
  |  Branch (325:59): [True: 0, False: 0]
  ------------------
  326|      0|            ASSIMP_LOG_INFO("LWO2: Mapping LW_SuperCelShader/AH_CelShader to aiShadingMode_Toon");
  327|       |
  328|      0|            m = aiShadingMode_Toon;
  329|      0|            break;
  330|      0|        } else if (shader.functionName == "LW_RealFresnel" || shader.functionName == "LW_FastFresnel") {
  ------------------
  |  Branch (330:20): [True: 0, False: 0]
  |  Branch (330:63): [True: 0, False: 0]
  ------------------
  331|      0|            ASSIMP_LOG_INFO("LWO2: Mapping LW_RealFresnel/LW_FastFresnel to aiShadingMode_Fresnel");
  332|       |
  333|      0|            m = aiShadingMode_Fresnel;
  334|      0|            break;
  335|      0|        } else {
  336|      0|            ASSIMP_LOG_WARN("LWO2: Unknown surface shader: ", shader.functionName);
  337|      0|        }
  338|      0|    }
  339|     15|    if (surf.mMaximumSmoothAngle <= 0.0)
  ------------------
  |  Branch (339:9): [True: 6, False: 9]
  ------------------
  340|      6|        m = aiShadingMode_Flat;
  341|     15|    int m_ = static_cast<int>(m);
  342|     15|    pcMat->AddProperty(&m_, 1, AI_MATKEY_SHADING_MODEL);
  343|       |
  344|       |    // (the diffuse value is just a scaling factor)
  345|       |    // If a diffuse texture is set, we set this value to 1.0
  346|     15|    clr = (b ? aiColor3D(1.0, 1.0, 1.0) : surf.mColor);
  ------------------
  |  Branch (346:12): [True: 2, False: 13]
  ------------------
  347|     15|    clr.r *= surf.mDiffuseValue;
  348|     15|    clr.g *= surf.mDiffuseValue;
  349|     15|    clr.b *= surf.mDiffuseValue;
  350|       |    pcMat->AddProperty<aiColor3D>(&clr, 1, AI_MATKEY_COLOR_DIFFUSE);
  351|     15|}
_ZN6Assimp11LWOImporter14FindUVChannelsERNSt3__14listINS_3LWO7TextureENS1_9allocatorIS4_EEEERNS3_5LayerERNS3_9UVChannelEj:
  355|     28|        LWO::Layer & /*layer*/, LWO::UVChannel &uv, unsigned int next) {
  356|     28|    char ret = 0;
  357|     28|    for (auto &texture : list) {
  ------------------
  |  Branch (357:24): [True: 3, False: 28]
  ------------------
  358|       |
  359|       |        // Ignore textures with non-UV mappings for the moment.
  360|      3|        if (!texture.enabled || !texture.bCanUse || texture.mapMode != LWO::Texture::UV) {
  ------------------
  |  Branch (360:13): [True: 0, False: 3]
  |  Branch (360:33): [True: 0, False: 3]
  |  Branch (360:53): [True: 0, False: 3]
  ------------------
  361|      0|            continue;
  362|      0|        }
  363|       |
  364|      3|        if (texture.mUVChannelIndex == uv.name) {
  ------------------
  |  Branch (364:13): [True: 2, False: 1]
  ------------------
  365|      2|            ret = 1;
  366|       |
  367|       |            // got it.
  368|      2|            if (texture.mRealUVIndex == UINT_MAX || texture.mRealUVIndex == next) {
  ------------------
  |  Branch (368:17): [True: 2, False: 0]
  |  Branch (368:53): [True: 0, False: 0]
  ------------------
  369|      2|                texture.mRealUVIndex = next;
  370|      2|            } else {
  371|       |                // channel mismatch. need to duplicate the material.
  372|      0|                ASSIMP_LOG_WARN("LWO: Channel mismatch, would need to duplicate surface [design bug]");
  373|       |
  374|       |                // TODO
  375|      0|            }
  376|      2|        }
  377|      3|    }
  378|     28|    return ret;
  379|     28|}
_ZN6Assimp11LWOImporter14FindUVChannelsERNS_3LWO7SurfaceERNSt3__16vectorIjNS4_9allocatorIjEEEERNS1_5LayerEPj:
  384|     18|        unsigned int out[AI_MAX_NUMBER_OF_TEXTURECOORDS]) {
  385|     18|    unsigned int next = 0, extra = 0, num_extra = 0;
  386|       |
  387|       |    // Check whether we have an UV entry != 0 for one of the faces in 'sorted'
  388|     22|    for (unsigned int i = 0; i < layer.mUVChannels.size(); ++i) {
  ------------------
  |  Branch (388:30): [True: 4, False: 18]
  ------------------
  389|      4|        LWO::UVChannel &uv = layer.mUVChannels[i];
  390|       |
  391|      8|        for (LWO::SortedRep::const_iterator it = sorted.begin(); it != sorted.end(); ++it) {
  ------------------
  |  Branch (391:66): [True: 4, False: 4]
  ------------------
  392|       |
  393|      4|            LWO::Face &face = layer.mFaces[*it];
  394|       |
  395|      4|            for (unsigned int n = 0; n < face.mNumIndices; ++n) {
  ------------------
  |  Branch (395:38): [True: 4, False: 0]
  ------------------
  396|      4|                unsigned int idx = face.mIndices[n];
  397|       |
  398|      4|                if (uv.abAssigned[idx] && ((aiVector2D *)&uv.rawData[0])[idx] != aiVector2D()) {
  ------------------
  |  Branch (398:21): [True: 4, False: 0]
  |  Branch (398:21): [True: 4, False: 0]
  |  Branch (398:43): [True: 4, False: 0]
  ------------------
  399|       |
  400|      4|                    if (extra >= AI_MAX_NUMBER_OF_TEXTURECOORDS) {
  ------------------
  |  Branch (400:25): [True: 0, False: 4]
  ------------------
  401|       |
  402|      0|                        ASSIMP_LOG_ERROR("LWO: Maximum number of UV channels for "
  403|      0|                                         "this mesh reached. Skipping channel \'" +
  404|      0|                                         uv.name + "\'");
  405|       |
  406|      4|                    } else {
  407|       |                        // Search through all textures assigned to 'surf' and look for this UV channel
  408|      4|                        char had = 0;
  409|      4|                        had |= FindUVChannels(surf.mColorTextures, layer, uv, next);
  410|      4|                        had |= FindUVChannels(surf.mDiffuseTextures, layer, uv, next);
  411|      4|                        had |= FindUVChannels(surf.mSpecularTextures, layer, uv, next);
  412|      4|                        had |= FindUVChannels(surf.mGlossinessTextures, layer, uv, next);
  413|      4|                        had |= FindUVChannels(surf.mOpacityTextures, layer, uv, next);
  414|      4|                        had |= FindUVChannels(surf.mBumpTextures, layer, uv, next);
  415|      4|                        had |= FindUVChannels(surf.mReflectionTextures, layer, uv, next);
  416|       |
  417|       |                        // We have a texture referencing this UV channel so we have to take special care
  418|       |                        // and are willing to drop unreferenced channels in favour of it.
  419|      4|                        if (had != 0) {
  ------------------
  |  Branch (419:29): [True: 2, False: 2]
  ------------------
  420|      2|                            if (num_extra) {
  ------------------
  |  Branch (420:33): [True: 0, False: 2]
  ------------------
  421|       |
  422|      0|                                for (unsigned int a = next; a < std::min(extra, AI_MAX_NUMBER_OF_TEXTURECOORDS - 1u); ++a) {
  ------------------
  |  Branch (422:61): [True: 0, False: 0]
  ------------------
  423|      0|                                    out[a + 1] = out[a];
  424|      0|                                }
  425|      0|                            }
  426|      2|                            ++extra;
  427|      2|                            out[next++] = i;
  428|      2|                        }
  429|       |                        // Bah ... seems not to be used at all. Push to end if enough space is available.
  430|      2|                        else {
  431|      2|                            out[extra++] = i;
  432|      2|                            ++num_extra;
  433|      2|                        }
  434|      4|                    }
  435|      4|                    it = sorted.end() - 1;
  436|      4|                    break;
  437|      4|                }
  438|      4|            }
  439|      4|        }
  440|      4|    }
  441|     18|    if (extra < AI_MAX_NUMBER_OF_TEXTURECOORDS) {
  ------------------
  |  Branch (441:9): [True: 18, False: 0]
  ------------------
  442|       |        out[extra] = UINT_MAX;
  443|     18|    }
  444|     18|}
_ZN6Assimp11LWOImporter14FindVCChannelsERKNS_3LWO7SurfaceERNSt3__16vectorIjNS5_9allocatorIjEEEERKNS1_5LayerEPj:
  448|     18|        unsigned int out[AI_MAX_NUMBER_OF_COLOR_SETS]) {
  449|     18|    unsigned int next = 0;
  450|       |
  451|       |    // Check whether we have an vc entry != 0 for one of the faces in 'sorted'
  452|     20|    for (unsigned int i = 0; i < layer.mVColorChannels.size(); ++i) {
  ------------------
  |  Branch (452:30): [True: 2, False: 18]
  ------------------
  453|      2|        const LWO::VColorChannel &vc = layer.mVColorChannels[i];
  454|       |
  455|      2|        if (surf.mVCMap == vc.name) {
  ------------------
  |  Branch (455:13): [True: 1, False: 1]
  ------------------
  456|       |            // The vertex color map is explicitly requested by the surface so we need to take special care of it
  457|      1|            for (unsigned int a = 0; a < std::min(next, AI_MAX_NUMBER_OF_COLOR_SETS - 1u); ++a) {
  ------------------
  |  Branch (457:38): [True: 0, False: 1]
  ------------------
  458|      0|                out[a + 1] = out[a];
  459|      0|            }
  460|      1|            out[0] = i;
  461|      1|            ++next;
  462|      1|        } else {
  463|       |
  464|      2|            for (LWO::SortedRep::iterator it = sorted.begin(); it != sorted.end(); ++it) {
  ------------------
  |  Branch (464:64): [True: 1, False: 1]
  ------------------
  465|      1|                const LWO::Face &face = layer.mFaces[*it];
  466|       |
  467|      1|                for (unsigned int n = 0; n < face.mNumIndices; ++n) {
  ------------------
  |  Branch (467:42): [True: 1, False: 0]
  ------------------
  468|      1|                    unsigned int idx = face.mIndices[n];
  469|       |
  470|      1|                    if (vc.abAssigned[idx] && ((aiColor4D *)&vc.rawData[0])[idx] != aiColor4D(0.0, 0.0, 0.0, 1.0)) {
  ------------------
  |  Branch (470:25): [True: 1, False: 0]
  |  Branch (470:25): [True: 1, False: 0]
  |  Branch (470:47): [True: 1, False: 0]
  ------------------
  471|      1|                        if (next >= AI_MAX_NUMBER_OF_COLOR_SETS) {
  ------------------
  |  Branch (471:29): [True: 0, False: 1]
  ------------------
  472|       |
  473|      0|                            ASSIMP_LOG_ERROR("LWO: Maximum number of vertex color channels for "
  474|      0|                                             "this mesh reached. Skipping channel \'" +
  475|      0|                                             vc.name + "\'");
  476|       |
  477|      1|                        } else {
  478|      1|                            out[next++] = i;
  479|      1|                        }
  480|      1|                        it = sorted.end() - 1;
  481|      1|                        break;
  482|      1|                    }
  483|      1|                }
  484|      1|            }
  485|      1|        }
  486|      2|    }
  487|     18|    if (next != AI_MAX_NUMBER_OF_COLOR_SETS) {
  ------------------
  |  Branch (487:9): [True: 18, False: 0]
  ------------------
  488|       |        out[next] = UINT_MAX;
  489|     18|    }
  490|     18|}
_ZN6Assimp11LWOImporter16LoadLWO2ImageMapEjRNS_3LWO7TextureE:
  493|      2|void LWOImporter::LoadLWO2ImageMap(unsigned int size, LWO::Texture &tex) {
  494|      2|    LE_NCONST uint8_t *const end = mFileBuffer + size;
  495|     22|    while (true) {
  ------------------
  |  Branch (495:12): [True: 22, Folded]
  ------------------
  496|     22|        if (mFileBuffer + 6 >= end) break;
  ------------------
  |  Branch (496:13): [True: 2, False: 20]
  ------------------
  497|     20|        LE_NCONST IFF::SubChunkHeader head = IFF::LoadSubChunk(mFileBuffer);
  498|       |
  499|     20|        if (mFileBuffer + head.length > end)
  ------------------
  |  Branch (499:13): [True: 0, False: 20]
  ------------------
  500|      0|            throw DeadlyImportError("LWO2: Invalid SURF.BLOCK chunk length");
  501|       |
  502|     20|        uint8_t *const next = mFileBuffer + head.length;
  503|     20|        switch (head.type) {
  ------------------
  |  Branch (503:17): [True: 14, False: 6]
  ------------------
  504|      2|            case AI_LWO_PROJ:
  ------------------
  |  |  194|      2|#define AI_LWO_PROJ AI_IFF_FOURCC('P', 'R', 'O', 'J')
  |  |  ------------------
  |  |  |  |   50|      2|#define AI_IFF_FOURCC(a,b,c,d) ((uint32_t) (((uint8_t)a << 24u) | \
  |  |  |  |   51|      2|    ((uint8_t)b << 16u) | ((uint8_t)c << 8u) | ((uint8_t)d)))
  |  |  ------------------
  ------------------
  |  Branch (504:13): [True: 2, False: 18]
  ------------------
  505|      2|                tex.mapMode = (Texture::MappingMode)GetU2();
  506|      2|                break;
  507|      2|            case AI_LWO_WRAP:
  ------------------
  |  |  211|      2|#define AI_LWO_WRAP AI_IFF_FOURCC('W', 'R', 'A', 'P')
  |  |  ------------------
  |  |  |  |   50|      2|#define AI_IFF_FOURCC(a,b,c,d) ((uint32_t) (((uint8_t)a << 24u) | \
  |  |  |  |   51|      2|    ((uint8_t)b << 16u) | ((uint8_t)c << 8u) | ((uint8_t)d)))
  |  |  ------------------
  ------------------
  |  Branch (507:13): [True: 2, False: 18]
  ------------------
  508|      2|                tex.wrapModeWidth = (Texture::Wrap)GetU2();
  509|      2|                tex.wrapModeHeight = (Texture::Wrap)GetU2();
  510|      2|                break;
  511|      2|            case AI_LWO_AXIS:
  ------------------
  |  |  200|      2|#define AI_LWO_AXIS AI_IFF_FOURCC('A', 'X', 'I', 'S')
  |  |  ------------------
  |  |  |  |   50|      2|#define AI_IFF_FOURCC(a,b,c,d) ((uint32_t) (((uint8_t)a << 24u) | \
  |  |  |  |   51|      2|    ((uint8_t)b << 16u) | ((uint8_t)c << 8u) | ((uint8_t)d)))
  |  |  ------------------
  ------------------
  |  Branch (511:13): [True: 2, False: 18]
  ------------------
  512|      2|                tex.majorAxis = (Texture::Axes)GetU2();
  513|      2|                break;
  514|      2|            case AI_LWO_IMAG:
  ------------------
  |  |  210|      2|#define AI_LWO_IMAG AI_IFF_FOURCC('I', 'M', 'A', 'G')
  |  |  ------------------
  |  |  |  |   50|      2|#define AI_IFF_FOURCC(a,b,c,d) ((uint32_t) (((uint8_t)a << 24u) | \
  |  |  |  |   51|      2|    ((uint8_t)b << 16u) | ((uint8_t)c << 8u) | ((uint8_t)d)))
  |  |  ------------------
  ------------------
  |  Branch (514:13): [True: 2, False: 18]
  ------------------
  515|      2|                tex.mClipIdx = GetU2();
  516|      2|                break;
  517|      2|            case AI_LWO_VMAP:
  ------------------
  |  |  214|      2|#define AI_LWO_VMAP AI_IFF_FOURCC('V', 'M', 'A', 'P')
  |  |  ------------------
  |  |  |  |   50|      2|#define AI_IFF_FOURCC(a,b,c,d) ((uint32_t) (((uint8_t)a << 24u) | \
  |  |  |  |   51|      2|    ((uint8_t)b << 16u) | ((uint8_t)c << 8u) | ((uint8_t)d)))
  |  |  ------------------
  ------------------
  |  Branch (517:13): [True: 2, False: 18]
  ------------------
  518|      2|                GetS0(tex.mUVChannelIndex, head.length);
  519|      2|                break;
  520|      2|            case AI_LWO_WRPH:
  ------------------
  |  |  213|      2|#define AI_LWO_WRPH AI_IFF_FOURCC('W', 'R', 'P', 'H')
  |  |  ------------------
  |  |  |  |   50|      2|#define AI_IFF_FOURCC(a,b,c,d) ((uint32_t) (((uint8_t)a << 24u) | \
  |  |  |  |   51|      2|    ((uint8_t)b << 16u) | ((uint8_t)c << 8u) | ((uint8_t)d)))
  |  |  ------------------
  ------------------
  |  Branch (520:13): [True: 2, False: 18]
  ------------------
  521|      2|                tex.wrapAmountH = GetF4();
  522|      2|                break;
  523|      2|            case AI_LWO_WRPW:
  ------------------
  |  |  212|      2|#define AI_LWO_WRPW AI_IFF_FOURCC('W', 'R', 'P', 'W')
  |  |  ------------------
  |  |  |  |   50|      2|#define AI_IFF_FOURCC(a,b,c,d) ((uint32_t) (((uint8_t)a << 24u) | \
  |  |  |  |   51|      2|    ((uint8_t)b << 16u) | ((uint8_t)c << 8u) | ((uint8_t)d)))
  |  |  ------------------
  ------------------
  |  Branch (523:13): [True: 2, False: 18]
  ------------------
  524|      2|                tex.wrapAmountW = GetF4();
  525|      2|                break;
  526|     20|        }
  527|     20|        mFileBuffer = next;
  528|     20|    }
  529|      2|}
_ZN6Assimp11LWOImporter21LoadLWO2TextureHeaderEjRNS_3LWO7TextureE:
  546|      2|void LWOImporter::LoadLWO2TextureHeader(unsigned int size, LWO::Texture &tex) {
  547|      2|    LE_NCONST uint8_t *const end = mFileBuffer + size;
  548|       |
  549|       |    // get the ordinal string
  550|      2|    GetS0(tex.ordinal, size);
  551|       |
  552|       |    // we could crash later if this is an empty string ...
  553|      2|    if (!tex.ordinal.length()) {
  ------------------
  |  Branch (553:9): [True: 0, False: 2]
  ------------------
  554|      0|        ASSIMP_LOG_ERROR("LWO2: Ill-formed SURF.BLOK ordinal string");
  555|      0|        tex.ordinal = "\x00";
  556|      0|    }
  557|     10|    while (true) {
  ------------------
  |  Branch (557:12): [True: 10, Folded]
  ------------------
  558|     10|        if (mFileBuffer + 6 >= end) break;
  ------------------
  |  Branch (558:13): [True: 2, False: 8]
  ------------------
  559|      8|        const IFF::SubChunkHeader head = IFF::LoadSubChunk(mFileBuffer);
  560|       |
  561|      8|        if (mFileBuffer + head.length > end)
  ------------------
  |  Branch (561:13): [True: 0, False: 8]
  ------------------
  562|      0|            throw DeadlyImportError("LWO2: Invalid texture header chunk length");
  563|       |
  564|      8|        uint8_t *const next = mFileBuffer + head.length;
  565|      8|        switch (head.type) {
  ------------------
  |  Branch (565:17): [True: 6, False: 2]
  ------------------
  566|      2|            case AI_LWO_CHAN:
  ------------------
  |  |  189|      2|#define AI_LWO_CHAN AI_IFF_FOURCC('C', 'H', 'A', 'N')
  |  |  ------------------
  |  |  |  |   50|      2|#define AI_IFF_FOURCC(a,b,c,d) ((uint32_t) (((uint8_t)a << 24u) | \
  |  |  |  |   51|      2|    ((uint8_t)b << 16u) | ((uint8_t)c << 8u) | ((uint8_t)d)))
  |  |  ------------------
  ------------------
  |  Branch (566:13): [True: 2, False: 6]
  ------------------
  567|      2|                tex.type = GetU4();
  568|      2|                break;
  569|      2|            case AI_LWO_ENAB:
  ------------------
  |  |  191|      2|#define AI_LWO_ENAB AI_IFF_FOURCC('E', 'N', 'A', 'B')
  |  |  ------------------
  |  |  |  |   50|      2|#define AI_IFF_FOURCC(a,b,c,d) ((uint32_t) (((uint8_t)a << 24u) | \
  |  |  |  |   51|      2|    ((uint8_t)b << 16u) | ((uint8_t)c << 8u) | ((uint8_t)d)))
  |  |  ------------------
  ------------------
  |  Branch (569:13): [True: 2, False: 6]
  ------------------
  570|      2|                tex.enabled = GetU2() ? true : false;
  ------------------
  |  Branch (570:31): [True: 2, False: 0]
  ------------------
  571|      2|                break;
  572|      2|            case AI_LWO_OPAC:
  ------------------
  |  |  192|      2|#define AI_LWO_OPAC AI_IFF_FOURCC('O', 'P', 'A', 'C')
  |  |  ------------------
  |  |  |  |   50|      2|#define AI_IFF_FOURCC(a,b,c,d) ((uint32_t) (((uint8_t)a << 24u) | \
  |  |  |  |   51|      2|    ((uint8_t)b << 16u) | ((uint8_t)c << 8u) | ((uint8_t)d)))
  |  |  ------------------
  ------------------
  |  Branch (572:13): [True: 2, False: 6]
  ------------------
  573|      2|                tex.blendType = (Texture::BlendType)GetU2();
  574|      2|                tex.mStrength = GetF4();
  575|      2|                break;
  576|      8|        }
  577|      8|        mFileBuffer = next;
  578|      8|    }
  579|      2|}
_ZN6Assimp11LWOImporter20LoadLWO2TextureBlockEPNS_3IFF14SubChunkHeaderEj:
  582|      2|void LWOImporter::LoadLWO2TextureBlock(LE_NCONST IFF::SubChunkHeader *head, unsigned int size) {
  583|      2|    ai_assert(!mSurfaces->empty());
  584|      2|    LWO::Surface &surf = mSurfaces->back();
  585|      2|    LWO::Texture tex;
  586|       |
  587|       |    // load the texture header
  588|      2|    LoadLWO2TextureHeader(head->length, tex);
  589|      2|    size -= head->length + 6;
  590|       |
  591|       |    // now get the exact type of the texture
  592|      2|    switch (head->type) {
  ------------------
  |  Branch (592:13): [True: 2, False: 0]
  ------------------
  593|      0|        case AI_LWO_PROC:
  ------------------
  |  |  219|      0|#define AI_LWO_PROC AI_IFF_FOURCC('P', 'R', 'O', 'C')
  |  |  ------------------
  |  |  |  |   50|      0|#define AI_IFF_FOURCC(a,b,c,d) ((uint32_t) (((uint8_t)a << 24u) | \
  |  |  |  |   51|      0|    ((uint8_t)b << 16u) | ((uint8_t)c << 8u) | ((uint8_t)d)))
  |  |  ------------------
  ------------------
  |  Branch (593:9): [True: 0, False: 2]
  ------------------
  594|      0|            LoadLWO2Procedural(size, tex);
  595|      0|            break;
  596|      0|        case AI_LWO_GRAD:
  ------------------
  |  |  228|      0|#define AI_LWO_GRAD AI_IFF_FOURCC('G', 'R', 'A', 'D')
  |  |  ------------------
  |  |  |  |   50|      0|#define AI_IFF_FOURCC(a,b,c,d) ((uint32_t) (((uint8_t)a << 24u) | \
  |  |  |  |   51|      0|    ((uint8_t)b << 16u) | ((uint8_t)c << 8u) | ((uint8_t)d)))
  |  |  ------------------
  ------------------
  |  Branch (596:9): [True: 0, False: 2]
  ------------------
  597|      0|            LoadLWO2Gradient(size, tex);
  598|      0|            break;
  599|      2|        case AI_LWO_IMAP:
  ------------------
  |  |  298|      2|#define AI_LWO_IMAP AI_IFF_FOURCC('I', 'M', 'A', 'P')
  |  |  ------------------
  |  |  |  |   50|      2|#define AI_IFF_FOURCC(a,b,c,d) ((uint32_t) (((uint8_t)a << 24u) | \
  |  |  |  |   51|      2|    ((uint8_t)b << 16u) | ((uint8_t)c << 8u) | ((uint8_t)d)))
  |  |  ------------------
  ------------------
  |  Branch (599:9): [True: 2, False: 0]
  ------------------
  600|      2|            LoadLWO2ImageMap(size, tex);
  601|      2|    }
  602|       |
  603|       |    // get the destination channel
  604|      2|    TextureList *listRef = nullptr;
  605|      2|    switch (tex.type) {
  606|      2|        case AI_LWO_COLR:
  ------------------
  |  |  220|      2|#define AI_LWO_COLR AI_IFF_FOURCC('C', 'O', 'L', 'R')
  |  |  ------------------
  |  |  |  |   50|      2|#define AI_IFF_FOURCC(a,b,c,d) ((uint32_t) (((uint8_t)a << 24u) | \
  |  |  |  |   51|      2|    ((uint8_t)b << 16u) | ((uint8_t)c << 8u) | ((uint8_t)d)))
  |  |  ------------------
  ------------------
  |  Branch (606:9): [True: 2, False: 0]
  ------------------
  607|      2|            listRef = &surf.mColorTextures;
  608|      2|            break;
  609|      0|        case AI_LWO_DIFF:
  ------------------
  |  |  160|      0|#define AI_LWO_DIFF AI_IFF_FOURCC('D', 'I', 'F', 'F')
  |  |  ------------------
  |  |  |  |   50|      0|#define AI_IFF_FOURCC(a,b,c,d) ((uint32_t) (((uint8_t)a << 24u) | \
  |  |  |  |   51|      0|    ((uint8_t)b << 16u) | ((uint8_t)c << 8u) | ((uint8_t)d)))
  |  |  ------------------
  ------------------
  |  Branch (609:9): [True: 0, False: 2]
  ------------------
  610|      0|            listRef = &surf.mDiffuseTextures;
  611|      0|            break;
  612|      0|        case AI_LWO_SPEC:
  ------------------
  |  |  161|      0|#define AI_LWO_SPEC AI_IFF_FOURCC('S', 'P', 'E', 'C')
  |  |  ------------------
  |  |  |  |   50|      0|#define AI_IFF_FOURCC(a,b,c,d) ((uint32_t) (((uint8_t)a << 24u) | \
  |  |  |  |   51|      0|    ((uint8_t)b << 16u) | ((uint8_t)c << 8u) | ((uint8_t)d)))
  |  |  ------------------
  ------------------
  |  Branch (612:9): [True: 0, False: 2]
  ------------------
  613|      0|            listRef = &surf.mSpecularTextures;
  614|      0|            break;
  615|      0|        case AI_LWO_GLOS:
  ------------------
  |  |  162|      0|#define AI_LWO_GLOS AI_IFF_FOURCC('G', 'L', 'O', 'S')
  |  |  ------------------
  |  |  |  |   50|      0|#define AI_IFF_FOURCC(a,b,c,d) ((uint32_t) (((uint8_t)a << 24u) | \
  |  |  |  |   51|      0|    ((uint8_t)b << 16u) | ((uint8_t)c << 8u) | ((uint8_t)d)))
  |  |  ------------------
  ------------------
  |  Branch (615:9): [True: 0, False: 2]
  ------------------
  616|      0|            listRef = &surf.mGlossinessTextures;
  617|      0|            break;
  618|      0|        case AI_LWO_BUMP:
  ------------------
  |  |  172|      0|#define AI_LWO_BUMP AI_IFF_FOURCC('B', 'U', 'M', 'P')
  |  |  ------------------
  |  |  |  |   50|      0|#define AI_IFF_FOURCC(a,b,c,d) ((uint32_t) (((uint8_t)a << 24u) | \
  |  |  |  |   51|      0|    ((uint8_t)b << 16u) | ((uint8_t)c << 8u) | ((uint8_t)d)))
  |  |  ------------------
  ------------------
  |  Branch (618:9): [True: 0, False: 2]
  ------------------
  619|      0|            listRef = &surf.mBumpTextures;
  620|      0|            break;
  621|      0|        case AI_LWO_TRAN:
  ------------------
  |  |  167|      0|#define AI_LWO_TRAN AI_IFF_FOURCC('T', 'R', 'A', 'N')
  |  |  ------------------
  |  |  |  |   50|      0|#define AI_IFF_FOURCC(a,b,c,d) ((uint32_t) (((uint8_t)a << 24u) | \
  |  |  |  |   51|      0|    ((uint8_t)b << 16u) | ((uint8_t)c << 8u) | ((uint8_t)d)))
  |  |  ------------------
  ------------------
  |  Branch (621:9): [True: 0, False: 2]
  ------------------
  622|      0|            listRef = &surf.mOpacityTextures;
  623|      0|            break;
  624|      0|        case AI_LWO_REFL:
  ------------------
  |  |  163|      0|#define AI_LWO_REFL AI_IFF_FOURCC('R', 'E', 'F', 'L')
  |  |  ------------------
  |  |  |  |   50|      0|#define AI_IFF_FOURCC(a,b,c,d) ((uint32_t) (((uint8_t)a << 24u) | \
  |  |  |  |   51|      0|    ((uint8_t)b << 16u) | ((uint8_t)c << 8u) | ((uint8_t)d)))
  |  |  ------------------
  ------------------
  |  Branch (624:9): [True: 0, False: 2]
  ------------------
  625|      0|            listRef = &surf.mReflectionTextures;
  626|      0|            break;
  627|      0|        default:
  ------------------
  |  Branch (627:9): [True: 0, False: 2]
  ------------------
  628|      0|            ASSIMP_LOG_WARN("LWO2: Encountered unknown texture type");
  629|      0|            return;
  630|      2|    }
  631|       |
  632|       |    // now attach the texture to the parent surface - sort by ordinal string
  633|      2|    for (TextureList::iterator it = listRef->begin(); it != listRef->end(); ++it) {
  ------------------
  |  Branch (633:55): [True: 0, False: 2]
  ------------------
  634|      0|        if (::strcmp(tex.ordinal.c_str(), (*it).ordinal.c_str()) < 0) {
  ------------------
  |  Branch (634:13): [True: 0, False: 0]
  ------------------
  635|      0|            listRef->insert(it, tex);
  636|      0|            return;
  637|      0|        }
  638|      0|    }
  639|      2|    listRef->push_back(tex);
  640|      2|}
_ZN6Assimp11LWOImporter15LoadLWO2SurfaceEj:
  934|     12|void LWOImporter::LoadLWO2Surface(unsigned int size) {
  935|     12|    LE_NCONST uint8_t *const end = mFileBuffer + size;
  936|       |
  937|     12|    mSurfaces->push_back(LWO::Surface());
  938|     12|    LWO::Surface &surf = mSurfaces->back();
  939|       |
  940|     12|    GetS0(surf.mName, size);
  941|       |
  942|       |    // check whether this surface was derived from any other surface
  943|     12|    std::string derived;
  944|     12|    GetS0(derived, (unsigned int)(end - mFileBuffer));
  945|     12|    if (derived.length()) {
  ------------------
  |  Branch (945:9): [True: 0, False: 12]
  ------------------
  946|       |        // yes, find this surface
  947|      0|        for (SurfaceList::iterator it = mSurfaces->begin(), itEnd = mSurfaces->end() - 1; it != itEnd; ++it) {
  ------------------
  |  Branch (947:91): [True: 0, False: 0]
  ------------------
  948|      0|            if ((*it).mName == derived) {
  ------------------
  |  Branch (948:17): [True: 0, False: 0]
  ------------------
  949|       |                // we have it ...
  950|      0|                surf = *it;
  951|      0|                derived.clear();
  952|      0|                break;
  953|      0|            }
  954|      0|        }
  955|      0|        if (derived.size()) {
  ------------------
  |  Branch (955:13): [True: 0, False: 0]
  ------------------
  956|      0|            ASSIMP_LOG_WARN("LWO2: Unable to find source surface: ", derived);
  957|      0|        }
  958|      0|    }
  959|       |
  960|     88|    while (true) {
  ------------------
  |  Branch (960:12): [True: 88, Folded]
  ------------------
  961|     88|        if (mFileBuffer + 6 >= end)
  ------------------
  |  Branch (961:13): [True: 12, False: 76]
  ------------------
  962|     12|            break;
  963|     76|        const IFF::SubChunkHeader head = IFF::LoadSubChunk(mFileBuffer);
  964|       |
  965|     76|        if (mFileBuffer + head.length > end)
  ------------------
  |  Branch (965:13): [True: 0, False: 76]
  ------------------
  966|      0|            throw DeadlyImportError("LWO2: Invalid surface chunk length");
  967|       |
  968|     76|        uint8_t *const next = mFileBuffer + head.length;
  969|     76|        switch (head.type) {
  ------------------
  |  Branch (969:17): [True: 49, False: 27]
  ------------------
  970|       |                // diffuse color
  971|     12|            case AI_LWO_COLR: {
  ------------------
  |  |  220|     12|#define AI_LWO_COLR AI_IFF_FOURCC('C', 'O', 'L', 'R')
  |  |  ------------------
  |  |  |  |   50|     12|#define AI_IFF_FOURCC(a,b,c,d) ((uint32_t) (((uint8_t)a << 24u) | \
  |  |  |  |   51|     12|    ((uint8_t)b << 16u) | ((uint8_t)c << 8u) | ((uint8_t)d)))
  |  |  ------------------
  ------------------
  |  Branch (971:13): [True: 12, False: 64]
  ------------------
  972|     12|                AI_LWO_VALIDATE_CHUNK_LENGTH(head.length, COLR, 12);
  ------------------
  |  |  631|     12|    if (length < size) {                                              \
  |  |  ------------------
  |  |  |  Branch (631:9): [True: 0, False: 12]
  |  |  ------------------
  |  |  632|      0|        throw DeadlyImportError("LWO: " #name " chunk is too small"); \
  |  |  633|      0|    }
  ------------------
  973|     12|                surf.mColor.r = GetF4();
  974|     12|                surf.mColor.g = GetF4();
  975|     12|                surf.mColor.b = GetF4();
  976|     12|                break;
  977|     12|            }
  978|       |                // diffuse strength ... hopefully
  979|     12|            case AI_LWO_DIFF: {
  ------------------
  |  |  160|     12|#define AI_LWO_DIFF AI_IFF_FOURCC('D', 'I', 'F', 'F')
  |  |  ------------------
  |  |  |  |   50|     12|#define AI_IFF_FOURCC(a,b,c,d) ((uint32_t) (((uint8_t)a << 24u) | \
  |  |  |  |   51|     12|    ((uint8_t)b << 16u) | ((uint8_t)c << 8u) | ((uint8_t)d)))
  |  |  ------------------
  ------------------
  |  Branch (979:13): [True: 12, False: 64]
  ------------------
  980|     12|                AI_LWO_VALIDATE_CHUNK_LENGTH(head.length, DIFF, 4);
  ------------------
  |  |  631|     12|    if (length < size) {                                              \
  |  |  ------------------
  |  |  |  Branch (631:9): [True: 0, False: 12]
  |  |  ------------------
  |  |  632|      0|        throw DeadlyImportError("LWO: " #name " chunk is too small"); \
  |  |  633|      0|    }
  ------------------
  981|     12|                surf.mDiffuseValue = GetF4();
  982|     12|                break;
  983|     12|            }
  984|       |                // specular strength ... hopefully
  985|      7|            case AI_LWO_SPEC: {
  ------------------
  |  |  161|      7|#define AI_LWO_SPEC AI_IFF_FOURCC('S', 'P', 'E', 'C')
  |  |  ------------------
  |  |  |  |   50|      7|#define AI_IFF_FOURCC(a,b,c,d) ((uint32_t) (((uint8_t)a << 24u) | \
  |  |  |  |   51|      7|    ((uint8_t)b << 16u) | ((uint8_t)c << 8u) | ((uint8_t)d)))
  |  |  ------------------
  ------------------
  |  Branch (985:13): [True: 7, False: 69]
  ------------------
  986|      7|                AI_LWO_VALIDATE_CHUNK_LENGTH(head.length, SPEC, 4);
  ------------------
  |  |  631|      7|    if (length < size) {                                              \
  |  |  ------------------
  |  |  |  Branch (631:9): [True: 0, False: 7]
  |  |  ------------------
  |  |  632|      0|        throw DeadlyImportError("LWO: " #name " chunk is too small"); \
  |  |  633|      0|    }
  ------------------
  987|      7|                surf.mSpecularValue = GetF4();
  988|      7|                break;
  989|      7|            }
  990|       |                // transparency
  991|      1|            case AI_LWO_TRAN: {
  ------------------
  |  |  167|      1|#define AI_LWO_TRAN AI_IFF_FOURCC('T', 'R', 'A', 'N')
  |  |  ------------------
  |  |  |  |   50|      1|#define AI_IFF_FOURCC(a,b,c,d) ((uint32_t) (((uint8_t)a << 24u) | \
  |  |  |  |   51|      1|    ((uint8_t)b << 16u) | ((uint8_t)c << 8u) | ((uint8_t)d)))
  |  |  ------------------
  ------------------
  |  Branch (991:13): [True: 1, False: 75]
  ------------------
  992|       |                // transparency explicitly disabled?
  993|      1|                if (surf.mTransparency == 10e10f)
  ------------------
  |  Branch (993:21): [True: 0, False: 1]
  ------------------
  994|      0|                    break;
  995|       |
  996|      1|                AI_LWO_VALIDATE_CHUNK_LENGTH(head.length, TRAN, 4);
  ------------------
  |  |  631|      1|    if (length < size) {                                              \
  |  |  ------------------
  |  |  |  Branch (631:9): [True: 0, False: 1]
  |  |  ------------------
  |  |  632|      0|        throw DeadlyImportError("LWO: " #name " chunk is too small"); \
  |  |  633|      0|    }
  ------------------
  997|      1|                surf.mTransparency = GetF4();
  998|      1|                break;
  999|      1|            }
 1000|       |                // additive transparency
 1001|      0|            case AI_LWO_ADTR: {
  ------------------
  |  |  177|      0|#define AI_LWO_ADTR AI_IFF_FOURCC('A', 'D', 'T', 'R')
  |  |  ------------------
  |  |  |  |   50|      0|#define AI_IFF_FOURCC(a,b,c,d) ((uint32_t) (((uint8_t)a << 24u) | \
  |  |  |  |   51|      0|    ((uint8_t)b << 16u) | ((uint8_t)c << 8u) | ((uint8_t)d)))
  |  |  ------------------
  ------------------
  |  Branch (1001:13): [True: 0, False: 76]
  ------------------
 1002|      0|                AI_LWO_VALIDATE_CHUNK_LENGTH(head.length, ADTR, 4);
  ------------------
  |  |  631|      0|    if (length < size) {                                              \
  |  |  ------------------
  |  |  |  Branch (631:9): [True: 0, False: 0]
  |  |  ------------------
  |  |  632|      0|        throw DeadlyImportError("LWO: " #name " chunk is too small"); \
  |  |  633|      0|    }
  ------------------
 1003|      0|                surf.mAdditiveTransparency = GetF4();
 1004|      0|                break;
 1005|      0|            }
 1006|       |                // wireframe mode
 1007|      0|            case AI_LWO_LINE: {
  ------------------
  |  |  179|      0|#define AI_LWO_LINE AI_IFF_FOURCC('L', 'I', 'N', 'E')
  |  |  ------------------
  |  |  |  |   50|      0|#define AI_IFF_FOURCC(a,b,c,d) ((uint32_t) (((uint8_t)a << 24u) | \
  |  |  |  |   51|      0|    ((uint8_t)b << 16u) | ((uint8_t)c << 8u) | ((uint8_t)d)))
  |  |  ------------------
  ------------------
  |  Branch (1007:13): [True: 0, False: 76]
  ------------------
 1008|      0|                AI_LWO_VALIDATE_CHUNK_LENGTH(head.length, LINE, 2);
  ------------------
  |  |  631|      0|    if (length < size) {                                              \
  |  |  ------------------
  |  |  |  Branch (631:9): [True: 0, False: 0]
  |  |  ------------------
  |  |  632|      0|        throw DeadlyImportError("LWO: " #name " chunk is too small"); \
  |  |  633|      0|    }
  ------------------
 1009|      0|                if (GetU2() & 0x1)
  ------------------
  |  Branch (1009:21): [True: 0, False: 0]
  ------------------
 1010|      0|                    surf.mWireframe = true;
 1011|      0|                break;
 1012|      0|            }
 1013|       |                // glossiness
 1014|      1|            case AI_LWO_GLOS: {
  ------------------
  |  |  162|      1|#define AI_LWO_GLOS AI_IFF_FOURCC('G', 'L', 'O', 'S')
  |  |  ------------------
  |  |  |  |   50|      1|#define AI_IFF_FOURCC(a,b,c,d) ((uint32_t) (((uint8_t)a << 24u) | \
  |  |  |  |   51|      1|    ((uint8_t)b << 16u) | ((uint8_t)c << 8u) | ((uint8_t)d)))
  |  |  ------------------
  ------------------
  |  Branch (1014:13): [True: 1, False: 75]
  ------------------
 1015|      1|                AI_LWO_VALIDATE_CHUNK_LENGTH(head.length, GLOS, 4);
  ------------------
  |  |  631|      1|    if (length < size) {                                              \
  |  |  ------------------
  |  |  |  Branch (631:9): [True: 0, False: 1]
  |  |  ------------------
  |  |  632|      0|        throw DeadlyImportError("LWO: " #name " chunk is too small"); \
  |  |  633|      0|    }
  ------------------
 1016|      1|                surf.mGlossiness = GetF4();
 1017|      1|                break;
 1018|      1|            }
 1019|       |                // bump intensity
 1020|      1|            case AI_LWO_BUMP: {
  ------------------
  |  |  172|      1|#define AI_LWO_BUMP AI_IFF_FOURCC('B', 'U', 'M', 'P')
  |  |  ------------------
  |  |  |  |   50|      1|#define AI_IFF_FOURCC(a,b,c,d) ((uint32_t) (((uint8_t)a << 24u) | \
  |  |  |  |   51|      1|    ((uint8_t)b << 16u) | ((uint8_t)c << 8u) | ((uint8_t)d)))
  |  |  ------------------
  ------------------
  |  Branch (1020:13): [True: 1, False: 75]
  ------------------
 1021|      1|                AI_LWO_VALIDATE_CHUNK_LENGTH(head.length, BUMP, 4);
  ------------------
  |  |  631|      1|    if (length < size) {                                              \
  |  |  ------------------
  |  |  |  Branch (631:9): [True: 0, False: 1]
  |  |  ------------------
  |  |  632|      0|        throw DeadlyImportError("LWO: " #name " chunk is too small"); \
  |  |  633|      0|    }
  ------------------
 1022|      1|                surf.mBumpIntensity = GetF4();
 1023|      1|                break;
 1024|      1|            }
 1025|       |                // color highlights
 1026|      0|            case AI_LWO_CLRH: {
  ------------------
  |  |  175|      0|#define AI_LWO_CLRH AI_IFF_FOURCC('C', 'L', 'R', 'H')
  |  |  ------------------
  |  |  |  |   50|      0|#define AI_IFF_FOURCC(a,b,c,d) ((uint32_t) (((uint8_t)a << 24u) | \
  |  |  |  |   51|      0|    ((uint8_t)b << 16u) | ((uint8_t)c << 8u) | ((uint8_t)d)))
  |  |  ------------------
  ------------------
  |  Branch (1026:13): [True: 0, False: 76]
  ------------------
 1027|      0|                AI_LWO_VALIDATE_CHUNK_LENGTH(head.length, CLRH, 4);
  ------------------
  |  |  631|      0|    if (length < size) {                                              \
  |  |  ------------------
  |  |  |  Branch (631:9): [True: 0, False: 0]
  |  |  ------------------
  |  |  632|      0|        throw DeadlyImportError("LWO: " #name " chunk is too small"); \
  |  |  633|      0|    }
  ------------------
 1028|      0|                surf.mColorHighlights = GetF4();
 1029|      0|                break;
 1030|      0|            }
 1031|       |                // index of refraction
 1032|      1|            case AI_LWO_RIND: {
  ------------------
  |  |  170|      1|#define AI_LWO_RIND AI_IFF_FOURCC('R', 'I', 'N', 'D')
  |  |  ------------------
  |  |  |  |   50|      1|#define AI_IFF_FOURCC(a,b,c,d) ((uint32_t) (((uint8_t)a << 24u) | \
  |  |  |  |   51|      1|    ((uint8_t)b << 16u) | ((uint8_t)c << 8u) | ((uint8_t)d)))
  |  |  ------------------
  ------------------
  |  Branch (1032:13): [True: 1, False: 75]
  ------------------
 1033|      1|                AI_LWO_VALIDATE_CHUNK_LENGTH(head.length, RIND, 4);
  ------------------
  |  |  631|      1|    if (length < size) {                                              \
  |  |  ------------------
  |  |  |  Branch (631:9): [True: 0, False: 1]
  |  |  ------------------
  |  |  632|      0|        throw DeadlyImportError("LWO: " #name " chunk is too small"); \
  |  |  633|      0|    }
  ------------------
 1034|      1|                surf.mIOR = GetF4();
 1035|      1|                break;
 1036|      1|            }
 1037|       |                // polygon sidedness
 1038|      2|            case AI_LWO_SIDE: {
  ------------------
  |  |  174|      2|#define AI_LWO_SIDE AI_IFF_FOURCC('S', 'I', 'D', 'E')
  |  |  ------------------
  |  |  |  |   50|      2|#define AI_IFF_FOURCC(a,b,c,d) ((uint32_t) (((uint8_t)a << 24u) | \
  |  |  |  |   51|      2|    ((uint8_t)b << 16u) | ((uint8_t)c << 8u) | ((uint8_t)d)))
  |  |  ------------------
  ------------------
  |  Branch (1038:13): [True: 2, False: 74]
  ------------------
 1039|      2|                AI_LWO_VALIDATE_CHUNK_LENGTH(head.length, SIDE, 2);
  ------------------
  |  |  631|      2|    if (length < size) {                                              \
  |  |  ------------------
  |  |  |  Branch (631:9): [True: 0, False: 2]
  |  |  ------------------
  |  |  632|      0|        throw DeadlyImportError("LWO: " #name " chunk is too small"); \
  |  |  633|      0|    }
  ------------------
 1040|      2|                surf.bDoubleSided = (3 == GetU2());
 1041|      2|                break;
 1042|      2|            }
 1043|       |                // maximum smoothing angle
 1044|      9|            case AI_LWO_SMAN: {
  ------------------
  |  |  173|      9|#define AI_LWO_SMAN AI_IFF_FOURCC('S', 'M', 'A', 'N')
  |  |  ------------------
  |  |  |  |   50|      9|#define AI_IFF_FOURCC(a,b,c,d) ((uint32_t) (((uint8_t)a << 24u) | \
  |  |  |  |   51|      9|    ((uint8_t)b << 16u) | ((uint8_t)c << 8u) | ((uint8_t)d)))
  |  |  ------------------
  ------------------
  |  Branch (1044:13): [True: 9, False: 67]
  ------------------
 1045|      9|                AI_LWO_VALIDATE_CHUNK_LENGTH(head.length, SMAN, 4);
  ------------------
  |  |  631|      9|    if (length < size) {                                              \
  |  |  ------------------
  |  |  |  Branch (631:9): [True: 0, False: 9]
  |  |  ------------------
  |  |  632|      0|        throw DeadlyImportError("LWO: " #name " chunk is too small"); \
  |  |  633|      0|    }
  ------------------
 1046|      9|                surf.mMaximumSmoothAngle = std::fabs(GetF4());
 1047|      9|                break;
 1048|      9|            }
 1049|       |                // vertex color channel to be applied to the surface
 1050|      1|            case AI_LWO_VCOL: {
  ------------------
  |  |  185|      1|#define AI_LWO_VCOL AI_IFF_FOURCC('V', 'C', 'O', 'L')
  |  |  ------------------
  |  |  |  |   50|      1|#define AI_IFF_FOURCC(a,b,c,d) ((uint32_t) (((uint8_t)a << 24u) | \
  |  |  |  |   51|      1|    ((uint8_t)b << 16u) | ((uint8_t)c << 8u) | ((uint8_t)d)))
  |  |  ------------------
  ------------------
  |  Branch (1050:13): [True: 1, False: 75]
  ------------------
 1051|      1|                AI_LWO_VALIDATE_CHUNK_LENGTH(head.length, VCOL, 12);
  ------------------
  |  |  631|      1|    if (length < size) {                                              \
  |  |  ------------------
  |  |  |  Branch (631:9): [True: 0, False: 1]
  |  |  ------------------
  |  |  632|      0|        throw DeadlyImportError("LWO: " #name " chunk is too small"); \
  |  |  633|      0|    }
  ------------------
 1052|      1|                surf.mDiffuseValue *= GetF4(); // strength
 1053|      1|                ReadVSizedIntLWO2(mFileBuffer); // skip envelope
 1054|      1|                surf.mVCMapType = GetU4(); // type of the channel
 1055|       |
 1056|       |                // name of the channel
 1057|      1|                GetS0(surf.mVCMap, (unsigned int)(next - mFileBuffer));
 1058|      1|                break;
 1059|      1|            }
 1060|       |                // surface bock entry
 1061|      2|            case AI_LWO_BLOK: {
  ------------------
  |  |  184|      2|#define AI_LWO_BLOK AI_IFF_FOURCC('B', 'L', 'O', 'K')
  |  |  ------------------
  |  |  |  |   50|      2|#define AI_IFF_FOURCC(a,b,c,d) ((uint32_t) (((uint8_t)a << 24u) | \
  |  |  |  |   51|      2|    ((uint8_t)b << 16u) | ((uint8_t)c << 8u) | ((uint8_t)d)))
  |  |  ------------------
  ------------------
  |  Branch (1061:13): [True: 2, False: 74]
  ------------------
 1062|      2|                AI_LWO_VALIDATE_CHUNK_LENGTH(head.length, BLOK, 4);
  ------------------
  |  |  631|      2|    if (length < size) {                                              \
  |  |  ------------------
  |  |  |  Branch (631:9): [True: 0, False: 2]
  |  |  ------------------
  |  |  632|      0|        throw DeadlyImportError("LWO: " #name " chunk is too small"); \
  |  |  633|      0|    }
  ------------------
 1063|      2|                IFF::SubChunkHeader head2 = IFF::LoadSubChunk(mFileBuffer);
 1064|       |
 1065|      2|                switch (head2.type) {
 1066|      0|                    case AI_LWO_PROC:
  ------------------
  |  |  219|      0|#define AI_LWO_PROC AI_IFF_FOURCC('P', 'R', 'O', 'C')
  |  |  ------------------
  |  |  |  |   50|      0|#define AI_IFF_FOURCC(a,b,c,d) ((uint32_t) (((uint8_t)a << 24u) | \
  |  |  |  |   51|      0|    ((uint8_t)b << 16u) | ((uint8_t)c << 8u) | ((uint8_t)d)))
  |  |  ------------------
  ------------------
  |  Branch (1066:21): [True: 0, False: 2]
  ------------------
 1067|      0|                    case AI_LWO_GRAD:
  ------------------
  |  |  228|      0|#define AI_LWO_GRAD AI_IFF_FOURCC('G', 'R', 'A', 'D')
  |  |  ------------------
  |  |  |  |   50|      0|#define AI_IFF_FOURCC(a,b,c,d) ((uint32_t) (((uint8_t)a << 24u) | \
  |  |  |  |   51|      0|    ((uint8_t)b << 16u) | ((uint8_t)c << 8u) | ((uint8_t)d)))
  |  |  ------------------
  ------------------
  |  Branch (1067:21): [True: 0, False: 2]
  ------------------
 1068|      2|                    case AI_LWO_IMAP:
  ------------------
  |  |  298|      2|#define AI_LWO_IMAP AI_IFF_FOURCC('I', 'M', 'A', 'P')
  |  |  ------------------
  |  |  |  |   50|      2|#define AI_IFF_FOURCC(a,b,c,d) ((uint32_t) (((uint8_t)a << 24u) | \
  |  |  |  |   51|      2|    ((uint8_t)b << 16u) | ((uint8_t)c << 8u) | ((uint8_t)d)))
  |  |  ------------------
  ------------------
  |  Branch (1068:21): [True: 2, False: 0]
  ------------------
 1069|      2|                        LoadLWO2TextureBlock(&head2, head.length);
 1070|      2|                        break;
 1071|      0|                    case AI_LWO_SHDR:
  ------------------
  |  |  238|      0|#define AI_LWO_SHDR AI_IFF_FOURCC('S', 'H', 'D', 'R')
  |  |  ------------------
  |  |  |  |   50|      0|#define AI_IFF_FOURCC(a,b,c,d) ((uint32_t) (((uint8_t)a << 24u) | \
  |  |  |  |   51|      0|    ((uint8_t)b << 16u) | ((uint8_t)c << 8u) | ((uint8_t)d)))
  |  |  ------------------
  ------------------
  |  Branch (1071:21): [True: 0, False: 2]
  ------------------
 1072|      0|                        LoadLWO2ShaderBlock(&head2, head.length);
 1073|      0|                        break;
 1074|       |
 1075|      0|                    default:
  ------------------
  |  Branch (1075:21): [True: 0, False: 2]
  ------------------
 1076|      0|                        ASSIMP_LOG_WARN("LWO2: Found an unsupported surface BLOK");
 1077|      2|                };
 1078|       |
 1079|      2|                break;
 1080|      2|            }
 1081|     76|        }
 1082|     76|        mFileBuffer = next;
 1083|     76|    }
 1084|     12|}
_Z10GetMapModeN6Assimp3LWO7Texture4WrapE:
   60|      4|inline aiTextureMapMode GetMapMode(LWO::Texture::Wrap in) {
   61|      4|    switch (in) {
  ------------------
  |  Branch (61:13): [True: 4, False: 0]
  ------------------
   62|      4|        case LWO::Texture::REPEAT:
  ------------------
  |  Branch (62:9): [True: 4, False: 0]
  ------------------
   63|      4|            return aiTextureMapMode_Wrap;
   64|       |
   65|      0|        case LWO::Texture::MIRROR:
  ------------------
  |  Branch (65:9): [True: 0, False: 4]
  ------------------
   66|      0|            return aiTextureMapMode_Mirror;
   67|       |
   68|      0|        case LWO::Texture::RESET:
  ------------------
  |  Branch (68:9): [True: 0, False: 4]
  ------------------
   69|      0|            ASSIMP_LOG_WARN("LWO2: Unsupported texture map mode: RESET");
   70|       |
   71|       |            // fall though here
   72|      0|        case LWO::Texture::EDGE:
  ------------------
  |  Branch (72:9): [True: 0, False: 4]
  ------------------
   73|      0|            return aiTextureMapMode_Clamp;
   74|      4|    }
   75|      0|    return (aiTextureMapMode)0;
   76|      4|}
_Z4lerpI9aiColor3DET_RKS1_S3_f:
   54|     15|T lerp(const T &one, const T &two, float val) {
   55|     15|    return one + (two - one) * val;
   56|     15|}

_ZN6Assimp3LWS7Element5ParseERPKcS3_i:
   85|    149|void LWS::Element::Parse(const char *&buffer, const char *end, int depth) {
   86|    149|    if (depth > MAX_DEPTH) {
  ------------------
  |  Branch (86:9): [True: 0, False: 149]
  ------------------
   87|      0|        throw std::runtime_error("Maximum recursion depth exceeded in LWS::Element::Parse");
   88|      0|    }
   89|       |
   90|   157k|    for (; SkipSpacesAndLineEnd(&buffer, end); SkipLine(&buffer, end)) {
  ------------------
  |  Branch (90:12): [True: 157k, False: 149]
  ------------------
   91|       |
   92|       |        // begin of a new element with children
   93|   157k|        bool sub = false;
   94|   157k|        if (*buffer == '{') {
  ------------------
  |  Branch (94:13): [True: 2, False: 157k]
  ------------------
   95|      2|            ++buffer;
   96|      2|            SkipSpaces(&buffer, end);
   97|      2|            sub = true;
   98|   157k|        } else if (*buffer == '}')
  ------------------
  |  Branch (98:20): [True: 0, False: 157k]
  ------------------
   99|      0|            return;
  100|       |
  101|   157k|        children.emplace_back();
  102|       |
  103|       |        // copy data line - read token per token
  104|       |
  105|   157k|        const char *cur = buffer;
  106|  1.74M|        while (!IsSpaceOrNewLine(*buffer))
  ------------------
  |  Branch (106:16): [True: 1.58M, False: 157k]
  ------------------
  107|  1.58M|            ++buffer;
  108|   157k|        children.back().tokens[0] = std::string(cur, (size_t)(buffer - cur));
  109|   157k|        SkipSpaces(&buffer, end);
  110|       |
  111|   157k|        if (children.back().tokens[0] == "Plugin") {
  ------------------
  |  Branch (111:13): [True: 0, False: 157k]
  ------------------
  112|      0|            ASSIMP_LOG_VERBOSE_DEBUG("LWS: Skipping over plugin-specific data");
  113|       |
  114|       |            // strange stuff inside Plugin/Endplugin blocks. Needn't
  115|       |            // follow LWS syntax, so we skip over it
  116|      0|            for (; SkipSpacesAndLineEnd(&buffer, end); SkipLine(&buffer, end)) {
  ------------------
  |  Branch (116:20): [True: 0, False: 0]
  ------------------
  117|      0|                if (!::strncmp(buffer, "EndPlugin", 9)) {
  ------------------
  |  Branch (117:21): [True: 0, False: 0]
  ------------------
  118|      0|                    break;
  119|      0|                }
  120|      0|            }
  121|      0|            continue;
  122|      0|        }
  123|       |
  124|   157k|        cur = buffer;
  125|  1.92M|        while (!IsLineEnd(*buffer)) {
  ------------------
  |  Branch (125:16): [True: 1.76M, False: 157k]
  ------------------
  126|  1.76M|            ++buffer;
  127|  1.76M|        }
  128|   157k|        children.back().tokens[1] = std::string(cur, (size_t)(buffer - cur));
  129|       |
  130|       |        // parse more elements recursively
  131|   157k|        if (sub) {
  ------------------
  |  Branch (131:13): [True: 2, False: 157k]
  ------------------
  132|      2|            children.back().Parse(buffer, end, depth + 1);
  133|      2|        }
  134|   157k|    }
  135|    149|}
_ZN6Assimp11LWSImporterC2Ev:
  145|    624|        noSkeletonMesh() {
  146|       |    // nothing to do here
  147|    624|}
_ZNK6Assimp11LWSImporter7CanReadERKNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEPNS_8IOSystemEb:
  151|    287|bool LWSImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool /*checkSig*/) const {
  152|    287|    static constexpr uint32_t tokens[] = {
  153|    287|        AI_MAKE_MAGIC("LWSC"),
  154|    287|        AI_MAKE_MAGIC("LWMO")
  155|    287|    };
  156|       |    return CheckMagicToken(pIOHandler, pFile, tokens, AI_COUNT_OF(tokens));
  157|    287|}
_ZNK6Assimp11LWSImporter7GetInfoEv:
  161|    781|const aiImporterDesc *LWSImporter::GetInfo() const {
  162|    781|    return &desc;
  163|    781|}
_ZN6Assimp11LWSImporter15SetupPropertiesEPKNS_8ImporterE:
  169|    147|void LWSImporter::SetupProperties(const Importer *pImp) {
  170|       |    // AI_CONFIG_FAVOUR_SPEED
  171|    147|    configSpeedFlag = (0 != pImp->GetPropertyInteger(AI_CONFIG_FAVOUR_SPEED, 0));
  172|       |
  173|       |    // AI_CONFIG_IMPORT_LWS_ANIM_START
  174|    147|    first = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_LWS_ANIM_START,
  175|    147|            MagicHackNo /* magic hack */);
  176|       |
  177|       |    // AI_CONFIG_IMPORT_LWS_ANIM_END
  178|    147|    last = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_LWS_ANIM_END,
  179|    147|            MagicHackNo /* magic hack */);
  180|       |
  181|    147|    if (last < first) {
  ------------------
  |  Branch (181:9): [True: 0, False: 147]
  ------------------
  182|      0|        std::swap(last, first);
  183|      0|    }
  184|       |
  185|       |    noSkeletonMesh = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_NO_SKELETON_MESHES, 0) != 0;
  186|    147|}
_ZN6Assimp11LWSImporter16ReadEnvelope_OldERNSt3__121__list_const_iteratorINS_3LWS7ElementEPvEERKS6_RNS3_8NodeDescEj:
  259|    601|        LWS::NodeDesc &nodes, unsigned int) {
  260|    601|    if (++it == endIt) {
  ------------------
  |  Branch (260:9): [True: 0, False: 601]
  ------------------
  261|      0|        ASSIMP_LOG_ERROR("LWS: Encountered unexpected end of file while parsing object motion");
  262|      0|        return;
  263|      0|    }
  264|       |
  265|    601|    const unsigned int num = strtoul10((*it).tokens[0].c_str());
  266|  1.92k|    for (unsigned int i = 0; i < num; ++i) {
  ------------------
  |  Branch (266:30): [True: 1.32k, False: 601]
  ------------------
  267|  1.32k|        nodes.channels.emplace_back();
  268|  1.32k|        LWO::Envelope &envl = nodes.channels.back();
  269|       |
  270|  1.32k|        envl.index = i;
  271|  1.32k|        envl.type = (LWO::EnvelopeType)(i + 1);
  272|       |
  273|  1.32k|        if (++it == endIt) {
  ------------------
  |  Branch (273:13): [True: 0, False: 1.32k]
  ------------------
  274|      0|            ASSIMP_LOG_ERROR("LWS: Encountered unexpected end of file while parsing object motion");
  275|      0|            return;
  276|      0|        }
  277|       |
  278|  1.32k|        const unsigned int sub_num = strtoul10((*it).tokens[0].c_str());
  279|  1.99k|        for (unsigned int n = 0; n < sub_num; ++n) {
  ------------------
  |  Branch (279:34): [True: 675, False: 1.32k]
  ------------------
  280|    675|            if (++it == endIt) {
  ------------------
  |  Branch (280:17): [True: 0, False: 675]
  ------------------
  281|      0|                ASSIMP_LOG_ERROR("LWS: Encountered unexpected end of file while parsing object motion");
  282|      0|                return;
  283|      0|            }
  284|       |
  285|       |            // parse value and time, skip the rest for the moment.
  286|    675|            LWO::Key key;
  287|    675|            const char *c = fast_atoreal_move((*it).tokens[0].c_str(), key.value);
  288|    675|            const char *end = c + (*it).tokens[0].size();
  289|    675|            SkipSpaces(&c, end);
  290|    675|            float f;
  291|    675|            fast_atoreal_move((*it).tokens[0].c_str(), f);
  292|    675|            key.time = f;
  293|       |
  294|    675|            envl.keys.emplace_back(key);
  295|    675|        }
  296|  1.32k|    }
  297|    601|}
_ZN6Assimp11LWSImporter13SetupNodeNameEP6aiNodeRNS_3LWS8NodeDescE:
  301|  22.0k|void LWSImporter::SetupNodeName(aiNode *nd, LWS::NodeDesc &src) {
  302|  22.0k|    const unsigned int combined = src.number | ((unsigned int)src.type) << 28u;
  303|       |
  304|       |    // the name depends on the type. We break LWS's strange naming convention
  305|       |    // and return human-readable, but still machine-parsable and unique, strings.
  306|  22.0k|    if (src.type == LWS::NodeDesc::OBJECT) {
  ------------------
  |  Branch (306:9): [True: 22.0k, False: 14]
  ------------------
  307|  22.0k|        if (src.path.length()) {
  ------------------
  |  Branch (307:13): [True: 22.0k, False: 4]
  ------------------
  308|  22.0k|            std::string::size_type s = src.path.find_last_of("\\/");
  309|  22.0k|            if (s == std::string::npos) {
  ------------------
  |  Branch (309:17): [True: 15.2k, False: 6.79k]
  ------------------
  310|  15.2k|                s = 0;
  311|  15.2k|            } else {
  312|  6.79k|                ++s;
  313|  6.79k|            }
  314|  22.0k|            std::string::size_type t = src.path.substr(s).find_last_of('.');
  315|       |
  316|  22.0k|            nd->mName.length = ::ai_snprintf(nd->mName.data, AI_MAXLEN, "%s_(%08X)", src.path.substr(s).substr(0, t).c_str(), combined);
  317|  22.0k|            if (nd->mName.length > AI_MAXLEN) {
  ------------------
  |  Branch (317:17): [True: 4, False: 22.0k]
  ------------------
  318|      4|                nd->mName.length = AI_MAXLEN;
  319|      4|            }
  320|  22.0k|            return;
  321|  22.0k|        }
  322|  22.0k|    }
  323|     18|    nd->mName.length = ::ai_snprintf(nd->mName.data, AI_MAXLEN, "%s_(%08X)", src.name, combined);
  324|     18|}
_ZN6Assimp11LWSImporter10BuildGraphEP6aiNodeRNS_3LWS8NodeDescERNSt3__16vectorINS_14AttachmentInfoENS6_9allocatorIS8_EEEERNS_11BatchLoaderERPP8aiCameraRPP7aiLightRNS7_IP10aiNodeAnimNS9_ISO_EEEE:
  332|  11.0k|        std::vector<aiNodeAnim *> &animOut) {
  333|       |    // Setup a very cryptic name for the node, we want the user to be happy
  334|  11.0k|    SetupNodeName(nd, src);
  335|  11.0k|    aiNode *ndAnim = nd;
  336|       |
  337|       |    // If the node is an object
  338|  11.0k|    if (src.type == LWS::NodeDesc::OBJECT) {
  ------------------
  |  Branch (338:9): [True: 11.0k, False: 14]
  ------------------
  339|       |
  340|       |        // If the object is from an external file, get it
  341|  11.0k|        aiScene *obj = nullptr;
  342|  11.0k|        if (src.path.length()) {
  ------------------
  |  Branch (342:13): [True: 11.0k, False: 2]
  ------------------
  343|  11.0k|            obj = batch.GetImport(src.id);
  344|  11.0k|            if (!obj) {
  ------------------
  |  Branch (344:17): [True: 10.4k, False: 555]
  ------------------
  345|  10.4k|                ASSIMP_LOG_ERROR("LWS: Failed to read external file ", src.path);
  346|  10.4k|            } else {
  347|    555|                if (obj->mRootNode->mNumChildren == 1) {
  ------------------
  |  Branch (347:21): [True: 0, False: 555]
  ------------------
  348|       |
  349|       |                    //If the pivot is not set for this layer, get it from the external object
  350|      0|                    if (!src.isPivotSet) {
  ------------------
  |  Branch (350:25): [True: 0, False: 0]
  ------------------
  351|      0|                        src.pivotPos.x = +obj->mRootNode->mTransformation.a4;
  352|      0|                        src.pivotPos.y = +obj->mRootNode->mTransformation.b4;
  353|      0|                        src.pivotPos.z = -obj->mRootNode->mTransformation.c4; //The sign is the RH to LH back conversion
  354|      0|                    }
  355|       |
  356|       |                    //Remove first node from obj (the old pivot), reset transform of second node (the mesh node)
  357|      0|                    aiNode *newRootNode = obj->mRootNode->mChildren[0];
  358|      0|                    obj->mRootNode->mChildren[0] = nullptr;
  359|      0|                    delete obj->mRootNode;
  360|       |
  361|      0|                    obj->mRootNode = newRootNode;
  362|      0|                    obj->mRootNode->mTransformation.a4 = 0.0;
  363|      0|                    obj->mRootNode->mTransformation.b4 = 0.0;
  364|      0|                    obj->mRootNode->mTransformation.c4 = 0.0;
  365|      0|                }
  366|    555|            }
  367|  11.0k|        }
  368|       |
  369|       |        //Setup the pivot node (also the animation node), the one we received
  370|  11.0k|        nd->mName = std::string("Pivot:") + nd->mName.data;
  371|  11.0k|        ndAnim = nd;
  372|       |
  373|       |        //Add the attachment node to it
  374|  11.0k|        nd->mNumChildren = 1;
  375|  11.0k|        nd->mChildren = new aiNode *[1];
  376|  11.0k|        nd->mChildren[0] = new aiNode();
  377|  11.0k|        nd->mChildren[0]->mParent = nd;
  378|  11.0k|        nd->mChildren[0]->mTransformation.a4 = -src.pivotPos.x;
  379|  11.0k|        nd->mChildren[0]->mTransformation.b4 = -src.pivotPos.y;
  380|  11.0k|        nd->mChildren[0]->mTransformation.c4 = -src.pivotPos.z;
  381|  11.0k|        SetupNodeName(nd->mChildren[0], src);
  382|       |
  383|       |        //Update the attachment node
  384|  11.0k|        nd = nd->mChildren[0];
  385|       |
  386|       |        //Push attachment, if the object came from an external file
  387|  11.0k|        if (obj) {
  ------------------
  |  Branch (387:13): [True: 555, False: 10.4k]
  ------------------
  388|    555|            attach.emplace_back(obj, nd);
  389|    555|        }
  390|  11.0k|    }
  391|       |
  392|       |    // If object is a light source - setup a corresponding ai structure
  393|     14|    else if (src.type == LWS::NodeDesc::LIGHT) {
  ------------------
  |  Branch (393:14): [True: 6, False: 8]
  ------------------
  394|      6|        aiLight *lit = *lightOut++ = new aiLight();
  395|       |
  396|       |        // compute final light color
  397|      6|        lit->mColorDiffuse = lit->mColorSpecular = src.lightColor * src.lightIntensity;
  398|       |
  399|       |        // name to attach light to node -> unique due to LWs indexing system
  400|      6|        lit->mName = nd->mName;
  401|       |
  402|       |        // determine light type and setup additional members
  403|      6|        if (src.lightType == 2) { /* spot light */
  ------------------
  |  Branch (403:13): [True: 0, False: 6]
  ------------------
  404|       |
  405|      0|            lit->mType = aiLightSource_SPOT;
  406|      0|            lit->mAngleInnerCone = (float)AI_DEG_TO_RAD(src.lightConeAngle);
  407|      0|            lit->mAngleOuterCone = lit->mAngleInnerCone + (float)AI_DEG_TO_RAD(src.lightEdgeAngle);
  408|       |
  409|      6|        } else if (src.lightType == 1) { /* directional light source */
  ------------------
  |  Branch (409:20): [True: 0, False: 6]
  ------------------
  410|      0|            lit->mType = aiLightSource_DIRECTIONAL;
  411|      6|        } else {
  412|      6|            lit->mType = aiLightSource_POINT;
  413|      6|        }
  414|       |
  415|       |        // fixme: no proper handling of light falloffs yet
  416|      6|        if (src.lightFalloffType == 1) {
  ------------------
  |  Branch (416:13): [True: 0, False: 6]
  ------------------
  417|      0|            lit->mAttenuationConstant = 1.f;
  418|      6|        } else if (src.lightFalloffType == 2) {
  ------------------
  |  Branch (418:20): [True: 0, False: 6]
  ------------------
  419|      0|            lit->mAttenuationLinear = 1.f;
  420|      6|        } else {
  421|      6|            lit->mAttenuationQuadratic = 1.f;
  422|      6|        }
  423|      8|    } else if (src.type == LWS::NodeDesc::CAMERA) { // If object is a camera - setup a corresponding ai structure
  ------------------
  |  Branch (423:16): [True: 8, False: 0]
  ------------------
  424|      8|        aiCamera *cam = *camOut++ = new aiCamera();
  425|       |
  426|       |        // name to attach cam to node -> unique due to LWs indexing system
  427|      8|        cam->mName = nd->mName;
  428|      8|    }
  429|       |
  430|       |    // Get the node transformation from the LWO key
  431|  11.0k|    LWO::AnimResolver resolver(src.channels, fps);
  432|  11.0k|    resolver.ExtractBindPose(ndAnim->mTransformation);
  433|       |
  434|       |    // .. and construct animation channels
  435|  11.0k|    aiNodeAnim *anim = nullptr;
  436|       |
  437|  11.0k|    if (first != last) {
  ------------------
  |  Branch (437:9): [True: 11.0k, False: 0]
  ------------------
  438|  11.0k|        resolver.SetAnimationRange(first, last);
  439|  11.0k|        resolver.ExtractAnimChannel(&anim, AI_LWO_ANIM_FLAG_SAMPLE_ANIMS | AI_LWO_ANIM_FLAG_START_AT_ZERO);
  ------------------
  |  |  177|  11.0k|#define AI_LWO_ANIM_FLAG_SAMPLE_ANIMS 0x1
  ------------------
                      resolver.ExtractAnimChannel(&anim, AI_LWO_ANIM_FLAG_SAMPLE_ANIMS | AI_LWO_ANIM_FLAG_START_AT_ZERO);
  ------------------
  |  |  183|  11.0k|#define AI_LWO_ANIM_FLAG_START_AT_ZERO 0x2
  ------------------
  440|  11.0k|        if (anim) {
  ------------------
  |  Branch (440:13): [True: 279, False: 10.7k]
  ------------------
  441|    279|            anim->mNodeName = ndAnim->mName;
  442|    279|            animOut.push_back(anim);
  443|    279|        }
  444|  11.0k|    }
  445|       |
  446|       |    // Add children
  447|  11.0k|    if (!src.children.empty()) {
  ------------------
  |  Branch (447:9): [True: 9, False: 11.0k]
  ------------------
  448|      9|        nd->mChildren = new aiNode *[src.children.size()];
  449|     20|        for (std::list<LWS::NodeDesc *>::iterator it = src.children.begin(); it != src.children.end(); ++it) {
  ------------------
  |  Branch (449:78): [True: 11, False: 9]
  ------------------
  450|     11|            aiNode *ndd = nd->mChildren[nd->mNumChildren++] = new aiNode();
  451|     11|            ndd->mParent = nd;
  452|       |
  453|     11|            BuildGraph(ndd, **it, attach, batch, camOut, lightOut, animOut);
  454|     11|        }
  455|      9|    }
  456|  11.0k|}
_ZN6Assimp11LWSImporter11FindLWOFileERKNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEE:
  460|  17.7k|std::string LWSImporter::FindLWOFile(const std::string &in) {
  461|       |    // insert missing directory separator if necessary
  462|  17.7k|    std::string tmp(in);
  463|  17.7k|    if (in.length() > 3 && in[1] == ':' && in[2] != '\\' && in[2] != '/') {
  ------------------
  |  Branch (463:9): [True: 15.1k, False: 2.56k]
  |  Branch (463:28): [True: 2.29k, False: 12.8k]
  |  Branch (463:44): [True: 2.29k, False: 0]
  |  Branch (463:61): [True: 1, False: 2.29k]
  ------------------
  464|      1|        tmp = in[0] + (std::string(":\\") + in.substr(2));
  465|      1|    }
  466|       |
  467|  17.7k|    if (io->Exists(tmp)) {
  ------------------
  |  Branch (467:9): [True: 5.91k, False: 11.8k]
  ------------------
  468|  5.91k|        return in;
  469|  5.91k|    }
  470|       |
  471|       |    // file is not accessible for us ... maybe it's packed by
  472|       |    // LightWave's 'Package Scene' command?
  473|       |
  474|       |    // Relevant for us are the following two directories:
  475|       |    // <folder>\Objects\<hh>\<*>.lwo
  476|       |    // <folder>\Scenes\<hh>\<*>.lws
  477|       |    // where <hh> is optional.
  478|       |
  479|  11.8k|    std::string test = std::string("..") + (io->getOsSeparator() + tmp);
  480|  11.8k|    if (io->Exists(test)) {
  ------------------
  |  Branch (480:9): [True: 824, False: 11.0k]
  ------------------
  481|    824|        return test;
  482|    824|    }
  483|       |
  484|  11.0k|    test = std::string("..") + (io->getOsSeparator() + test);
  485|  11.0k|    if (io->Exists(test)) {
  ------------------
  |  Branch (485:9): [True: 0, False: 11.0k]
  ------------------
  486|      0|        return test;
  487|      0|    }
  488|       |
  489|       |    // return original path, maybe the IOsystem knows better
  490|  11.0k|    return tmp;
  491|  11.0k|}
_ZN6Assimp11LWSImporter14InternReadFileERKNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEP7aiScenePNS_8IOSystemE:
  495|    147|void LWSImporter::InternReadFile(const std::string &pFile, aiScene *pScene, IOSystem *pIOHandler) {
  496|    147|    io = pIOHandler;
  497|    147|    std::unique_ptr<IOStream> file(pIOHandler->Open(pFile, "rb"));
  498|       |
  499|       |    // Check whether we can read from the file
  500|    147|    if (file == nullptr) {
  ------------------
  |  Branch (500:9): [True: 0, False: 147]
  ------------------
  501|      0|        throw DeadlyImportError("Failed to open LWS file ", pFile, ".");
  502|      0|    }
  503|       |
  504|       |    // Allocate storage and copy the contents of the file to a memory buffer
  505|    147|    std::vector<char> mBuffer;
  506|    147|    TextFileToBuffer(file.get(), mBuffer);
  507|       |
  508|       |    // Parse the file structure
  509|    147|    LWS::Element root;
  510|    147|    const char *dummy = &mBuffer[0];
  511|    147|    const char *dummyEnd = dummy + mBuffer.size();
  512|    147|    root.Parse(dummy, dummyEnd);
  513|       |
  514|       |    // Construct a Batch-importer to read more files recursively
  515|    147|    BatchLoader batch(pIOHandler);
  516|       |
  517|       |    // Construct an array to receive the flat output graph
  518|    147|    std::list<LWS::NodeDesc> nodes;
  519|       |
  520|    147|    unsigned int cur_light = 0, cur_camera = 0, cur_object = 0;
  521|    147|    unsigned int num_light = 0, num_camera = 0;
  522|       |
  523|       |    // check magic identifier, 'LWSC'
  524|    147|    bool motion_file = false;
  525|    147|    std::list<LWS::Element>::const_iterator it = root.children.begin();
  526|       |
  527|    147|    if ((*it).tokens[0] == "LWMO") {
  ------------------
  |  Branch (527:9): [True: 145, False: 2]
  ------------------
  528|    145|        motion_file = true;
  529|    145|    }
  530|       |
  531|    147|    if ((*it).tokens[0] != "LWSC" && !motion_file) {
  ------------------
  |  Branch (531:9): [True: 145, False: 2]
  |  Branch (531:38): [True: 0, False: 145]
  ------------------
  532|      0|        throw DeadlyImportError("LWS: Not a LightWave scene, magic tag LWSC not found");
  533|      0|    }
  534|       |
  535|       |    // get file format version and print to log
  536|    147|    ++it;
  537|       |
  538|    147|    if (it == root.children.end() || (*it).tokens[0].empty()) {
  ------------------
  |  Branch (538:9): [True: 0, False: 147]
  |  Branch (538:9): [True: 0, False: 147]
  |  Branch (538:38): [True: 0, False: 147]
  ------------------
  539|      0|        ASSIMP_LOG_ERROR("Invalid LWS file detectedm abort import.");
  540|      0|        return;
  541|      0|    }
  542|    147|    unsigned int version = strtoul10((*it).tokens[0].c_str());
  543|    147|    ASSIMP_LOG_INFO("LWS file format version is ", (*it).tokens[0]);
  544|    147|    first = 0.;
  545|    147|    last = 60.;
  546|    147|    fps = 25.; // seems to be a good default frame rate
  547|       |
  548|       |    // Now read all elements in a very straightforward manner
  549|  90.1k|    for (; it != root.children.end(); ++it) {
  ------------------
  |  Branch (549:12): [True: 90.1k, False: 44]
  ------------------
  550|  90.1k|        const char *c = (*it).tokens[1].c_str();
  551|  90.1k|        const char *end = c + (*it).tokens[1].size();
  552|       |
  553|       |        // 'FirstFrame': begin of animation slice
  554|  90.1k|        if ((*it).tokens[0] == "FirstFrame") {
  ------------------
  |  Branch (554:13): [True: 0, False: 90.1k]
  ------------------
  555|       |            // see SetupProperties()
  556|      0|            if (150392. != first ) {
  ------------------
  |  Branch (556:17): [True: 0, False: 0]
  ------------------
  557|      0|                first = strtoul10(c, &c) - 1.; // we're zero-based
  558|      0|            }
  559|  90.1k|        } else if ((*it).tokens[0] == "LastFrame") { // 'LastFrame': end of animation slice
  ------------------
  |  Branch (559:20): [True: 0, False: 90.1k]
  ------------------
  560|       |            // see SetupProperties()
  561|      0|            if (150392. != last ) {
  ------------------
  |  Branch (561:17): [True: 0, False: 0]
  ------------------
  562|      0|                last = strtoul10(c, &c) - 1.; // we're zero-based
  563|      0|            }
  564|  90.1k|        } else if ((*it).tokens[0] == "FramesPerSecond") { // 'FramesPerSecond': frames per second
  ------------------
  |  Branch (564:20): [True: 0, False: 90.1k]
  ------------------
  565|      0|            fps = strtoul10(c, &c);
  566|  90.1k|        } else if ((*it).tokens[0] == "LoadObjectLayer") { // 'LoadObjectLayer': load a layer of a specific LWO file
  ------------------
  |  Branch (566:20): [True: 5.06k, False: 85.0k]
  ------------------
  567|       |
  568|       |            // get layer index
  569|  5.06k|            const int layer = strtoul10(c, &c);
  570|       |
  571|       |            // setup the layer to be loaded
  572|  5.06k|            BatchLoader::PropertyMap props;
  573|  5.06k|            SetGenericProperty(props.ints, AI_CONFIG_IMPORT_LWO_ONE_LAYER_ONLY, layer);
  574|       |
  575|       |            // add node to list
  576|  5.06k|            LWS::NodeDesc d;
  577|  5.06k|            d.type = LWS::NodeDesc::OBJECT;
  578|  5.06k|            if (version >= 4) { // handle LWSC 4 explicit ID
  ------------------
  |  Branch (578:17): [True: 0, False: 5.06k]
  ------------------
  579|      0|                SkipSpaces(&c, end);
  580|      0|                d.number = strtoul16(c, &c) & AI_LWS_MASK;
  ------------------
  |  |   82|      0|#define AI_LWS_MASK (0xffffffff >> 4u)
  ------------------
  581|  5.06k|            } else {
  582|  5.06k|                d.number = cur_object++;
  583|  5.06k|            }
  584|       |
  585|       |            // and add the file to the import list
  586|  5.06k|            SkipSpaces(&c, end);
  587|  5.06k|            std::string path = FindLWOFile(c);
  588|       |
  589|  5.06k|            if (path.empty()) {
  ------------------
  |  Branch (589:17): [True: 0, False: 5.06k]
  ------------------
  590|      0|                throw DeadlyImportError("LWS: Invalid LoadObjectLayer: empty path.");
  591|      0|            }
  592|       |
  593|  5.06k|            if (path == pFile) {
  ------------------
  |  Branch (593:17): [True: 43, False: 5.01k]
  ------------------
  594|     43|                throw DeadlyImportError("LWS: Invalid LoadObjectLayer: self reference.");
  595|     43|            }
  596|       |
  597|  5.01k|            d.path = path;
  598|  5.01k|            d.id = batch.AddLoadRequest(path, 0, &props);
  599|       |
  600|  5.01k|            nodes.push_back(d);
  601|  85.0k|        } else if ((*it).tokens[0] == "LoadObject") { // 'LoadObject': load a LWO file into the scene-graph
  ------------------
  |  Branch (601:20): [True: 12.6k, False: 72.4k]
  ------------------
  602|       |
  603|       |            // add node to list
  604|  12.6k|            LWS::NodeDesc d;
  605|  12.6k|            d.type = LWS::NodeDesc::OBJECT;
  606|       |
  607|  12.6k|            if (version >= 4) { // handle LWSC 4 explicit ID
  ------------------
  |  Branch (607:17): [True: 3, False: 12.6k]
  ------------------
  608|      3|                d.number = strtoul16(c, &c) & AI_LWS_MASK;
  ------------------
  |  |   82|      3|#define AI_LWS_MASK (0xffffffff >> 4u)
  ------------------
  609|      3|                SkipSpaces(&c, end);
  610|  12.6k|            } else {
  611|  12.6k|                d.number = cur_object++;
  612|  12.6k|            }
  613|  12.6k|            std::string path = FindLWOFile(c);
  614|       |
  615|  12.6k|            if (path.empty()) {
  ------------------
  |  Branch (615:17): [True: 0, False: 12.6k]
  ------------------
  616|      0|                throw DeadlyImportError("LWS: Invalid LoadObject: empty path.");
  617|      0|            }
  618|       |
  619|  12.6k|            if (path == pFile) {
  ------------------
  |  Branch (619:17): [True: 60, False: 12.6k]
  ------------------
  620|     60|                throw DeadlyImportError("LWS: Invalid LoadObject: self reference.");
  621|     60|            }
  622|       |
  623|  12.6k|            d.id = batch.AddLoadRequest(path, 0, nullptr);
  624|       |
  625|  12.6k|            d.path = path;
  626|  12.6k|            nodes.push_back(d);
  627|  72.4k|        } else if ((*it).tokens[0] == "AddNullObject") { // 'AddNullObject': add a dummy node to the hierarchy
  ------------------
  |  Branch (627:20): [True: 0, False: 72.4k]
  ------------------
  628|       |
  629|       |            // add node to list
  630|      0|            LWS::NodeDesc d;
  631|      0|            d.type = LWS::NodeDesc::OBJECT;
  632|      0|            if (version >= 4) { // handle LWSC 4 explicit ID
  ------------------
  |  Branch (632:17): [True: 0, False: 0]
  ------------------
  633|      0|                d.number = strtoul16(c, &c) & AI_LWS_MASK;
  ------------------
  |  |   82|      0|#define AI_LWS_MASK (0xffffffff >> 4u)
  ------------------
  634|      0|                SkipSpaces(&c, end);
  635|      0|            } else {
  636|      0|                d.number = cur_object++;
  637|      0|            }
  638|      0|            d.name = c;
  639|      0|            nodes.push_back(d);
  640|      0|        }
  641|       |        // 'NumChannels': Number of envelope channels assigned to last layer
  642|  72.4k|        else if ((*it).tokens[0] == "NumChannels") {
  ------------------
  |  Branch (642:18): [True: 0, False: 72.4k]
  ------------------
  643|       |            // ignore for now
  644|      0|        }
  645|       |        // 'Channel': preceedes any envelope description
  646|  72.4k|        else if ((*it).tokens[0] == "Channel") {
  ------------------
  |  Branch (646:18): [True: 162, False: 72.2k]
  ------------------
  647|    162|            if (nodes.empty()) {
  ------------------
  |  Branch (647:17): [True: 22, False: 140]
  ------------------
  648|     22|                if (motion_file) {
  ------------------
  |  Branch (648:21): [True: 22, False: 0]
  ------------------
  649|       |
  650|       |                    // LightWave motion file. Add dummy node
  651|     22|                    LWS::NodeDesc d;
  652|     22|                    d.type = LWS::NodeDesc::OBJECT;
  653|     22|                    d.name = c;
  654|     22|                    d.number = cur_object++;
  655|     22|                    nodes.push_back(d);
  656|     22|                }
  657|     22|                ASSIMP_LOG_ERROR("LWS: Unexpected keyword: \'Channel\'");
  658|    140|            } else {
  659|       |                // important: index of channel
  660|    140|                nodes.back().channels.emplace_back();
  661|    140|                LWO::Envelope &env = nodes.back().channels.back();
  662|       |
  663|    140|                env.index = strtoul10(c);
  664|       |
  665|       |                // currently we can just interpret the standard channels 0...9
  666|       |                // (hack) assume that index-i yields the binary channel type from LWO
  667|    140|                env.type = (LWO::EnvelopeType)(env.index + 1);
  668|    140|            }
  669|    162|        }
  670|       |        // 'Envelope': a single animation channel
  671|  72.2k|        else if ((*it).tokens[0] == "Envelope") {
  ------------------
  |  Branch (671:18): [True: 0, False: 72.2k]
  ------------------
  672|      0|            if (nodes.empty() || nodes.back().channels.empty())
  ------------------
  |  Branch (672:17): [True: 0, False: 0]
  |  Branch (672:34): [True: 0, False: 0]
  ------------------
  673|      0|                ASSIMP_LOG_ERROR("LWS: Unexpected keyword: \'Envelope\'");
  674|      0|            else {
  675|      0|                ReadEnvelope((*it), nodes.back().channels.back());
  676|      0|            }
  677|      0|        }
  678|       |        // 'ObjectMotion': animation information for older lightwave formats
  679|  72.2k|        else if (version < 3 && ((*it).tokens[0] == "ObjectMotion" ||
  ------------------
  |  Branch (679:18): [True: 72.2k, False: 7]
  |  Branch (679:34): [True: 604, False: 71.6k]
  ------------------
  680|  71.6k|                                        (*it).tokens[0] == "CameraMotion" ||
  ------------------
  |  Branch (680:41): [True: 0, False: 71.6k]
  ------------------
  681|  71.6k|                                        (*it).tokens[0] == "LightMotion")) {
  ------------------
  |  Branch (681:41): [True: 0, False: 71.6k]
  ------------------
  682|       |
  683|    604|            if (nodes.empty())
  ------------------
  |  Branch (683:17): [True: 3, False: 601]
  ------------------
  684|    604|                ASSIMP_LOG_ERROR("LWS: Unexpected keyword: \'<Light|Object|Camera>Motion\'");
  685|    601|            else {
  686|    601|                ReadEnvelope_Old(it, root.children.end(), nodes.back(), version);
  687|    601|            }
  688|    604|        }
  689|       |        // 'Pre/PostBehavior': pre/post animation behaviour for LWSC 2
  690|  71.6k|        else if (version == 2 && (*it).tokens[0] == "Pre/PostBehavior") {
  ------------------
  |  Branch (690:18): [True: 23.0k, False: 48.5k]
  |  Branch (690:34): [True: 203, False: 22.8k]
  ------------------
  691|    203|            if (nodes.empty())
  ------------------
  |  Branch (691:17): [True: 28, False: 175]
  ------------------
  692|    203|                ASSIMP_LOG_ERROR("LWS: Unexpected keyword: \'Pre/PostBehavior'");
  693|    175|            else {
  694|  1.38k|                for (std::list<LWO::Envelope>::iterator envelopeIt = nodes.back().channels.begin(); envelopeIt != nodes.back().channels.end(); ++envelopeIt) {
  ------------------
  |  Branch (694:101): [True: 1.21k, False: 175]
  ------------------
  695|       |                    // two ints per envelope
  696|  1.21k|                    LWO::Envelope &env = *envelopeIt;
  697|  1.21k|                    env.pre = (LWO::PrePostBehaviour)strtoul10(c, &c);
  698|  1.21k|                    SkipSpaces(&c, end);
  699|  1.21k|                    env.post = (LWO::PrePostBehaviour)strtoul10(c, &c);
  700|  1.21k|                    SkipSpaces(&c, end);
  701|  1.21k|                }
  702|    175|            }
  703|    203|        }
  704|       |        // 'ParentItem': specifies the parent of the current element
  705|  71.4k|        else if ((*it).tokens[0] == "ParentItem") {
  ------------------
  |  Branch (705:18): [True: 0, False: 71.4k]
  ------------------
  706|      0|            if (nodes.empty()) {
  ------------------
  |  Branch (706:17): [True: 0, False: 0]
  ------------------
  707|      0|                ASSIMP_LOG_ERROR("LWS: Unexpected keyword: \'ParentItem\'");
  708|      0|            } else {
  709|      0|                nodes.back().parent = strtoul16(c, &c);
  710|      0|            }
  711|      0|        }
  712|       |        // 'ParentObject': deprecated one for older formats
  713|  71.4k|        else if (version < 3 && (*it).tokens[0] == "ParentObject") {
  ------------------
  |  Branch (713:18): [True: 71.4k, False: 7]
  |  Branch (713:33): [True: 27, False: 71.4k]
  ------------------
  714|     27|            if (nodes.empty()) {
  ------------------
  |  Branch (714:17): [True: 0, False: 27]
  ------------------
  715|      0|                ASSIMP_LOG_ERROR("LWS: Unexpected keyword: \'ParentObject\'");
  716|     27|            } else {
  717|     27|                nodes.back().parent = strtoul10(c, &c) | (1u << 28u);
  718|     27|            }
  719|     27|        }
  720|       |        // 'AddCamera': add a camera to the scenegraph
  721|  71.4k|        else if ((*it).tokens[0] == "AddCamera") {
  ------------------
  |  Branch (721:18): [True: 20, False: 71.3k]
  ------------------
  722|       |
  723|       |            // add node to list
  724|     20|            LWS::NodeDesc d;
  725|     20|            d.type = LWS::NodeDesc::CAMERA;
  726|       |
  727|     20|            if (version >= 4) { // handle LWSC 4 explicit ID
  ------------------
  |  Branch (727:17): [True: 0, False: 20]
  ------------------
  728|      0|                d.number = strtoul16(c, &c) & AI_LWS_MASK;
  ------------------
  |  |   82|      0|#define AI_LWS_MASK (0xffffffff >> 4u)
  ------------------
  729|     20|            } else {
  730|     20|                d.number = cur_camera++;
  731|     20|            }
  732|     20|            nodes.push_back(d);
  733|       |
  734|     20|            num_camera++;
  735|     20|        }
  736|       |        // 'CameraName': set name of currently active camera
  737|  71.3k|        else if ((*it).tokens[0] == "CameraName") {
  ------------------
  |  Branch (737:18): [True: 0, False: 71.3k]
  ------------------
  738|      0|            if (nodes.empty() || nodes.back().type != LWS::NodeDesc::CAMERA) {
  ------------------
  |  Branch (738:17): [True: 0, False: 0]
  |  Branch (738:34): [True: 0, False: 0]
  ------------------
  739|      0|                ASSIMP_LOG_ERROR("LWS: Unexpected keyword: \'CameraName\'");
  740|      0|            } else {
  741|      0|                nodes.back().name = c;
  742|      0|            }
  743|      0|        }
  744|       |        // 'AddLight': add a light to the scenegraph
  745|  71.3k|        else if ((*it).tokens[0] == "AddLight") {
  ------------------
  |  Branch (745:18): [True: 19, False: 71.3k]
  ------------------
  746|       |
  747|       |            // add node to list
  748|     19|            LWS::NodeDesc d;
  749|     19|            d.type = LWS::NodeDesc::LIGHT;
  750|       |
  751|     19|            if (version >= 4) { // handle LWSC 4 explicit ID
  ------------------
  |  Branch (751:17): [True: 0, False: 19]
  ------------------
  752|      0|                d.number = strtoul16(c, &c) & AI_LWS_MASK;
  ------------------
  |  |   82|      0|#define AI_LWS_MASK (0xffffffff >> 4u)
  ------------------
  753|     19|            } else {
  754|     19|                d.number = cur_light++;
  755|     19|            }
  756|     19|            nodes.push_back(d);
  757|       |
  758|     19|            num_light++;
  759|     19|        }
  760|       |        // 'LightName': set name of currently active light
  761|  71.3k|        else if ((*it).tokens[0] == "LightName") {
  ------------------
  |  Branch (761:18): [True: 0, False: 71.3k]
  ------------------
  762|      0|            if (nodes.empty() || nodes.back().type != LWS::NodeDesc::LIGHT) {
  ------------------
  |  Branch (762:17): [True: 0, False: 0]
  |  Branch (762:34): [True: 0, False: 0]
  ------------------
  763|      0|                ASSIMP_LOG_ERROR("LWS: Unexpected keyword: \'LightName\'");
  764|      0|            } else {
  765|      0|                nodes.back().name = c;
  766|      0|            }
  767|      0|        }
  768|       |        // 'LightIntensity': set intensity of currently active light
  769|  71.3k|        else if ((*it).tokens[0] == "LightIntensity" || (*it).tokens[0] == "LgtIntensity") {
  ------------------
  |  Branch (769:18): [True: 0, False: 71.3k]
  |  Branch (769:57): [True: 0, False: 71.3k]
  ------------------
  770|      0|            if (nodes.empty() || nodes.back().type != LWS::NodeDesc::LIGHT) {
  ------------------
  |  Branch (770:17): [True: 0, False: 0]
  |  Branch (770:34): [True: 0, False: 0]
  ------------------
  771|      0|                ASSIMP_LOG_ERROR("LWS: Unexpected keyword: \'LightIntensity\'");
  772|      0|            } else {
  773|      0|                const std::string env = "(envelope)";
  774|      0|                if (0 == strncmp(c, env.c_str(), env.size())) {
  ------------------
  |  Branch (774:21): [True: 0, False: 0]
  ------------------
  775|      0|                    ASSIMP_LOG_ERROR("LWS: envelopes for  LightIntensity not supported, set to 1.0");
  776|      0|                    nodes.back().lightIntensity = (ai_real)1.0;
  777|      0|                } else {
  778|      0|                    fast_atoreal_move(c, nodes.back().lightIntensity);
  779|      0|                }
  780|      0|            }
  781|      0|        }
  782|       |        // 'LightType': set type of currently active light
  783|  71.3k|        else if ((*it).tokens[0] == "LightType") {
  ------------------
  |  Branch (783:18): [True: 0, False: 71.3k]
  ------------------
  784|      0|            if (nodes.empty() || nodes.back().type != LWS::NodeDesc::LIGHT) {
  ------------------
  |  Branch (784:17): [True: 0, False: 0]
  |  Branch (784:34): [True: 0, False: 0]
  ------------------
  785|      0|                ASSIMP_LOG_ERROR("LWS: Unexpected keyword: \'LightType\'");
  786|      0|            } else {
  787|      0|                nodes.back().lightType = strtoul10(c);
  788|      0|            }
  789|      0|        }
  790|       |        // 'LightFalloffType': set falloff type of currently active light
  791|  71.3k|        else if ((*it).tokens[0] == "LightFalloffType") {
  ------------------
  |  Branch (791:18): [True: 0, False: 71.3k]
  ------------------
  792|      0|            if (nodes.empty() || nodes.back().type != LWS::NodeDesc::LIGHT) {
  ------------------
  |  Branch (792:17): [True: 0, False: 0]
  |  Branch (792:34): [True: 0, False: 0]
  ------------------
  793|      0|                ASSIMP_LOG_ERROR("LWS: Unexpected keyword: \'LightFalloffType\'");
  794|      0|            } else {
  795|      0|                nodes.back().lightFalloffType = strtoul10(c);
  796|      0|            }
  797|      0|        }
  798|       |        // 'LightConeAngle': set cone angle of currently active light
  799|  71.3k|        else if ((*it).tokens[0] == "LightConeAngle") {
  ------------------
  |  Branch (799:18): [True: 0, False: 71.3k]
  ------------------
  800|      0|            if (nodes.empty() || nodes.back().type != LWS::NodeDesc::LIGHT) {
  ------------------
  |  Branch (800:17): [True: 0, False: 0]
  |  Branch (800:34): [True: 0, False: 0]
  ------------------
  801|      0|                ASSIMP_LOG_ERROR("LWS: Unexpected keyword: \'LightConeAngle\'");
  802|      0|            } else {
  803|      0|                nodes.back().lightConeAngle = fast_atof(c);
  804|      0|            }
  805|      0|        }
  806|       |        // 'LightEdgeAngle': set area where we're smoothing from min to max intensity
  807|  71.3k|        else if ((*it).tokens[0] == "LightEdgeAngle") {
  ------------------
  |  Branch (807:18): [True: 0, False: 71.3k]
  ------------------
  808|      0|            if (nodes.empty() || nodes.back().type != LWS::NodeDesc::LIGHT) {
  ------------------
  |  Branch (808:17): [True: 0, False: 0]
  |  Branch (808:34): [True: 0, False: 0]
  ------------------
  809|      0|                ASSIMP_LOG_ERROR("LWS: Unexpected keyword: \'LightEdgeAngle\'");
  810|      0|            } else {
  811|      0|                nodes.back().lightEdgeAngle = fast_atof(c);
  812|      0|            }
  813|      0|        }
  814|       |        // 'LightColor': set color of currently active light
  815|  71.3k|        else if ((*it).tokens[0] == "LightColor") {
  ------------------
  |  Branch (815:18): [True: 0, False: 71.3k]
  ------------------
  816|      0|            if (nodes.empty() || nodes.back().type != LWS::NodeDesc::LIGHT) {
  ------------------
  |  Branch (816:17): [True: 0, False: 0]
  |  Branch (816:34): [True: 0, False: 0]
  ------------------
  817|      0|                ASSIMP_LOG_ERROR("LWS: Unexpected keyword: \'LightColor\'");
  818|      0|            } else {
  819|      0|                c = fast_atoreal_move(c, nodes.back().lightColor.r);
  820|      0|                SkipSpaces(&c, end);
  821|      0|                c = fast_atoreal_move(c, nodes.back().lightColor.g);
  822|      0|                SkipSpaces(&c, end);
  823|      0|                c = fast_atoreal_move(c, nodes.back().lightColor.b);
  824|      0|            }
  825|      0|        }
  826|       |
  827|       |        // 'PivotPosition': position of local transformation origin
  828|  71.3k|        else if ((*it).tokens[0] == "PivotPosition" || (*it).tokens[0] == "PivotPoint") {
  ------------------
  |  Branch (828:18): [True: 0, False: 71.3k]
  |  Branch (828:56): [True: 0, False: 71.3k]
  ------------------
  829|      0|            if (nodes.empty()) {
  ------------------
  |  Branch (829:17): [True: 0, False: 0]
  ------------------
  830|      0|                ASSIMP_LOG_ERROR("LWS: Unexpected keyword: \'PivotPosition\'");
  831|      0|            } else {
  832|      0|                c = fast_atoreal_move(c, nodes.back().pivotPos.x);
  833|      0|                SkipSpaces(&c, end);
  834|      0|                c = fast_atoreal_move(c, nodes.back().pivotPos.y);
  835|      0|                SkipSpaces(&c, end);
  836|      0|                c = fast_atoreal_move(c, nodes.back().pivotPos.z);
  837|       |                // Mark pivotPos as set
  838|      0|                nodes.back().isPivotSet = true;
  839|      0|            }
  840|      0|        }
  841|  90.1k|    }
  842|       |
  843|       |    // resolve parenting
  844|  11.0k|    for (std::list<LWS::NodeDesc>::iterator ndIt = nodes.begin(); ndIt != nodes.end(); ++ndIt) {
  ------------------
  |  Branch (844:67): [True: 11.0k, False: 44]
  ------------------
  845|       |        // check whether there is another node which calls us a parent
  846|  14.1M|        for (std::list<LWS::NodeDesc>::iterator dit = nodes.begin(); dit != nodes.end(); ++dit) {
  ------------------
  |  Branch (846:70): [True: 14.1M, False: 11.0k]
  ------------------
  847|  14.1M|            if (dit != ndIt && *ndIt == (*dit).parent) {
  ------------------
  |  Branch (847:17): [True: 14.1M, False: 11.0k]
  |  Branch (847:32): [True: 15, False: 14.1M]
  ------------------
  848|     15|                if ((*dit).parent_resolved) {
  ------------------
  |  Branch (848:21): [True: 0, False: 15]
  ------------------
  849|       |                    // fixme: it's still possible to produce an overflow due to cross references ..
  850|      0|                    ASSIMP_LOG_ERROR("LWS: Found cross reference in scene-graph");
  851|      0|                    continue;
  852|      0|                }
  853|       |
  854|     15|                ndIt->children.push_back(&*dit);
  855|     15|                (*dit).parent_resolved = &*ndIt;
  856|     15|            }
  857|  14.1M|        }
  858|  11.0k|    }
  859|       |
  860|       |    // find out how many nodes have no parent yet
  861|     44|    unsigned int no_parent = 0;
  862|  11.0k|    for (std::list<LWS::NodeDesc>::iterator ndIt = nodes.begin(); ndIt != nodes.end(); ++ndIt) {
  ------------------
  |  Branch (862:67): [True: 11.0k, False: 44]
  ------------------
  863|  11.0k|        if (!ndIt->parent_resolved) {
  ------------------
  |  Branch (863:13): [True: 11.0k, False: 15]
  ------------------
  864|  11.0k|            ++no_parent;
  865|  11.0k|        }
  866|  11.0k|    }
  867|     44|    if (!no_parent) {
  ------------------
  |  Branch (867:9): [True: 2, False: 42]
  ------------------
  868|      2|        throw DeadlyImportError("LWS: Unable to find scene root node");
  869|      2|    }
  870|       |
  871|       |    // Load all subsequent files
  872|     42|    batch.LoadAll();
  873|       |
  874|       |    // and build the final output graph by attaching the loaded external
  875|       |    // files to ourselves. first build a master graph
  876|     42|    aiScene *master = new aiScene();
  877|     42|    aiNode *nd = master->mRootNode = new aiNode();
  878|       |
  879|       |    // allocate storage for cameras&lights
  880|     42|    if (num_camera > 0u) {
  ------------------
  |  Branch (880:9): [True: 2, False: 40]
  ------------------
  881|      2|        master->mCameras = new aiCamera *[master->mNumCameras = num_camera];
  882|      2|    }
  883|     42|    aiCamera **cams = master->mCameras;
  884|     42|    if (num_light) {
  ------------------
  |  Branch (884:9): [True: 3, False: 39]
  ------------------
  885|      3|        master->mLights = new aiLight *[master->mNumLights = num_light];
  886|      3|    }
  887|     42|    aiLight **lights = master->mLights;
  888|       |
  889|     42|    std::vector<AttachmentInfo> attach;
  890|     42|    std::vector<aiNodeAnim *> anims;
  891|       |
  892|     42|    nd->mName.Set("<LWSRoot>");
  893|     42|    nd->mChildren = new aiNode *[no_parent];
  894|  11.0k|    for (std::list<LWS::NodeDesc>::iterator ndIt = nodes.begin(); ndIt != nodes.end(); ++ndIt) {
  ------------------
  |  Branch (894:67): [True: 11.0k, False: 42]
  ------------------
  895|  11.0k|        if (!ndIt->parent_resolved) {
  ------------------
  |  Branch (895:13): [True: 11.0k, False: 15]
  ------------------
  896|  11.0k|            aiNode *ro = nd->mChildren[nd->mNumChildren++] = new aiNode();
  897|  11.0k|            ro->mParent = nd;
  898|       |
  899|       |            // ... and build the scene graph. If we encounter object nodes,
  900|       |            // add then to our attachment table.
  901|  11.0k|            BuildGraph(ro, *ndIt, attach, batch, cams, lights, anims);
  902|  11.0k|        }
  903|  11.0k|    }
  904|       |
  905|       |    // create a master animation channel for us
  906|     42|    if (anims.size()) {
  ------------------
  |  Branch (906:9): [True: 7, False: 35]
  ------------------
  907|      7|        master->mAnimations = new aiAnimation *[master->mNumAnimations = 1];
  908|      7|        aiAnimation *anim = master->mAnimations[0] = new aiAnimation();
  909|      7|        anim->mName.Set("LWSMasterAnim");
  910|       |
  911|       |        // LWS uses seconds as time units, but we convert to frames
  912|      7|        anim->mTicksPerSecond = fps;
  913|      7|        anim->mDuration = last - (first - 1); /* fixme ... zero or one-based?*/
  914|       |
  915|      7|        anim->mChannels = new aiNodeAnim *[anim->mNumChannels = static_cast<unsigned int>(anims.size())];
  916|      7|        std::copy(anims.begin(), anims.end(), anim->mChannels);
  917|      7|    }
  918|       |
  919|       |    // convert the master scene to RH
  920|     42|    MakeLeftHandedProcess monster_cheat;
  921|     42|    monster_cheat.Execute(master);
  922|       |
  923|       |    // .. ccw
  924|     42|    FlipWindingOrderProcess flipper;
  925|     42|    flipper.Execute(master);
  926|       |
  927|       |    // OK ... finally build the output graph
  928|     42|    SceneCombiner::MergeScenes(&pScene, master, attach,
  929|     42|            AI_INT_MERGE_SCENE_GEN_UNIQUE_NAMES | (!configSpeedFlag ? (
  ------------------
  |  Branch (929:52): [True: 42, False: 0]
  ------------------
  930|     42|                                                                              AI_INT_MERGE_SCENE_GEN_UNIQUE_NAMES_IF_NECESSARY | AI_INT_MERGE_SCENE_GEN_UNIQUE_MATNAMES) :
  931|     42|                                                                      0));
  932|       |
  933|       |    // Check flags
  934|     42|    if (!pScene->mNumMeshes || !pScene->mNumMaterials) {
  ------------------
  |  Branch (934:9): [True: 37, False: 5]
  |  Branch (934:32): [True: 0, False: 5]
  ------------------
  935|     37|        pScene->mFlags |= AI_SCENE_FLAGS_INCOMPLETE;
  936|       |
  937|     37|        if (pScene->mNumAnimations && !noSkeletonMesh) {
  ------------------
  |  Branch (937:13): [True: 7, False: 30]
  |  Branch (937:39): [True: 7, False: 0]
  ------------------
  938|       |            // construct skeleton mesh
  939|      7|            SkeletonMeshBuilder builder(pScene);
  940|      7|        }
  941|     37|    }
  942|     42|}

_ZN6Assimp3LWS8NodeDescC2Ev:
   91|  17.8k|            number(0),
   92|  17.8k|            parent(0),
   93|       |            name(),
   94|  17.8k|            isPivotSet(false),
   95|  17.8k|            lightColor(1.f, 1.f, 1.f),
   96|  17.8k|            lightIntensity(1.f),
   97|  17.8k|            lightType(0),
   98|  17.8k|            lightFalloffType(0),
   99|  17.8k|            lightConeAngle(45.f),
  100|       |            lightEdgeAngle(),
  101|  17.8k|            parent_resolved(nullptr) {}
_ZNK6Assimp3LWS8NodeDesceqEj:
  156|  14.1M|    bool operator==(unsigned int num) const {
  157|  14.1M|        if (!num)
  ------------------
  |  Branch (157:13): [True: 14.1M, False: 116]
  ------------------
  158|  14.1M|            return false;
  159|    116|        unsigned int _type = num >> 28u;
  160|       |
  161|    116|        return _type == static_cast<unsigned int>(type) && (num & AI_LWS_MASK) == number;
  ------------------
  |  |   82|    116|#define AI_LWS_MASK (0xffffffff >> 4u)
  ------------------
  |  Branch (161:16): [True: 116, False: 0]
  |  Branch (161:60): [True: 15, False: 101]
  ------------------
  162|  14.1M|    }
_ZN6Assimp3LWS7ElementC2Ev:
   72|   157k|    Element() = default;

_ZN6Assimp3MD217LookupNormalIndexEhR10aiVector3tIfE:
   81|  12.6k|{
   82|       |    // make sure the normal index has a valid value
   83|  12.6k|    if (iNormalIndex >= ARRAYSIZE(g_avNormals)) {
  ------------------
  |  |   62|  12.6k|#   define ARRAYSIZE(_array) (int(sizeof(_array) / sizeof(_array[0])))
  ------------------
  |  Branch (83:9): [True: 835, False: 11.8k]
  ------------------
   84|    835|        ASSIMP_LOG_WARN("Index overflow in Quake II normal vector list");
   85|    835|        iNormalIndex = ARRAYSIZE(g_avNormals) - 1;
  ------------------
  |  |   62|    835|#   define ARRAYSIZE(_array) (int(sizeof(_array) / sizeof(_array[0])))
  ------------------
   86|    835|    }
   87|  12.6k|    vOut = *((const aiVector3D*)(&g_avNormals[iNormalIndex]));
   88|  12.6k|}
_ZN6Assimp11MD2ImporterC2Ev:
   98|    624|{}
_ZNK6Assimp11MD2Importer7CanReadERKNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEPNS_8IOSystemEb:
  103|    469|{
  104|    469|    static constexpr uint32_t tokens[] = { AI_MD2_MAGIC_NUMBER_LE };
  ------------------
  |  |   59|    469|#define AI_MD2_MAGIC_NUMBER_LE  AI_MAKE_MAGIC("2PDI")
  ------------------
  105|       |    return CheckMagicToken(pIOHandler,pFile,tokens,AI_COUNT_OF(tokens));
  106|    469|}
_ZNK6Assimp11MD2Importer7GetInfoEv:
  111|    636|{
  112|    636|    return &desc;
  113|    636|}
_ZN6Assimp11MD2Importer15SetupPropertiesEPKNS_8ImporterE:
  118|      2|{
  119|       |    // The
  120|       |    // AI_CONFIG_IMPORT_MD2_KEYFRAME option overrides the
  121|       |    // AI_CONFIG_IMPORT_GLOBAL_KEYFRAME option.
  122|      2|    configFrameID = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_MD2_KEYFRAME,-1);
  123|      2|    if(static_cast<unsigned int>(-1) == configFrameID){
  ------------------
  |  Branch (123:8): [True: 2, False: 0]
  ------------------
  124|       |        configFrameID = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_GLOBAL_KEYFRAME,0);
  125|      2|    }
  126|      2|}
_ZN6Assimp11MD2Importer14ValidateHeaderEv:
  130|      2|{
  131|       |    // check magic number
  132|      2|    if (m_pcHeader->magic != AI_MD2_MAGIC_NUMBER_BE &&
  ------------------
  |  |   58|      2|#define AI_MD2_MAGIC_NUMBER_BE  AI_MAKE_MAGIC("IDP2")
  ------------------
  |  Branch (132:9): [True: 2, False: 0]
  ------------------
  133|      2|        m_pcHeader->magic != AI_MD2_MAGIC_NUMBER_LE)
  ------------------
  |  |   59|      2|#define AI_MD2_MAGIC_NUMBER_LE  AI_MAKE_MAGIC("2PDI")
  ------------------
  |  Branch (133:9): [True: 0, False: 2]
  ------------------
  134|      0|    {
  135|      0|        throw DeadlyImportError("Invalid MD2 magic word: expected IDP2, found ",
  136|      0|                                ai_str_toprintable((char *)&m_pcHeader->magic, 4));
  137|      0|    }
  138|       |
  139|       |    // check file format version
  140|      2|    if (m_pcHeader->version != 8)
  ------------------
  |  Branch (140:9): [True: 0, False: 2]
  ------------------
  141|      2|        ASSIMP_LOG_WARN( "Unsupported MD2 file version. Continuing happily ...");
  142|       |
  143|       |    // check some values whether they are valid
  144|      2|    if (0 == m_pcHeader->numFrames)
  ------------------
  |  Branch (144:9): [True: 0, False: 2]
  ------------------
  145|      0|        throw DeadlyImportError( "Invalid MD2 file: NUM_FRAMES is 0");
  146|       |
  147|      2|    if (m_pcHeader->offsetEnd > (uint32_t)fileSize)
  ------------------
  |  Branch (147:9): [True: 0, False: 2]
  ------------------
  148|      0|        throw DeadlyImportError( "Invalid MD2 file: File is too small");
  149|       |
  150|      2|    if (m_pcHeader->numSkins > AI_MAX_ALLOC(MD2::Skin)) {
  ------------------
  |  Branch (150:9): [True: 0, False: 2]
  ------------------
  151|      0|        throw DeadlyImportError("Invalid MD2 header: Too many skins, would overflow");
  152|      0|    }
  153|       |
  154|      2|    if (m_pcHeader->numVertices > AI_MAX_ALLOC(MD2::Vertex)) {
  ------------------
  |  Branch (154:9): [True: 0, False: 2]
  ------------------
  155|      0|        throw DeadlyImportError("Invalid MD2 header: Too many vertices, would overflow");
  156|      0|    }
  157|       |
  158|      2|    if (m_pcHeader->numTexCoords > AI_MAX_ALLOC(MD2::TexCoord)) {
  ------------------
  |  Branch (158:9): [True: 0, False: 2]
  ------------------
  159|      0|        throw DeadlyImportError("Invalid MD2 header: Too many texcoords, would overflow");
  160|      0|    }
  161|       |
  162|      2|    if (m_pcHeader->numTriangles > AI_MAX_ALLOC(MD2::Triangle)) {
  ------------------
  |  Branch (162:9): [True: 0, False: 2]
  ------------------
  163|      0|        throw DeadlyImportError("Invalid MD2 header: Too many triangles, would overflow");
  164|      0|    }
  165|       |
  166|      2|    if (m_pcHeader->numFrames > AI_MAX_ALLOC(MD2::Frame)) {
  ------------------
  |  Branch (166:9): [True: 0, False: 2]
  ------------------
  167|      0|        throw DeadlyImportError("Invalid MD2 header: Too many frames, would overflow");
  168|      0|    }
  169|       |
  170|       |    // -1 because Frame already contains one
  171|      2|    unsigned int frameSize = sizeof (MD2::Frame) + (m_pcHeader->numVertices - 1) * sizeof(MD2::Vertex);
  172|       |
  173|      2|    if (m_pcHeader->offsetSkins     + m_pcHeader->numSkins * sizeof (MD2::Skin)         >= fileSize ||
  ------------------
  |  Branch (173:9): [True: 0, False: 2]
  ------------------
  174|      2|        m_pcHeader->offsetTexCoords + m_pcHeader->numTexCoords * sizeof (MD2::TexCoord) >= fileSize ||
  ------------------
  |  Branch (174:9): [True: 0, False: 2]
  ------------------
  175|      2|        m_pcHeader->offsetTriangles + m_pcHeader->numTriangles * sizeof (MD2::Triangle) >= fileSize ||
  ------------------
  |  Branch (175:9): [True: 0, False: 2]
  ------------------
  176|      2|        m_pcHeader->offsetFrames    + m_pcHeader->numFrames * frameSize                 >= fileSize ||
  ------------------
  |  Branch (176:9): [True: 0, False: 2]
  ------------------
  177|      2|        m_pcHeader->offsetEnd           > fileSize)
  ------------------
  |  Branch (177:9): [True: 0, False: 2]
  ------------------
  178|      0|    {
  179|      0|        throw DeadlyImportError("Invalid MD2 header: Some offsets are outside the file");
  180|      0|    }
  181|       |
  182|      2|    if (m_pcHeader->numSkins > AI_MD2_MAX_SKINS)
  ------------------
  |  |   65|      2|#define AI_MD2_MAX_SKINS        32
  ------------------
  |  Branch (182:9): [True: 0, False: 2]
  ------------------
  183|      2|        ASSIMP_LOG_WARN("The model contains more skins than Quake 2 supports");
  184|      2|    if ( m_pcHeader->numFrames > AI_MD2_MAX_FRAMES)
  ------------------
  |  |   64|      2|#define AI_MD2_MAX_FRAMES       512
  ------------------
  |  Branch (184:10): [True: 0, False: 2]
  ------------------
  185|      2|        ASSIMP_LOG_WARN("The model contains more frames than Quake 2 supports");
  186|      2|    if (m_pcHeader->numVertices > AI_MD2_MAX_VERTS)
  ------------------
  |  |   66|      2|#define AI_MD2_MAX_VERTS        2048
  ------------------
  |  Branch (186:9): [True: 0, False: 2]
  ------------------
  187|      2|        ASSIMP_LOG_WARN("The model contains more vertices than Quake 2 supports");
  188|       |
  189|      2|    if (m_pcHeader->numFrames <= configFrameID )
  ------------------
  |  Branch (189:9): [True: 0, False: 2]
  ------------------
  190|      0|        throw DeadlyImportError("MD2: The requested frame (", configFrameID, ") does not exist in the file");
  191|      2|}
_ZN6Assimp11MD2Importer14InternReadFileERKNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEP7aiScenePNS_8IOSystemE:
  197|      2|{
  198|      2|    std::unique_ptr<IOStream> file( pIOHandler->Open( pFile));
  199|       |
  200|       |    // Check whether we can read from the file
  201|      2|    if (file == nullptr) {
  ------------------
  |  Branch (201:9): [True: 0, False: 2]
  ------------------
  202|      0|        throw DeadlyImportError("Failed to open MD2 file ", pFile, "");
  203|      0|    }
  204|       |
  205|       |    // check whether the md3 file is large enough to contain
  206|       |    // at least the file header
  207|      2|    fileSize = (unsigned int)file->FileSize();
  208|      2|    if (fileSize < sizeof(MD2::Header)) {
  ------------------
  |  Branch (208:9): [True: 0, False: 2]
  ------------------
  209|      0|        throw DeadlyImportError("MD2 File is too small");
  210|      0|    }
  211|       |
  212|      2|    std::vector<uint8_t> mBuffer2(fileSize);
  213|      2|    file->Read(&mBuffer2[0], 1, fileSize);
  214|      2|    mBuffer = &mBuffer2[0];
  215|       |
  216|      2|    m_pcHeader = (BE_NCONST MD2::Header*)mBuffer;
  217|       |
  218|       |#ifdef AI_BUILD_BIG_ENDIAN
  219|       |
  220|       |    ByteSwap::Swap4(&m_pcHeader->frameSize);
  221|       |    ByteSwap::Swap4(&m_pcHeader->magic);
  222|       |    ByteSwap::Swap4(&m_pcHeader->numFrames);
  223|       |    ByteSwap::Swap4(&m_pcHeader->numGlCommands);
  224|       |    ByteSwap::Swap4(&m_pcHeader->numSkins);
  225|       |    ByteSwap::Swap4(&m_pcHeader->numTexCoords);
  226|       |    ByteSwap::Swap4(&m_pcHeader->numTriangles);
  227|       |    ByteSwap::Swap4(&m_pcHeader->numVertices);
  228|       |    ByteSwap::Swap4(&m_pcHeader->offsetEnd);
  229|       |    ByteSwap::Swap4(&m_pcHeader->offsetFrames);
  230|       |    ByteSwap::Swap4(&m_pcHeader->offsetGlCommands);
  231|       |    ByteSwap::Swap4(&m_pcHeader->offsetSkins);
  232|       |    ByteSwap::Swap4(&m_pcHeader->offsetTexCoords);
  233|       |    ByteSwap::Swap4(&m_pcHeader->offsetTriangles);
  234|       |    ByteSwap::Swap4(&m_pcHeader->skinHeight);
  235|       |    ByteSwap::Swap4(&m_pcHeader->skinWidth);
  236|       |    ByteSwap::Swap4(&m_pcHeader->version);
  237|       |
  238|       |#endif
  239|       |
  240|      2|    ValidateHeader();
  241|       |
  242|       |    // there won't be more than one mesh inside the file
  243|      2|    pScene->mNumMaterials = 1;
  244|      2|    pScene->mRootNode = new aiNode();
  245|      2|    pScene->mRootNode->mNumMeshes = 1;
  246|      2|    pScene->mRootNode->mMeshes = new unsigned int[1];
  247|      2|    pScene->mRootNode->mMeshes[0] = 0;
  248|      2|    pScene->mMaterials = new aiMaterial*[1];
  249|      2|    pScene->mMaterials[0] = new aiMaterial();
  250|      2|    pScene->mNumMeshes = 1;
  251|      2|    pScene->mMeshes = new aiMesh*[1];
  252|       |
  253|      2|    aiMesh* pcMesh = pScene->mMeshes[0] = new aiMesh();
  254|      2|    pcMesh->mPrimitiveTypes = aiPrimitiveType_TRIANGLE;
  255|       |
  256|       |    // navigate to the begin of the current frame data
  257|      2|	BE_NCONST MD2::Frame* pcFrame = (BE_NCONST MD2::Frame*) ((uint8_t*)
  258|      2|		m_pcHeader + m_pcHeader->offsetFrames + (m_pcHeader->frameSize * configFrameID));
  259|       |
  260|       |    // navigate to the begin of the triangle data
  261|      2|    MD2::Triangle* pcTriangles = (MD2::Triangle*) ((uint8_t*)
  262|      2|        m_pcHeader + m_pcHeader->offsetTriangles);
  263|       |
  264|       |    // navigate to the begin of the tex coords data
  265|      2|    BE_NCONST MD2::TexCoord* pcTexCoords = (BE_NCONST MD2::TexCoord*) ((uint8_t*)
  266|      2|        m_pcHeader + m_pcHeader->offsetTexCoords);
  267|       |
  268|       |    // navigate to the begin of the vertex data
  269|      2|    BE_NCONST MD2::Vertex* pcVerts = (BE_NCONST MD2::Vertex*) (pcFrame->vertices);
  270|       |
  271|       |#ifdef AI_BUILD_BIG_ENDIAN
  272|       |    for (uint32_t i = 0; i< m_pcHeader->numTriangles; ++i)
  273|       |    {
  274|       |        for (unsigned int p = 0; p < 3;++p)
  275|       |        {
  276|       |            ByteSwap::Swap2(& pcTriangles[i].textureIndices[p]);
  277|       |            ByteSwap::Swap2(& pcTriangles[i].vertexIndices[p]);
  278|       |        }
  279|       |    }
  280|       |    for (uint32_t i = 0; i < m_pcHeader->offsetTexCoords;++i)
  281|       |    {
  282|       |        ByteSwap::Swap2(& pcTexCoords[i].s);
  283|       |        ByteSwap::Swap2(& pcTexCoords[i].t);
  284|       |    }
  285|       |    ByteSwap::Swap4( & pcFrame->scale[0] );
  286|       |    ByteSwap::Swap4( & pcFrame->scale[1] );
  287|       |    ByteSwap::Swap4( & pcFrame->scale[2] );
  288|       |    ByteSwap::Swap4( & pcFrame->translate[0] );
  289|       |    ByteSwap::Swap4( & pcFrame->translate[1] );
  290|       |    ByteSwap::Swap4( & pcFrame->translate[2] );
  291|       |#endif
  292|       |
  293|      2|    pcMesh->mNumFaces = m_pcHeader->numTriangles;
  294|      2|    pcMesh->mFaces = new aiFace[m_pcHeader->numTriangles];
  295|       |
  296|       |    // allocate output storage
  297|      2|    pcMesh->mNumVertices = (unsigned int)pcMesh->mNumFaces*3;
  298|      2|    pcMesh->mVertices = new aiVector3D[pcMesh->mNumVertices];
  299|      2|    pcMesh->mNormals = new aiVector3D[pcMesh->mNumVertices];
  300|       |
  301|       |    // Not sure whether there are MD2 files without texture coordinates
  302|       |    // NOTE: texture coordinates can be there without a texture,
  303|       |    // but a texture can't be there without a valid UV channel
  304|      2|    aiMaterial* pcHelper = (aiMaterial*)pScene->mMaterials[0];
  305|      2|    const int iMode = (int)aiShadingMode_Gouraud;
  306|      2|    pcHelper->AddProperty<int>(&iMode, 1, AI_MATKEY_SHADING_MODEL);
  307|       |
  308|      2|    if (m_pcHeader->numTexCoords && m_pcHeader->numSkins)
  ------------------
  |  Branch (308:9): [True: 2, False: 0]
  |  Branch (308:37): [True: 0, False: 2]
  ------------------
  309|      0|    {
  310|       |        // navigate to the first texture associated with the mesh
  311|      0|        const MD2::Skin* pcSkins = (const MD2::Skin*) ((unsigned char*)m_pcHeader +
  312|      0|            m_pcHeader->offsetSkins);
  313|       |
  314|      0|        aiColor3D clr;
  315|      0|        clr.b = clr.g = clr.r = 1.0f;
  316|      0|        pcHelper->AddProperty<aiColor3D>(&clr, 1,AI_MATKEY_COLOR_DIFFUSE);
  317|      0|        pcHelper->AddProperty<aiColor3D>(&clr, 1,AI_MATKEY_COLOR_SPECULAR);
  318|       |
  319|      0|        clr.b = clr.g = clr.r = 0.05f;
  320|      0|        pcHelper->AddProperty<aiColor3D>(&clr, 1,AI_MATKEY_COLOR_AMBIENT);
  321|       |
  322|      0|        const ai_uint32 MaxNameLength = AI_MAXLEN - 1; // one byte reserved for \0
  323|      0|        ai_uint32 iLen = static_cast<ai_uint32>(::strlen(pcSkins->name));
  324|      0|        bool nameTooLong = iLen > MaxNameLength;
  325|       |
  326|      0|        if (pcSkins->name[0] && !nameTooLong)
  ------------------
  |  Branch (326:13): [True: 0, False: 0]
  |  Branch (326:33): [True: 0, False: 0]
  ------------------
  327|      0|        {
  328|      0|            aiString szString;
  329|      0|            ::memcpy(szString.data, pcSkins->name, iLen);
  330|      0|            szString.data[iLen] = '\0';
  331|      0|            szString.length = iLen;
  332|       |
  333|      0|            pcHelper->AddProperty(&szString,AI_MATKEY_TEXTURE_DIFFUSE(0));
  334|      0|        }
  335|      0|        else if (nameTooLong) {
  ------------------
  |  Branch (335:18): [True: 0, False: 0]
  ------------------
  336|      0|            ASSIMP_LOG_WARN("Texture file name is too long. It will be skipped.");
  337|      0|        }
  338|      0|        else{
  339|      0|            ASSIMP_LOG_WARN("Texture file name has zero length. It will be skipped.");
  340|      0|        }
  341|      0|    }
  342|      2|    else    {
  343|       |        // apply a default material
  344|      2|        aiColor3D clr;
  345|      2|        clr.b = clr.g = clr.r = 0.6f;
  346|      2|        pcHelper->AddProperty<aiColor3D>(&clr, 1,AI_MATKEY_COLOR_DIFFUSE);
  347|      2|        pcHelper->AddProperty<aiColor3D>(&clr, 1,AI_MATKEY_COLOR_SPECULAR);
  348|       |
  349|      2|        clr.b = clr.g = clr.r = 0.05f;
  350|      2|        pcHelper->AddProperty<aiColor3D>(&clr, 1,AI_MATKEY_COLOR_AMBIENT);
  351|       |
  352|      2|        aiString szName;
  353|      2|        szName.Set(AI_DEFAULT_MATERIAL_NAME);
  354|      2|        pcHelper->AddProperty(&szName,AI_MATKEY_NAME);
  355|       |
  356|      2|        aiString sz;
  357|       |
  358|       |        // TODO: Try to guess the name of the texture file from the model file name
  359|       |
  360|      2|        sz.Set("$texture_dummy.bmp");
  361|      2|        pcHelper->AddProperty(&sz,AI_MATKEY_TEXTURE_DIFFUSE(0));
  362|      2|    }
  363|       |
  364|       |
  365|       |    // now read all triangles of the first frame, apply scaling and translation
  366|      2|    unsigned int iCurrent = 0;
  367|       |
  368|      2|    float fDivisorU = 1.0f,fDivisorV = 1.0f;
  369|      2|    if (m_pcHeader->numTexCoords)   {
  ------------------
  |  Branch (369:9): [True: 2, False: 0]
  ------------------
  370|       |        // allocate storage for texture coordinates, too
  371|      2|        pcMesh->mTextureCoords[0] = new aiVector3D[pcMesh->mNumVertices];
  372|      2|        pcMesh->mNumUVComponents[0] = 2;
  373|       |
  374|       |        // check whether the skin width or height are zero (this would
  375|       |        // cause a division through zero)
  376|      2|        if (!m_pcHeader->skinWidth) {
  ------------------
  |  Branch (376:13): [True: 0, False: 2]
  ------------------
  377|      0|            ASSIMP_LOG_ERROR("MD2: No valid skin width given");
  378|      0|        }
  379|      2|        else fDivisorU = (float)m_pcHeader->skinWidth;
  380|      2|        if (!m_pcHeader->skinHeight){
  ------------------
  |  Branch (380:13): [True: 0, False: 2]
  ------------------
  381|      0|            ASSIMP_LOG_ERROR("MD2: No valid skin height given");
  382|      0|        }
  383|      2|        else fDivisorV = (float)m_pcHeader->skinHeight;
  384|      2|    }
  385|       |
  386|  1.33k|    for (unsigned int i = 0; i < (unsigned int)m_pcHeader->numTriangles;++i)    {
  ------------------
  |  Branch (386:30): [True: 1.33k, False: 2]
  ------------------
  387|       |        // Allocate the face
  388|  1.33k|        pScene->mMeshes[0]->mFaces[i].mIndices = new unsigned int[3];
  389|  1.33k|        pScene->mMeshes[0]->mFaces[i].mNumIndices = 3;
  390|       |
  391|       |        // copy texture coordinates
  392|       |        // check whether they are different from the previous value at this index.
  393|       |        // In this case, create a full separate set of vertices/normals/texcoords
  394|  5.33k|        for (unsigned int c = 0; c < 3;++c,++iCurrent)  {
  ------------------
  |  Branch (394:34): [True: 3.99k, False: 1.33k]
  ------------------
  395|       |
  396|       |            // validate vertex indices
  397|  3.99k|            unsigned int iIndex = (unsigned int)pcTriangles[i].vertexIndices[c];
  398|  3.99k|            if (iIndex >= m_pcHeader->numVertices)  {
  ------------------
  |  Branch (398:17): [True: 0, False: 3.99k]
  ------------------
  399|      0|                ASSIMP_LOG_ERROR("MD2: Vertex index is outside the allowed range");
  400|      0|                iIndex = m_pcHeader->numVertices-1;
  401|      0|            }
  402|       |
  403|       |            // read x,y, and z component of the vertex
  404|  3.99k|            aiVector3D& vec = pcMesh->mVertices[iCurrent];
  405|       |
  406|  3.99k|            vec.x = (float)pcVerts[iIndex].vertex[0] * pcFrame->scale[0];
  407|  3.99k|            vec.x += pcFrame->translate[0];
  408|       |
  409|  3.99k|            vec.y = (float)pcVerts[iIndex].vertex[1] * pcFrame->scale[1];
  410|  3.99k|            vec.y += pcFrame->translate[1];
  411|       |
  412|  3.99k|            vec.z = (float)pcVerts[iIndex].vertex[2] * pcFrame->scale[2];
  413|  3.99k|            vec.z += pcFrame->translate[2];
  414|       |
  415|       |            // read the normal vector from the precalculated normal table
  416|  3.99k|            aiVector3D& vNormal = pcMesh->mNormals[iCurrent];
  417|  3.99k|            LookupNormalIndex(pcVerts[iIndex].lightNormalIndex,vNormal);
  418|       |
  419|  3.99k|            if (m_pcHeader->numTexCoords)   {
  ------------------
  |  Branch (419:17): [True: 3.99k, False: 0]
  ------------------
  420|       |                // validate texture coordinates
  421|  3.99k|                iIndex = pcTriangles[i].textureIndices[c];
  422|  3.99k|                if (iIndex >= m_pcHeader->numTexCoords) {
  ------------------
  |  Branch (422:21): [True: 0, False: 3.99k]
  ------------------
  423|      0|                    ASSIMP_LOG_ERROR("MD2: UV index is outside the allowed range");
  424|      0|                    iIndex = m_pcHeader->numTexCoords-1;
  425|      0|                }
  426|       |
  427|  3.99k|                aiVector3D& pcOut = pcMesh->mTextureCoords[0][iCurrent];
  428|       |
  429|       |                // the texture coordinates are absolute values but we
  430|       |                // need relative values between 0 and 1
  431|  3.99k|                pcOut.x = pcTexCoords[iIndex].s / fDivisorU;
  432|  3.99k|                pcOut.y = 1.f-pcTexCoords[iIndex].t / fDivisorV;
  433|  3.99k|            }
  434|  3.99k|            pScene->mMeshes[0]->mFaces[i].mIndices[c] = iCurrent;
  435|  3.99k|        }
  436|       |        // flip the face order
  437|  1.33k|        std::swap( pScene->mMeshes[0]->mFaces[i].mIndices[0], pScene->mMeshes[0]->mFaces[i].mIndices[2] );
  438|  1.33k|    }
  439|       |    // Now rotate the whole scene 90 degrees around the x axis to convert to internal coordinate system
  440|      2|    pScene->mRootNode->mTransformation = aiMatrix4x4(
  441|      2|            1.f, 0.f, 0.f, 0.f,
  442|      2|            0.f, 0.f, 1.f, 0.f,
  443|      2|            0.f, -1.f, 0.f, 0.f,
  444|      2|            0.f, 0.f, 0.f, 1.f);
  445|      2|}

_ZN6Assimp3MD318LatLngNormalToVec3EtPf:
  259|  4.10k|{
  260|  4.10k|    ai_real lat = (ai_real)(( p_iNormal >> 8u ) & 0xff);
  261|  4.10k|    ai_real lng = (ai_real)(( p_iNormal & 0xff ));
  262|  4.10k|    const ai_real invVal( ai_real( 1.0 ) / ai_real( 128.0 ) );
  263|  4.10k|    lat *= ai_real( 3.141926 ) * invVal;
  264|  4.10k|    lng *= ai_real( 3.141926 ) * invVal;
  265|       |
  266|  4.10k|    p_afOut[ 0 ] = std::cos(lat) * std::sin(lng);
  267|  4.10k|    p_afOut[ 1 ] = std::sin(lat) * std::sin(lng);
  268|  4.10k|    p_afOut[ 2 ] = std::cos(lng);
  269|  4.10k|}

_ZN6Assimp11MD3ImporterC2Ev:
  344|    624|        configFrameID(0), configHandleMP(true), configSpeedFlag(), pcHeader(), mBuffer(), fileSize(), mScene(), mIOHandler() {}
_ZN6Assimp11MD3ImporterD2Ev:
  348|    624|MD3Importer::~MD3Importer() = default;
_ZNK6Assimp11MD3Importer7CanReadERKNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEPNS_8IOSystemEb:
  352|    474|bool MD3Importer::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool /*checkSig*/) const {
  353|    474|    static constexpr uint32_t tokens[] = { AI_MD3_MAGIC_NUMBER_LE };
  ------------------
  |  |   66|    474|#define AI_MD3_MAGIC_NUMBER_LE  AI_MAKE_MAGIC("3PDI")
  ------------------
  354|       |    return CheckMagicToken(pIOHandler, pFile, tokens, AI_COUNT_OF(tokens));
  355|    474|}
_ZN6Assimp11MD3Importer21ValidateHeaderOffsetsEv:
  358|      5|void MD3Importer::ValidateHeaderOffsets() {
  359|       |    // Check magic number
  360|      5|    if (pcHeader->IDENT != AI_MD3_MAGIC_NUMBER_BE &&
  ------------------
  |  |   65|      5|#define AI_MD3_MAGIC_NUMBER_BE  AI_MAKE_MAGIC("IDP3")
  ------------------
  |  Branch (360:9): [True: 0, False: 5]
  ------------------
  361|      0|            pcHeader->IDENT != AI_MD3_MAGIC_NUMBER_LE)
  ------------------
  |  |   66|      0|#define AI_MD3_MAGIC_NUMBER_LE  AI_MAKE_MAGIC("3PDI")
  ------------------
  |  Branch (361:13): [True: 0, False: 0]
  ------------------
  362|      0|        throw DeadlyImportError("Invalid MD3 file: Magic bytes not found");
  363|       |
  364|       |    // Check file format version
  365|      5|    if (pcHeader->VERSION > 15)
  ------------------
  |  Branch (365:9): [True: 5, False: 0]
  ------------------
  366|      5|        ASSIMP_LOG_WARN("Unsupported MD3 file version. Continuing happily ...");
  367|       |
  368|       |    // Check some offset values whether they are valid
  369|      5|    if (!pcHeader->NUM_SURFACES)
  ------------------
  |  Branch (369:9): [True: 0, False: 5]
  ------------------
  370|      0|        throw DeadlyImportError("Invalid md3 file: NUM_SURFACES is 0");
  371|       |
  372|      5|    if (pcHeader->OFS_FRAMES >= fileSize || pcHeader->OFS_SURFACES >= fileSize ||
  ------------------
  |  Branch (372:9): [True: 0, False: 5]
  |  Branch (372:45): [True: 0, False: 5]
  ------------------
  373|      5|            pcHeader->OFS_EOF > fileSize) {
  ------------------
  |  Branch (373:13): [True: 0, False: 5]
  ------------------
  374|      0|        throw DeadlyImportError("Invalid MD3 header: some offsets are outside the file");
  375|      0|    }
  376|       |
  377|      5|    if (pcHeader->NUM_SURFACES > AI_MAX_ALLOC(MD3::Surface)) {
  ------------------
  |  Branch (377:9): [True: 0, False: 5]
  ------------------
  378|      0|        throw DeadlyImportError("Invalid MD3 header: too many surfaces, would overflow");
  379|      0|    }
  380|       |
  381|      5|    if (pcHeader->OFS_SURFACES + pcHeader->NUM_SURFACES * sizeof(MD3::Surface) >= fileSize) {
  ------------------
  |  Branch (381:9): [True: 0, False: 5]
  ------------------
  382|      0|        throw DeadlyImportError("Invalid MD3 header: some surfaces are outside the file");
  383|      0|    }
  384|       |
  385|      5|    if (pcHeader->NUM_FRAMES <= configFrameID)
  ------------------
  |  Branch (385:9): [True: 0, False: 5]
  ------------------
  386|      0|        throw DeadlyImportError("The requested frame is not existing the file");
  387|      5|}
_ZNK6Assimp11MD3Importer7GetInfoEv:
  431|    639|const aiImporterDesc *MD3Importer::GetInfo() const {
  432|    639|    return &desc;
  433|    639|}
_ZN6Assimp11MD3Importer15SetupPropertiesEPKNS_8ImporterE:
  437|      5|void MD3Importer::SetupProperties(const Importer *pImp) {
  438|       |    // The
  439|       |    // AI_CONFIG_IMPORT_MD3_KEYFRAME option overrides the
  440|       |    // AI_CONFIG_IMPORT_GLOBAL_KEYFRAME option.
  441|      5|    configFrameID = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_MD3_KEYFRAME, -1);
  442|      5|    if (static_cast<unsigned int>(-1) == configFrameID) {
  ------------------
  |  Branch (442:9): [True: 5, False: 0]
  ------------------
  443|      5|        configFrameID = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_GLOBAL_KEYFRAME, 0);
  444|      5|    }
  445|       |
  446|       |    // AI_CONFIG_IMPORT_MD3_HANDLE_MULTIPART
  447|      5|    configHandleMP = (0 != pImp->GetPropertyInteger(AI_CONFIG_IMPORT_MD3_HANDLE_MULTIPART, 1));
  448|       |
  449|       |    // AI_CONFIG_IMPORT_MD3_SKIN_NAME
  450|      5|    configSkinFile = (pImp->GetPropertyString(AI_CONFIG_IMPORT_MD3_SKIN_NAME, "default"));
  451|       |
  452|       |    // AI_CONFIG_IMPORT_MD3_LOAD_SHADERS
  453|      5|    configLoadShaders = (pImp->GetPropertyBool(AI_CONFIG_IMPORT_MD3_LOAD_SHADERS, true));
  454|       |
  455|       |    // AI_CONFIG_IMPORT_MD3_SHADER_SRC
  456|      5|    configShaderFile = (pImp->GetPropertyString(AI_CONFIG_IMPORT_MD3_SHADER_SRC, ""));
  457|       |
  458|       |    // AI_CONFIG_FAVOUR_SPEED
  459|       |    configSpeedFlag = (0 != pImp->GetPropertyInteger(AI_CONFIG_FAVOUR_SPEED, 0));
  460|      5|}
_ZN6Assimp11MD3Importer17ReadMultipartFileEv:
  526|      5|bool MD3Importer::ReadMultipartFile() {
  527|       |    // check whether the file name contains a common postfix, e.g lower_2.md3
  528|      5|    std::string::size_type s = filename.find_last_of('_'), t = filename.find_last_of('.');
  529|       |
  530|      5|    if (t == std::string::npos)
  ------------------
  |  Branch (530:9): [True: 0, False: 5]
  ------------------
  531|      0|        t = filename.size();
  532|      5|    if (s == std::string::npos)
  ------------------
  |  Branch (532:9): [True: 0, False: 5]
  ------------------
  533|      0|        s = t;
  534|       |
  535|      5|    const std::string mod_filename = filename.substr(0, s);
  536|      5|    const std::string suffix = filename.substr(s, t - s);
  537|       |
  538|      5|    if (mod_filename == "lower" || mod_filename == "upper" || mod_filename == "head") {
  ------------------
  |  Branch (538:9): [True: 0, False: 5]
  |  Branch (538:36): [True: 0, False: 5]
  |  Branch (538:63): [True: 0, False: 5]
  ------------------
  539|      0|        const std::string lower = path + "lower" + suffix + ".md3";
  540|      0|        const std::string upper = path + "upper" + suffix + ".md3";
  541|      0|        const std::string head = path + "head" + suffix + ".md3";
  542|       |
  543|      0|        aiScene *scene_upper = nullptr;
  544|      0|        aiScene *scene_lower = nullptr;
  545|      0|        aiScene *scene_head = nullptr;
  546|      0|        std::string failure;
  547|       |
  548|      0|        aiNode *tag_torso, *tag_head;
  549|      0|        std::vector<AttachmentInfo> attach;
  550|       |
  551|      0|        ASSIMP_LOG_INFO("Multi part MD3 player model: lower, upper and head parts are joined");
  552|       |
  553|       |        // ensure we won't try to load ourselves recursively
  554|      0|        BatchLoader::PropertyMap props;
  555|      0|        SetGenericProperty(props.ints, AI_CONFIG_IMPORT_MD3_HANDLE_MULTIPART, 0);
  556|       |
  557|       |        // now read these three files
  558|      0|        BatchLoader batch(mIOHandler);
  559|      0|        const unsigned int _lower = batch.AddLoadRequest(lower, 0, &props);
  560|      0|        const unsigned int _upper = batch.AddLoadRequest(upper, 0, &props);
  561|      0|        const unsigned int _head = batch.AddLoadRequest(head, 0, &props);
  562|      0|        batch.LoadAll();
  563|       |
  564|       |        // now construct a dummy scene to place these three parts in
  565|      0|        aiScene *master = new aiScene();
  566|      0|        aiNode *nd = master->mRootNode = new aiNode();
  567|      0|        nd->mName.Set("<MD3_Player>");
  568|       |
  569|       |        // ... and get them. We need all of them.
  570|      0|        scene_lower = batch.GetImport(_lower);
  571|      0|        if (!scene_lower) {
  ------------------
  |  Branch (571:13): [True: 0, False: 0]
  ------------------
  572|      0|            ASSIMP_LOG_ERROR("M3D: Failed to read multi part model, lower.md3 fails to load");
  573|      0|            failure = "lower";
  574|      0|            goto error_cleanup;
  575|      0|        }
  576|       |
  577|      0|        scene_upper = batch.GetImport(_upper);
  578|      0|        if (!scene_upper) {
  ------------------
  |  Branch (578:13): [True: 0, False: 0]
  ------------------
  579|      0|            ASSIMP_LOG_ERROR("M3D: Failed to read multi part model, upper.md3 fails to load");
  580|      0|            failure = "upper";
  581|      0|            goto error_cleanup;
  582|      0|        }
  583|       |
  584|      0|        scene_head = batch.GetImport(_head);
  585|      0|        if (!scene_head) {
  ------------------
  |  Branch (585:13): [True: 0, False: 0]
  ------------------
  586|      0|            ASSIMP_LOG_ERROR("M3D: Failed to read multi part model, head.md3 fails to load");
  587|      0|            failure = "head";
  588|      0|            goto error_cleanup;
  589|      0|        }
  590|       |
  591|       |        // build attachment infos. search for typical Q3 tags
  592|       |
  593|       |        // original root
  594|      0|        scene_lower->mRootNode->mName.Set("lower");
  595|      0|        attach.emplace_back(scene_lower, nd);
  596|       |
  597|       |        // tag_torso
  598|      0|        tag_torso = scene_lower->mRootNode->FindNode("tag_torso");
  599|      0|        if (!tag_torso) {
  ------------------
  |  Branch (599:13): [True: 0, False: 0]
  ------------------
  600|      0|            ASSIMP_LOG_ERROR("M3D: Failed to find attachment tag for multi part model: tag_torso expected");
  601|      0|            goto error_cleanup;
  602|      0|        }
  603|      0|        scene_upper->mRootNode->mName.Set("upper");
  604|      0|        attach.emplace_back(scene_upper, tag_torso);
  605|       |
  606|       |        // tag_head
  607|      0|        tag_head = scene_upper->mRootNode->FindNode("tag_head");
  608|      0|        if (!tag_head) {
  ------------------
  |  Branch (608:13): [True: 0, False: 0]
  ------------------
  609|      0|            ASSIMP_LOG_ERROR("M3D: Failed to find attachment tag for multi part model: tag_head expected");
  610|      0|            goto error_cleanup;
  611|      0|        }
  612|      0|        scene_head->mRootNode->mName.Set("head");
  613|      0|        attach.emplace_back(scene_head, tag_head);
  614|       |
  615|       |        // Remove tag_head and tag_torso from all other model parts ...
  616|       |        // this ensures (together with AI_INT_MERGE_SCENE_GEN_UNIQUE_NAMES_IF_NECESSARY)
  617|       |        // that tag_torso/tag_head is also the name of the (unique) output node
  618|      0|        RemoveSingleNodeFromList(scene_upper->mRootNode->FindNode("tag_torso"));
  619|      0|        RemoveSingleNodeFromList(scene_head->mRootNode->FindNode("tag_head"));
  620|       |
  621|       |        // Undo the rotations which we applied to the coordinate systems. We're
  622|       |        // working in global Quake space here
  623|      0|        scene_head->mRootNode->mTransformation = aiMatrix4x4();
  624|      0|        scene_lower->mRootNode->mTransformation = aiMatrix4x4();
  625|      0|        scene_upper->mRootNode->mTransformation = aiMatrix4x4();
  626|       |
  627|       |        // and merge the scenes
  628|      0|        SceneCombiner::MergeScenes(&mScene, master, attach,
  629|      0|                AI_INT_MERGE_SCENE_GEN_UNIQUE_NAMES |
  630|      0|                        AI_INT_MERGE_SCENE_GEN_UNIQUE_MATNAMES |
  631|      0|                        AI_INT_MERGE_SCENE_RESOLVE_CROSS_ATTACHMENTS |
  632|      0|                        (!configSpeedFlag ? AI_INT_MERGE_SCENE_GEN_UNIQUE_NAMES_IF_NECESSARY : 0));
  ------------------
  |  Branch (632:26): [True: 0, False: 0]
  ------------------
  633|       |
  634|       |        // Now rotate the whole scene 90 degrees around the x axis to convert to internal coordinate system
  635|      0|        mScene->mRootNode->mTransformation = aiMatrix4x4(1.f, 0.f, 0.f, 0.f,
  636|      0|                0.f, 0.f, 1.f, 0.f, 0.f, -1.f, 0.f, 0.f, 0.f, 0.f, 0.f, 1.f);
  637|       |
  638|      0|        return true;
  639|       |
  640|      0|    error_cleanup:
  641|      0|        delete scene_upper;
  642|      0|        delete scene_lower;
  643|      0|        delete scene_head;
  644|      0|        delete master;
  645|       |
  646|      0|        if (failure == mod_filename) {
  ------------------
  |  Branch (646:13): [True: 0, False: 0]
  ------------------
  647|      0|            throw DeadlyImportError("MD3: failure to read multipart host file");
  648|      0|        }
  649|      0|    }
  650|      5|    return false;
  651|      5|}
_ZN6Assimp11MD3Importer14InternReadFileERKNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEP7aiScenePNS_8IOSystemE:
  693|      5|void MD3Importer::InternReadFile(const std::string &pFile, aiScene *pScene, IOSystem *pIOHandler) {
  694|      5|    mFile = pFile;
  695|      5|    mScene = pScene;
  696|      5|    mIOHandler = pIOHandler;
  697|       |
  698|       |    // get base path and file name
  699|       |    // todo ... move to PathConverter
  700|      5|    std::string::size_type s = mFile.find_last_of("/\\");
  701|      5|    if (s == std::string::npos) {
  ------------------
  |  Branch (701:9): [True: 5, False: 0]
  ------------------
  702|      5|        s = 0;
  703|      5|    } else {
  704|      0|        ++s;
  705|      0|    }
  706|      5|    filename = mFile.substr(s), path = mFile.substr(0, s);
  707|     95|    for (std::string::iterator it = filename.begin(); it != filename.end(); ++it) {
  ------------------
  |  Branch (707:55): [True: 90, False: 5]
  ------------------
  708|     90|        *it = static_cast<char>(tolower(static_cast<unsigned char>(*it)));
  709|     90|    }
  710|       |
  711|       |    // Load multi-part model file, if necessary
  712|      5|    if (configHandleMP) {
  ------------------
  |  Branch (712:9): [True: 5, False: 0]
  ------------------
  713|      5|        if (ReadMultipartFile())
  ------------------
  |  Branch (713:13): [True: 0, False: 5]
  ------------------
  714|      0|            return;
  715|      5|    }
  716|       |
  717|      5|    std::unique_ptr<IOStream> file(pIOHandler->Open(pFile));
  718|       |
  719|       |    // Check whether we can read from the file
  720|      5|    if (file == nullptr) {
  ------------------
  |  Branch (720:9): [True: 0, False: 5]
  ------------------
  721|      0|        throw DeadlyImportError("Failed to open MD3 file ", pFile, ".");
  722|      0|    }
  723|       |
  724|       |    // Check whether the md3 file is large enough to contain the header
  725|      5|    fileSize = (unsigned int)file->FileSize();
  726|      5|    if (fileSize < sizeof(MD3::Header))
  ------------------
  |  Branch (726:9): [True: 0, False: 5]
  ------------------
  727|      0|        throw DeadlyImportError("MD3 File is too small.");
  728|       |
  729|       |    // Allocate storage and copy the contents of the file to a memory buffer
  730|      5|    std::vector<unsigned char> mBuffer2(fileSize);
  731|      5|    file->Read(&mBuffer2[0], 1, fileSize);
  732|      5|    mBuffer = &mBuffer2[0];
  733|      5|    const unsigned char* bufferEnd = mBuffer + fileSize;
  734|       |
  735|      5|    pcHeader = (BE_NCONST MD3::Header *)mBuffer;
  736|       |
  737|       |    // Ensure correct endianness
  738|       |#ifdef AI_BUILD_BIG_ENDIAN
  739|       |
  740|       |    AI_SWAP4(pcHeader->VERSION);
  741|       |    AI_SWAP4(pcHeader->FLAGS);
  742|       |    AI_SWAP4(pcHeader->IDENT);
  743|       |    AI_SWAP4(pcHeader->NUM_FRAMES);
  744|       |    AI_SWAP4(pcHeader->NUM_SKINS);
  745|       |    AI_SWAP4(pcHeader->NUM_SURFACES);
  746|       |    AI_SWAP4(pcHeader->NUM_TAGS);
  747|       |    AI_SWAP4(pcHeader->OFS_EOF);
  748|       |    AI_SWAP4(pcHeader->OFS_FRAMES);
  749|       |    AI_SWAP4(pcHeader->OFS_SURFACES);
  750|       |    AI_SWAP4(pcHeader->OFS_TAGS);
  751|       |
  752|       |#endif
  753|       |
  754|       |    // Validate the file header
  755|      5|    ValidateHeaderOffsets();
  756|       |
  757|       |    // Navigate to the list of surfaces
  758|      5|    BE_NCONST MD3::Surface *pcSurfaces = (BE_NCONST MD3::Surface *)(mBuffer + pcHeader->OFS_SURFACES);
  759|      5|    if ((const unsigned char*)pcSurfaces + sizeof(MD3::Surface) * pcHeader->NUM_SURFACES > bufferEnd) {
  ------------------
  |  Branch (759:9): [True: 0, False: 5]
  ------------------
  760|      0|        throw DeadlyImportError("MD3 surface headers are outside the file");
  761|      0|    }
  762|       |
  763|       |    // Navigate to the list of tags
  764|      5|    BE_NCONST MD3::Tag *pcTags = (BE_NCONST MD3::Tag *)(mBuffer + pcHeader->OFS_TAGS);
  765|      5|    if ((const unsigned char*)pcTags + sizeof(MD3::Tag) * pcHeader->NUM_TAGS > bufferEnd) {
  ------------------
  |  Branch (765:9): [True: 5, False: 0]
  ------------------
  766|      5|        throw DeadlyImportError("MD3 tags are outside the file");
  767|      5|    }
  768|       |
  769|       |    // Allocate output storage
  770|      0|    pScene->mNumMeshes = pcHeader->NUM_SURFACES;
  771|      0|    if (pcHeader->NUM_SURFACES == 0) {
  ------------------
  |  Branch (771:9): [True: 0, False: 0]
  ------------------
  772|      0|        throw DeadlyImportError("MD3: No surfaces");
  773|      0|    } else if (pcHeader->NUM_SURFACES > AI_MAX_ALLOC(aiMesh)) {
  ------------------
  |  Branch (773:16): [True: 0, False: 0]
  ------------------
  774|       |        // We allocate pointers but check against the size of aiMesh
  775|       |        // since those pointers will eventually have to point to real objects
  776|      0|        throw DeadlyImportError("MD3: Too many surfaces, would run out of memory");
  777|      0|    }
  778|      0|    pScene->mMeshes = new aiMesh *[pScene->mNumMeshes];
  779|       |
  780|      0|    pScene->mNumMaterials = pcHeader->NUM_SURFACES;
  781|      0|    pScene->mMaterials = new aiMaterial *[pScene->mNumMeshes];
  782|       |
  783|       |    // Set arrays to zero to ensue proper destruction if an exception is raised
  784|      0|    ::memset(pScene->mMeshes, 0, pScene->mNumMeshes * sizeof(aiMesh *));
  785|      0|    ::memset(pScene->mMaterials, 0, pScene->mNumMaterials * sizeof(aiMaterial *));
  786|       |
  787|       |    // Now read possible skins from .skin file
  788|      0|    Q3Shader::SkinData skins;
  789|      0|    ReadSkin(skins);
  790|       |
  791|       |    // And check whether we can locate a shader file for this model
  792|      0|    Q3Shader::ShaderData shaders;
  793|      0|    if (configLoadShaders){
  ------------------
  |  Branch (793:9): [True: 0, False: 0]
  ------------------
  794|      0|        ReadShader(shaders);
  795|      0|    }
  796|       |
  797|       |    // Adjust all texture paths in the shader
  798|      0|    const char *header_name = pcHeader->NAME;
  799|      0|    if (!shaders.blocks.empty()) {
  ------------------
  |  Branch (799:9): [True: 0, False: 0]
  ------------------
  800|      0|        for (std::list<Q3Shader::ShaderDataBlock>::iterator dit = shaders.blocks.begin(); dit != shaders.blocks.end(); ++dit) {
  ------------------
  |  Branch (800:91): [True: 0, False: 0]
  ------------------
  801|      0|            ConvertPath((*dit).name.c_str(), header_name, (*dit).name);
  802|       |
  803|      0|            for (std::list<Q3Shader::ShaderMapBlock>::iterator mit = (*dit).maps.begin(); mit != (*dit).maps.end(); ++mit) {
  ------------------
  |  Branch (803:91): [True: 0, False: 0]
  ------------------
  804|      0|                ConvertPath((*mit).name.c_str(), header_name, (*mit).name);
  805|      0|            }
  806|      0|        }
  807|      0|    }
  808|       |
  809|       |    // Read all surfaces from the file
  810|      0|    unsigned int iNum = pcHeader->NUM_SURFACES;
  811|      0|    unsigned int iNumMaterials = 0;
  812|      0|    while (iNum-- > 0) {
  ------------------
  |  Branch (812:12): [True: 0, False: 0]
  ------------------
  813|       |
  814|       |        // Ensure correct endianness
  815|       |#ifdef AI_BUILD_BIG_ENDIAN
  816|       |
  817|       |        AI_SWAP4(pcSurfaces->FLAGS);
  818|       |        AI_SWAP4(pcSurfaces->IDENT);
  819|       |        AI_SWAP4(pcSurfaces->NUM_FRAMES);
  820|       |        AI_SWAP4(pcSurfaces->NUM_SHADER);
  821|       |        AI_SWAP4(pcSurfaces->NUM_TRIANGLES);
  822|       |        AI_SWAP4(pcSurfaces->NUM_VERTICES);
  823|       |        AI_SWAP4(pcSurfaces->OFS_END);
  824|       |        AI_SWAP4(pcSurfaces->OFS_SHADERS);
  825|       |        AI_SWAP4(pcSurfaces->OFS_ST);
  826|       |        AI_SWAP4(pcSurfaces->OFS_TRIANGLES);
  827|       |        AI_SWAP4(pcSurfaces->OFS_XYZNORMAL);
  828|       |
  829|       |#endif
  830|       |
  831|       |        // Validate the surface header
  832|      0|        ValidateSurfaceHeaderOffsets(pcSurfaces);
  833|       |
  834|       |        // Navigate to the vertex list of the surface
  835|      0|        BE_NCONST MD3::Vertex *pcVertices = (BE_NCONST MD3::Vertex *)(((uint8_t *)pcSurfaces) + pcSurfaces->OFS_XYZNORMAL);
  836|       |
  837|       |        // Navigate to the triangle list of the surface
  838|      0|        BE_NCONST MD3::Triangle *pcTriangles = (BE_NCONST MD3::Triangle *)(((uint8_t *)pcSurfaces) + pcSurfaces->OFS_TRIANGLES);
  839|       |
  840|       |        // Navigate to the texture coordinate list of the surface
  841|      0|        BE_NCONST MD3::TexCoord *pcUVs = (BE_NCONST MD3::TexCoord *)(((uint8_t *)pcSurfaces) + pcSurfaces->OFS_ST);
  842|       |
  843|       |        // Navigate to the shader list of the surface
  844|      0|        BE_NCONST MD3::Shader *pcShaders = (BE_NCONST MD3::Shader *)(((uint8_t *)pcSurfaces) + pcSurfaces->OFS_SHADERS);
  845|       |
  846|       |        // If the submesh is empty ignore it
  847|      0|        if (0 == pcSurfaces->NUM_VERTICES || 0 == pcSurfaces->NUM_TRIANGLES) {
  ------------------
  |  Branch (847:13): [True: 0, False: 0]
  |  Branch (847:46): [True: 0, False: 0]
  ------------------
  848|      0|            pcSurfaces = (BE_NCONST MD3::Surface *)(((uint8_t *)pcSurfaces) + pcSurfaces->OFS_END);
  849|      0|            pScene->mNumMeshes--;
  850|      0|            continue;
  851|      0|        }
  852|       |
  853|       |        // Allocate output mesh
  854|      0|        pScene->mMeshes[iNum] = new aiMesh();
  855|      0|        aiMesh *pcMesh = pScene->mMeshes[iNum];
  856|       |
  857|      0|        std::string _texture_name;
  858|      0|        const char *texture_name = nullptr;
  859|       |
  860|       |        // Check whether we have a texture record for this surface in the .skin file
  861|      0|        std::list<Q3Shader::SkinData::TextureEntry>::iterator it = std::find(
  862|      0|                skins.textures.begin(), skins.textures.end(), pcSurfaces->NAME);
  863|       |
  864|      0|        if (it != skins.textures.end()) {
  ------------------
  |  Branch (864:13): [True: 0, False: 0]
  ------------------
  865|      0|            texture_name = &*(_texture_name = (*it).second).begin();
  866|      0|            ASSIMP_LOG_VERBOSE_DEBUG("MD3: Assigning skin texture ", (*it).second, " to surface ", pcSurfaces->NAME);
  867|      0|            (*it).resolved = true; // mark entry as resolved
  868|      0|        }
  869|       |
  870|       |        // Get the first shader (= texture?) assigned to the surface
  871|      0|        if (!texture_name && pcSurfaces->NUM_SHADER) {
  ------------------
  |  Branch (871:13): [True: 0, False: 0]
  |  Branch (871:30): [True: 0, False: 0]
  ------------------
  872|      0|            texture_name = pcShaders->NAME;
  873|      0|        }
  874|       |
  875|      0|        std::string convertedPath;
  876|      0|        if (texture_name) {
  ------------------
  |  Branch (876:13): [True: 0, False: 0]
  ------------------
  877|      0|            if (configLoadShaders){
  ------------------
  |  Branch (877:17): [True: 0, False: 0]
  ------------------
  878|      0|                ConvertPath(texture_name, header_name, convertedPath);
  879|      0|            }
  880|      0|            else{
  881|      0|                convertedPath = texture_name;
  882|      0|            }
  883|      0|        }
  884|       |
  885|      0|        const Q3Shader::ShaderDataBlock *shader = nullptr;
  886|       |
  887|       |        // Now search the current shader for a record with this name (
  888|       |        // excluding texture file extension)
  889|      0|        if (!shaders.blocks.empty()) {
  ------------------
  |  Branch (889:13): [True: 0, False: 0]
  ------------------
  890|      0|            std::string::size_type sh = convertedPath.find_last_of('.');
  891|      0|            if (sh == std::string::npos) {
  ------------------
  |  Branch (891:17): [True: 0, False: 0]
  ------------------
  892|      0|                sh = convertedPath.length();
  893|      0|            }
  894|       |
  895|      0|            const std::string without_ext = convertedPath.substr(0, sh);
  896|      0|            std::list<Q3Shader::ShaderDataBlock>::const_iterator dit = std::find(shaders.blocks.begin(), shaders.blocks.end(), without_ext);
  897|      0|            if (dit != shaders.blocks.end()) {
  ------------------
  |  Branch (897:17): [True: 0, False: 0]
  ------------------
  898|       |                // We made it!
  899|      0|                shader = &*dit;
  900|      0|                ASSIMP_LOG_INFO("Found shader record for ", without_ext);
  901|      0|            } else {
  902|      0|                ASSIMP_LOG_WARN("Unable to find shader record for ", without_ext);
  903|      0|            }
  904|      0|        }
  905|       |
  906|      0|        aiMaterial *pcHelper = new aiMaterial();
  907|       |
  908|      0|        const int iMode = (int)aiShadingMode_Gouraud;
  909|      0|        pcHelper->AddProperty<int>(&iMode, 1, AI_MATKEY_SHADING_MODEL);
  910|       |
  911|       |        // Add a small ambient color value - Quake 3 seems to have one
  912|      0|        aiColor3D clr;
  913|      0|        clr.b = clr.g = clr.r = 0.05f;
  914|      0|        pcHelper->AddProperty<aiColor3D>(&clr, 1, AI_MATKEY_COLOR_AMBIENT);
  915|       |
  916|      0|        clr.b = clr.g = clr.r = 1.0f;
  917|      0|        pcHelper->AddProperty<aiColor3D>(&clr, 1, AI_MATKEY_COLOR_DIFFUSE);
  918|      0|        pcHelper->AddProperty<aiColor3D>(&clr, 1, AI_MATKEY_COLOR_SPECULAR);
  919|       |
  920|       |        // use surface name + skin_name as material name
  921|      0|        aiString name;
  922|      0|        name.Set("MD3_[" + configSkinFile + "][" + pcSurfaces->NAME + "]");
  923|      0|        pcHelper->AddProperty(&name, AI_MATKEY_NAME);
  924|       |
  925|      0|        if (!shader) {
  ------------------
  |  Branch (925:13): [True: 0, False: 0]
  ------------------
  926|       |            // Setup dummy texture file name to ensure UV coordinates are kept during postprocessing
  927|      0|            aiString szString;
  928|      0|            if (convertedPath.length()) {
  ------------------
  |  Branch (928:17): [True: 0, False: 0]
  ------------------
  929|      0|                szString.Set(convertedPath);
  930|      0|            } else {
  931|      0|                ASSIMP_LOG_WARN("Texture file name has zero length. Using default name");
  932|      0|                szString.Set("dummy_texture.bmp");
  933|      0|            }
  934|      0|            pcHelper->AddProperty(&szString, AI_MATKEY_TEXTURE_DIFFUSE(0));
  935|       |
  936|       |            // prevent transparency by default
  937|      0|            int no_alpha = aiTextureFlags_IgnoreAlpha;
  938|      0|            pcHelper->AddProperty(&no_alpha, 1, AI_MATKEY_TEXFLAGS_DIFFUSE(0));
  939|      0|        } else {
  940|      0|            Q3Shader::ConvertShaderToMaterial(pcHelper, *shader);
  941|      0|        }
  942|       |
  943|      0|        pScene->mMaterials[iNumMaterials] = (aiMaterial *)pcHelper;
  944|      0|        pcMesh->mMaterialIndex = iNumMaterials++;
  945|       |
  946|       |        // Ensure correct endianness
  947|       |#ifdef AI_BUILD_BIG_ENDIAN
  948|       |
  949|       |        for (uint32_t i = 0; i < pcSurfaces->NUM_VERTICES; ++i) {
  950|       |            AI_SWAP2(pcVertices[i].NORMAL);
  951|       |            AI_SWAP2(pcVertices[i].X);
  952|       |            AI_SWAP2(pcVertices[i].Y);
  953|       |            AI_SWAP2(pcVertices[i].Z);
  954|       |
  955|       |            AI_SWAP4(pcUVs[i].U);
  956|       |            AI_SWAP4(pcUVs[i].V);
  957|       |        }
  958|       |        for (uint32_t i = 0; i < pcSurfaces->NUM_TRIANGLES; ++i) {
  959|       |            AI_SWAP4(pcTriangles[i].INDEXES[0]);
  960|       |            AI_SWAP4(pcTriangles[i].INDEXES[1]);
  961|       |            AI_SWAP4(pcTriangles[i].INDEXES[2]);
  962|       |        }
  963|       |
  964|       |#endif
  965|       |
  966|       |        // Fill mesh information
  967|      0|        pcMesh->mPrimitiveTypes = aiPrimitiveType_TRIANGLE;
  968|       |
  969|      0|        pcMesh->mNumVertices = pcSurfaces->NUM_TRIANGLES * 3;
  970|      0|        pcMesh->mNumFaces = pcSurfaces->NUM_TRIANGLES;
  971|      0|        pcMesh->mFaces = new aiFace[pcSurfaces->NUM_TRIANGLES];
  972|      0|        pcMesh->mNormals = new aiVector3D[pcMesh->mNumVertices];
  973|      0|        pcMesh->mVertices = new aiVector3D[pcMesh->mNumVertices];
  974|      0|        pcMesh->mTextureCoords[0] = new aiVector3D[pcMesh->mNumVertices];
  975|      0|        pcMesh->mNumUVComponents[0] = 2;
  976|       |
  977|       |        // Fill in all triangles
  978|      0|        unsigned int iCurrent = 0;
  979|      0|        for (unsigned int i = 0; i < (unsigned int)pcSurfaces->NUM_TRIANGLES; ++i) {
  ------------------
  |  Branch (979:34): [True: 0, False: 0]
  ------------------
  980|      0|            pcMesh->mFaces[i].mIndices = new unsigned int[3];
  981|      0|            pcMesh->mFaces[i].mNumIndices = 3;
  982|       |
  983|       |            //unsigned int iTemp = iCurrent;
  984|      0|            for (unsigned int c = 0; c < 3; ++c, ++iCurrent) {
  ------------------
  |  Branch (984:38): [True: 0, False: 0]
  ------------------
  985|      0|                pcMesh->mFaces[i].mIndices[c] = iCurrent;
  986|       |
  987|       |                // Read vertices
  988|      0|                aiVector3D &vec = pcMesh->mVertices[iCurrent];
  989|      0|                uint32_t index = pcTriangles->INDEXES[c];
  990|      0|                if (index >= pcSurfaces->NUM_VERTICES) {
  ------------------
  |  Branch (990:21): [True: 0, False: 0]
  ------------------
  991|      0|                    throw DeadlyImportError("MD3: Invalid vertex index");
  992|      0|                }
  993|      0|                vec.x = pcVertices[index].X * AI_MD3_XYZ_SCALE;
  ------------------
  |  |   80|      0|#define AI_MD3_XYZ_SCALE        (1.0f/64.0f)
  ------------------
  994|      0|                vec.y = pcVertices[index].Y * AI_MD3_XYZ_SCALE;
  ------------------
  |  |   80|      0|#define AI_MD3_XYZ_SCALE        (1.0f/64.0f)
  ------------------
  995|      0|                vec.z = pcVertices[index].Z * AI_MD3_XYZ_SCALE;
  ------------------
  |  |   80|      0|#define AI_MD3_XYZ_SCALE        (1.0f/64.0f)
  ------------------
  996|       |
  997|       |                // Convert the normal vector to uncompressed float3 format
  998|      0|                aiVector3D &nor = pcMesh->mNormals[iCurrent];
  999|      0|                LatLngNormalToVec3(pcVertices[index].NORMAL, (ai_real *)&nor);
 1000|       |
 1001|       |                // Read texture coordinates
 1002|      0|                pcMesh->mTextureCoords[0][iCurrent].x = pcUVs[index].U;
 1003|      0|                pcMesh->mTextureCoords[0][iCurrent].y = 1.0f - pcUVs[index].V;
 1004|      0|            }
 1005|       |            // Flip face order normally, unless shader is backfacing
 1006|      0|            if (!(shader && shader->cull == Q3Shader::CULL_CCW)) {
  ------------------
  |  Branch (1006:19): [True: 0, False: 0]
  |  Branch (1006:29): [True: 0, False: 0]
  ------------------
 1007|      0|                std::swap(pcMesh->mFaces[i].mIndices[2], pcMesh->mFaces[i].mIndices[1]);
 1008|      0|            }
 1009|      0|            ++pcTriangles;
 1010|      0|        }
 1011|       |
 1012|       |        // Go to the next surface
 1013|      0|        pcSurfaces = (BE_NCONST MD3::Surface *)(((unsigned char *)pcSurfaces) + pcSurfaces->OFS_END);
 1014|      0|    }
 1015|       |
 1016|       |    // For debugging purposes: check whether we found matches for all entries in the skins file
 1017|      0|    if (!DefaultLogger::isNullLogger()) {
  ------------------
  |  Branch (1017:9): [True: 0, False: 0]
  ------------------
 1018|      0|        for (std::list<Q3Shader::SkinData::TextureEntry>::const_iterator it = skins.textures.begin(); it != skins.textures.end(); ++it) {
  ------------------
  |  Branch (1018:103): [True: 0, False: 0]
  ------------------
 1019|      0|            if (!(*it).resolved) {
  ------------------
  |  Branch (1019:17): [True: 0, False: 0]
  ------------------
 1020|      0|                ASSIMP_LOG_ERROR("MD3: Failed to match skin ", (*it).first, " to surface ", (*it).second);
 1021|      0|            }
 1022|      0|        }
 1023|      0|    }
 1024|       |
 1025|      0|    if (!pScene->mNumMeshes) {
  ------------------
  |  Branch (1025:9): [True: 0, False: 0]
  ------------------
 1026|      0|        throw DeadlyImportError("MD3: File contains no valid mesh");
 1027|      0|    }
 1028|      0|    pScene->mNumMaterials = iNumMaterials;
 1029|       |
 1030|       |    // Now we need to generate an empty node graph
 1031|      0|    pScene->mRootNode = new aiNode("<MD3Root>");
 1032|      0|    pScene->mRootNode->mNumMeshes = pScene->mNumMeshes;
 1033|      0|    pScene->mRootNode->mMeshes = new unsigned int[pScene->mNumMeshes];
 1034|       |
 1035|       |    // Attach tiny children for all tags
 1036|      0|    if (pcHeader->NUM_TAGS) {
  ------------------
  |  Branch (1036:9): [True: 0, False: 0]
  ------------------
 1037|      0|        pScene->mRootNode->mNumChildren = pcHeader->NUM_TAGS;
 1038|      0|        pScene->mRootNode->mChildren = new aiNode *[pcHeader->NUM_TAGS];
 1039|       |
 1040|      0|        for (unsigned int i = 0; i < pcHeader->NUM_TAGS; ++i, ++pcTags) {
  ------------------
  |  Branch (1040:34): [True: 0, False: 0]
  ------------------
 1041|      0|            aiNode *nd = pScene->mRootNode->mChildren[i] = new aiNode();
 1042|      0|            if ((const unsigned char*)pcTags + sizeof(MD3::Tag) > bufferEnd) {
  ------------------
  |  Branch (1042:17): [True: 0, False: 0]
  ------------------
 1043|      0|                throw DeadlyImportError("MD3 tag is outside the file");
 1044|      0|            }
 1045|       |
 1046|      0|            nd->mName.Set((const char *)pcTags->NAME);
 1047|      0|            nd->mParent = pScene->mRootNode;
 1048|       |
 1049|      0|            AI_SWAP4(pcTags->origin.x);
 1050|      0|            AI_SWAP4(pcTags->origin.y);
 1051|      0|            AI_SWAP4(pcTags->origin.z);
 1052|       |
 1053|       |            // Copy local origin, again flip z,y
 1054|      0|            nd->mTransformation.a4 = pcTags->origin.x;
 1055|      0|            nd->mTransformation.b4 = pcTags->origin.y;
 1056|      0|            nd->mTransformation.c4 = pcTags->origin.z;
 1057|       |
 1058|       |            // Copy rest of transformation (need to transpose to match row-order matrix)
 1059|      0|            for (unsigned int a = 0; a < 3; ++a) {
  ------------------
  |  Branch (1059:38): [True: 0, False: 0]
  ------------------
 1060|      0|                for (unsigned int m = 0; m < 3; ++m) {
  ------------------
  |  Branch (1060:42): [True: 0, False: 0]
  ------------------
 1061|      0|                    nd->mTransformation[m][a] = pcTags->orientation[a][m];
 1062|      0|                    AI_SWAP4(nd->mTransformation[m][a]);
 1063|      0|                }
 1064|      0|            }
 1065|      0|        }
 1066|      0|    }
 1067|       |
 1068|      0|    for (unsigned int i = 0; i < pScene->mNumMeshes; ++i)
  ------------------
  |  Branch (1068:30): [True: 0, False: 0]
  ------------------
 1069|      0|        pScene->mRootNode->mMeshes[i] = i;
 1070|       |
 1071|       |    // Now rotate the whole scene 90 degrees around the x axis to convert to internal coordinate system
 1072|      0|    pScene->mRootNode->mTransformation = aiMatrix4x4(
 1073|      0|            1.f, 0.f, 0.f, 0.f,
 1074|      0|            0.f, 0.f, 1.f, 0.f,
 1075|      0|            0.f, -1.f, 0.f, 0.f,
 1076|      0|            0.f, 0.f, 0.f, 1.f);
 1077|      0|}

_ZN6Assimp11MD5ImporterC2Ev:
   83|    624|        mIOHandler(nullptr),
   84|       |        mBuffer(),
   85|       |        mFileSize(),
   86|       |        mLineNumber(),
   87|       |        mScene(),
   88|       |        mHadMD5Mesh(),
   89|       |        mHadMD5Anim(),
   90|       |        mHadMD5Camera(),
   91|    624|        mCconfigNoAutoLoad(false) {
   92|       |    // empty
   93|    624|}
_ZNK6Assimp11MD5Importer7CanReadERKNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEPNS_8IOSystemEb:
   97|    409|bool MD5Importer::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool /*checkSig*/) const {
   98|    409|    static const char *tokens[] = { "MD5Version" };
   99|       |    return SearchFileHeaderForToken(pIOHandler, pFile, tokens, AI_COUNT_OF(tokens));
  100|    409|}
_ZNK6Assimp11MD5Importer7GetInfoEv:
  104|    641|const aiImporterDesc *MD5Importer::GetInfo() const {
  105|    641|    return &desc;
  106|    641|}
_ZN6Assimp11MD5Importer15SetupPropertiesEPKNS_8ImporterE:
  110|      7|void MD5Importer::SetupProperties(const Importer *pImp) {
  111|       |    // AI_CONFIG_IMPORT_MD5_NO_ANIM_AUTOLOAD
  112|       |    mCconfigNoAutoLoad = (0 != pImp->GetPropertyInteger(AI_CONFIG_IMPORT_MD5_NO_ANIM_AUTOLOAD, 0));
  113|      7|}
_ZN6Assimp11MD5Importer14InternReadFileERKNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEP7aiScenePNS_8IOSystemE:
  117|      7|void MD5Importer::InternReadFile(const std::string &pFile, aiScene *_pScene, IOSystem *pIOHandler) {
  118|      7|    mIOHandler = pIOHandler;
  119|      7|    mScene = _pScene;
  120|      7|    mHadMD5Mesh = mHadMD5Anim = mHadMD5Camera = false;
  121|       |
  122|       |    // remove the file extension
  123|      7|    const std::string::size_type pos = pFile.find_last_of('.');
  124|      7|    mFile = (std::string::npos == pos ? pFile : pFile.substr(0, pos + 1));
  ------------------
  |  Branch (124:14): [True: 0, False: 7]
  ------------------
  125|       |
  126|      7|    const std::string extension = GetExtension(pFile);
  127|      7|    try {
  128|      7|        if (extension == "md5camera") {
  ------------------
  |  Branch (128:13): [True: 0, False: 7]
  ------------------
  129|      0|            LoadMD5CameraFile();
  130|      7|        } else if (mCconfigNoAutoLoad || extension == "md5anim") {
  ------------------
  |  Branch (130:20): [True: 0, False: 7]
  |  Branch (130:42): [True: 0, False: 7]
  ------------------
  131|       |            // determine file extension and process just *one* file
  132|      0|            if (extension.length() == 0) {
  ------------------
  |  Branch (132:17): [True: 0, False: 0]
  ------------------
  133|      0|                throw DeadlyImportError("Failure, need file extension to determine MD5 part type");
  134|      0|            }
  135|      0|            if (extension == "md5anim") {
  ------------------
  |  Branch (135:17): [True: 0, False: 0]
  ------------------
  136|      0|                LoadMD5AnimFile();
  137|      0|            } else if (extension == "md5mesh") {
  ------------------
  |  Branch (137:24): [True: 0, False: 0]
  ------------------
  138|      0|                LoadMD5MeshFile();
  139|      0|            }
  140|      7|        } else {
  141|      7|            LoadMD5MeshFile();
  142|      7|            LoadMD5AnimFile();
  143|      7|        }
  144|      7|    } catch (...) { // std::exception, Assimp::DeadlyImportError
  145|      2|        UnloadFileFromMemory();
  146|      2|        throw;
  147|      2|    }
  148|       |
  149|       |    // make sure we have at least one file
  150|      5|    if (!mHadMD5Mesh && !mHadMD5Anim && !mHadMD5Camera) {
  ------------------
  |  Branch (150:9): [True: 0, False: 5]
  |  Branch (150:25): [True: 0, False: 0]
  |  Branch (150:41): [True: 0, False: 0]
  ------------------
  151|      0|        throw DeadlyImportError("Failed to read valid contents out of this MD5* file");
  152|      0|    }
  153|       |
  154|       |    // Now rotate the whole scene 90 degrees around the x axis to match our internal coordinate system
  155|      5|    mScene->mRootNode->mTransformation = aiMatrix4x4(1.f, 0.f, 0.f, 0.f,
  156|      5|            0.f, 0.f, 1.f, 0.f, 0.f, -1.f, 0.f, 0.f, 0.f, 0.f, 0.f, 1.f);
  157|       |
  158|       |    // the output scene wouldn't pass the validation without this flag
  159|      5|    if (!mHadMD5Mesh) {
  ------------------
  |  Branch (159:9): [True: 0, False: 5]
  ------------------
  160|      0|        mScene->mFlags |= AI_SCENE_FLAGS_INCOMPLETE;
  161|      0|    }
  162|       |
  163|       |    // clean the instance -- the BaseImporter instance may be reused later.
  164|      5|    UnloadFileFromMemory();
  165|      5|}
_ZN6Assimp11MD5Importer18LoadFileIntoMemoryEPNS_8IOStreamE:
  169|     12|void MD5Importer::LoadFileIntoMemory(IOStream *file) {
  170|       |    // unload the previous buffer, if any
  171|     12|    UnloadFileFromMemory();
  172|       |
  173|     12|    ai_assert(nullptr != file);
  174|     12|    mFileSize = (unsigned int)file->FileSize();
  175|     12|    ai_assert(mFileSize);
  176|       |
  177|       |    // allocate storage and copy the contents of the file to a memory buffer
  178|     12|    mBuffer = new char[mFileSize + 1];
  179|     12|    file->Read((void *)mBuffer, 1, mFileSize);
  180|     12|    mLineNumber = 1;
  181|       |
  182|       |    // append a terminal 0
  183|     12|    mBuffer[mFileSize] = '\0';
  184|       |
  185|       |    // now remove all line comments from the file
  186|     12|    CommentRemover::RemoveLineComments("//", mBuffer, ' ');
  187|     12|}
_ZN6Assimp11MD5Importer20UnloadFileFromMemoryEv:
  191|     19|void MD5Importer::UnloadFileFromMemory() {
  192|       |    // delete the file buffer
  193|     19|    delete[] mBuffer;
  194|     19|    mBuffer = nullptr;
  195|     19|    mFileSize = 0;
  196|     19|}
_ZN6Assimp11MD5Importer17AttachChilds_MeshEiP6aiNodeRNSt3__16vectorINS_3MD58BoneDescENS3_9allocatorIS6_EEEE:
  234|      5|void MD5Importer::AttachChilds_Mesh(int iParentID, aiNode *piParent, BoneArray &bones) {
  235|      5|    ai_assert(nullptr != piParent);
  236|      5|    ai_assert(!piParent->mNumChildren);
  237|       |
  238|       |    // First find out how many children we'll have
  239|      5|    for (int i = 0; i < (int)bones.size(); ++i) {
  ------------------
  |  Branch (239:21): [True: 0, False: 5]
  ------------------
  240|      0|        if (iParentID != i && bones[i].mParentIndex == iParentID) {
  ------------------
  |  Branch (240:13): [True: 0, False: 0]
  |  Branch (240:31): [True: 0, False: 0]
  ------------------
  241|      0|            ++piParent->mNumChildren;
  242|      0|        }
  243|      0|    }
  244|      5|    if (piParent->mNumChildren) {
  ------------------
  |  Branch (244:9): [True: 0, False: 5]
  ------------------
  245|      0|        piParent->mChildren = new aiNode *[piParent->mNumChildren];
  246|      0|        for (int i = 0; i < (int)bones.size(); ++i) {
  ------------------
  |  Branch (246:25): [True: 0, False: 0]
  ------------------
  247|       |            // (avoid infinite recursion)
  248|      0|            if (iParentID != i && bones[i].mParentIndex == iParentID) {
  ------------------
  |  Branch (248:17): [True: 0, False: 0]
  |  Branch (248:35): [True: 0, False: 0]
  ------------------
  249|      0|                aiNode *pc;
  250|       |                // setup a new node
  251|      0|                *piParent->mChildren++ = pc = new aiNode();
  252|      0|                pc->mName = aiString(bones[i].mName);
  253|      0|                pc->mParent = piParent;
  254|       |
  255|       |                // get the transformation matrix from rotation and translational components
  256|      0|                aiQuaternion quat;
  257|      0|                MD5::ConvertQuaternion(bones[i].mRotationQuat, quat);
  258|       |
  259|      0|                bones[i].mTransform = aiMatrix4x4(quat.GetMatrix());
  260|      0|                bones[i].mTransform.a4 = bones[i].mPositionXYZ.x;
  261|      0|                bones[i].mTransform.b4 = bones[i].mPositionXYZ.y;
  262|      0|                bones[i].mTransform.c4 = bones[i].mPositionXYZ.z;
  263|       |
  264|       |                // store it for later use
  265|      0|                pc->mTransformation = bones[i].mInvTransform = bones[i].mTransform;
  266|      0|                bones[i].mInvTransform.Inverse();
  267|       |
  268|       |                // the transformations for each bone are absolute, so we need to multiply them
  269|       |                // with the inverse of the absolute matrix of the parent joint
  270|      0|                if (-1 != iParentID) {
  ------------------
  |  Branch (270:21): [True: 0, False: 0]
  ------------------
  271|      0|                    pc->mTransformation = bones[iParentID].mInvTransform * pc->mTransformation;
  272|      0|                }
  273|       |
  274|       |                // add children to this node, too
  275|      0|                AttachChilds_Mesh(i, pc, bones);
  276|      0|            }
  277|      0|        }
  278|       |        // undo offset computations
  279|      0|        piParent->mChildren -= piParent->mNumChildren;
  280|      0|    }
  281|      5|}
_ZN6Assimp11MD5Importer15LoadMD5MeshFileEv:
  325|      7|void MD5Importer::LoadMD5MeshFile() {
  326|      7|    std::string filename = mFile + "md5mesh";
  327|      7|    std::unique_ptr<IOStream> file(mIOHandler->Open(filename, "rb"));
  328|       |
  329|       |    // Check whether we can read from the file
  330|      7|    if (file == nullptr || !file->FileSize()) {
  ------------------
  |  Branch (330:9): [True: 0, False: 7]
  |  Branch (330:28): [True: 0, False: 7]
  ------------------
  331|      0|        ASSIMP_LOG_WARN("Failed to access MD5MESH file: ", filename);
  332|      0|        return;
  333|      0|    }
  334|      7|    mHadMD5Mesh = true;
  335|      7|    LoadFileIntoMemory(file.get());
  336|       |
  337|       |    // now construct a parser and parse the file
  338|      7|    MD5::MD5Parser parser(mBuffer, mFileSize);
  339|       |
  340|       |    // load the mesh information from it
  341|      7|    MD5::MD5MeshParser meshParser(parser.mSections);
  342|       |
  343|       |    // create the bone hierarchy - first the root node and dummy nodes for all meshes
  344|      7|    mScene->mRootNode = new aiNode("<MD5_Root>");
  345|      7|    mScene->mRootNode->mNumChildren = 2;
  346|      7|    mScene->mRootNode->mChildren = new aiNode *[2];
  347|       |
  348|       |    // build the hierarchy from the MD5MESH file
  349|      7|    aiNode *pcNode = mScene->mRootNode->mChildren[1] = new aiNode();
  350|      7|    pcNode->mName.Set("<MD5_Hierarchy>");
  351|      7|    pcNode->mParent = mScene->mRootNode;
  352|      7|    AttachChilds_Mesh(-1, pcNode, meshParser.mJoints);
  353|       |
  354|      7|    pcNode = mScene->mRootNode->mChildren[0] = new aiNode();
  355|      7|    pcNode->mName.Set("<MD5_Mesh>");
  356|      7|    pcNode->mParent = mScene->mRootNode;
  357|       |
  358|       |#if 0
  359|       |    if (pScene->mRootNode->mChildren[1]->mNumChildren) /* start at the right hierarchy level */
  360|       |        SkeletonMeshBuilder skeleton_maker(pScene,pScene->mRootNode->mChildren[1]->mChildren[0]);
  361|       |#else
  362|       |
  363|       |    // FIX: MD5 files exported from Blender can have empty meshes
  364|      7|    unsigned int numMaterials = 0;
  365|     68|    for (std::vector<MD5::MeshDesc>::const_iterator it = meshParser.mMeshes.begin(), end = meshParser.mMeshes.end(); it != end; ++it) {
  ------------------
  |  Branch (365:118): [True: 61, False: 7]
  ------------------
  366|     61|        if (!(*it).mFaces.empty() && !(*it).mVertices.empty()) {
  ------------------
  |  Branch (366:13): [True: 2, False: 59]
  |  Branch (366:38): [True: 0, False: 2]
  ------------------
  367|      0|            ++numMaterials;
  368|      0|        }
  369|     61|    }
  370|       |
  371|       |    // generate all meshes
  372|      7|    mScene->mMeshes = new aiMesh *[numMaterials];
  373|      7|    mScene->mMaterials = new aiMaterial *[numMaterials];
  374|       |
  375|       |    //  storage for node mesh indices
  376|      7|    pcNode->mNumMeshes = numMaterials;
  377|      7|    pcNode->mMeshes = new unsigned int[pcNode->mNumMeshes];
  378|      7|    for (unsigned int m = 0; m < pcNode->mNumMeshes; ++m) {
  ------------------
  |  Branch (378:30): [True: 0, False: 7]
  ------------------
  379|      0|        pcNode->mMeshes[m] = m;
  380|      0|    }
  381|       |
  382|      7|    unsigned int n = 0;
  383|     68|    for (std::vector<MD5::MeshDesc>::iterator it = meshParser.mMeshes.begin(), end = meshParser.mMeshes.end(); it != end; ++it) {
  ------------------
  |  Branch (383:112): [True: 61, False: 7]
  ------------------
  384|     61|        MD5::MeshDesc &meshSrc = *it;
  385|     61|        if (meshSrc.mFaces.empty() || meshSrc.mVertices.empty()) {
  ------------------
  |  Branch (385:13): [True: 59, False: 2]
  |  Branch (385:39): [True: 2, False: 0]
  ------------------
  386|     61|            continue;
  387|     61|        }
  388|       |
  389|      0|        aiMesh* mesh = new aiMesh();
  390|      0|        mScene->mMeshes[n] = mesh;
  391|      0|        ++mScene->mNumMeshes;
  392|       |
  393|      0|        mesh->mPrimitiveTypes = aiPrimitiveType_TRIANGLE;
  394|       |
  395|       |        // generate unique vertices in our internal verbose format
  396|      0|        MakeDataUnique(meshSrc);
  397|       |
  398|      0|        std::string name(meshSrc.mShader.C_Str());
  399|      0|        name += ".msh";
  400|      0|        mesh->mName = name;
  401|      0|        mesh->mNumVertices = (unsigned int)meshSrc.mVertices.size();
  402|      0|        mesh->mVertices = new aiVector3D[mesh->mNumVertices];
  403|      0|        mesh->mTextureCoords[0] = new aiVector3D[mesh->mNumVertices];
  404|      0|        mesh->mNumUVComponents[0] = 2;
  405|       |
  406|       |        // copy texture coordinates
  407|      0|        aiVector3D *pv = mesh->mTextureCoords[0];
  408|      0|        for (MD5::VertexArray::const_iterator iter = meshSrc.mVertices.begin(); iter != meshSrc.mVertices.end(); ++iter, ++pv) {
  ------------------
  |  Branch (408:81): [True: 0, False: 0]
  ------------------
  409|      0|            pv->x = (*iter).mUV.x;
  410|      0|            pv->y = 1.0f - (*iter).mUV.y; // D3D to OpenGL
  411|      0|            pv->z = 0.0f;
  412|      0|        }
  413|       |
  414|       |        // sort all bone weights - per bone
  415|      0|        unsigned int *piCount = new unsigned int[meshParser.mJoints.size()];
  416|      0|        ::memset(piCount, 0, sizeof(unsigned int) * meshParser.mJoints.size());
  417|       |
  418|      0|        for (MD5::VertexArray::const_iterator iter = meshSrc.mVertices.begin(); iter != meshSrc.mVertices.end(); ++iter, ++pv) {
  ------------------
  |  Branch (418:81): [True: 0, False: 0]
  ------------------
  419|      0|            for (unsigned int jub = (*iter).mFirstWeight, w = jub; w < jub + (*iter).mNumWeights; ++w) {
  ------------------
  |  Branch (419:68): [True: 0, False: 0]
  ------------------
  420|      0|                MD5::WeightDesc &weightDesc = meshSrc.mWeights[w];
  421|       |                /* FIX for some invalid exporters */
  422|      0|                if (!(weightDesc.mWeight < AI_MD5_WEIGHT_EPSILON && weightDesc.mWeight >= -AI_MD5_WEIGHT_EPSILON)) {
  ------------------
  |  |   65|      0|#define AI_MD5_WEIGHT_EPSILON Math::getEpsilon<float>()
  ------------------
                              if (!(weightDesc.mWeight < AI_MD5_WEIGHT_EPSILON && weightDesc.mWeight >= -AI_MD5_WEIGHT_EPSILON)) {
  ------------------
  |  |   65|      0|#define AI_MD5_WEIGHT_EPSILON Math::getEpsilon<float>()
  ------------------
  |  Branch (422:23): [True: 0, False: 0]
  |  Branch (422:69): [True: 0, False: 0]
  ------------------
  423|      0|                    ++piCount[weightDesc.mBone];
  424|      0|                }
  425|      0|            }
  426|      0|        }
  427|       |
  428|       |        // check how many we will need
  429|      0|        for (unsigned int p = 0; p < meshParser.mJoints.size(); ++p) {
  ------------------
  |  Branch (429:34): [True: 0, False: 0]
  ------------------
  430|      0|            if (piCount[p]) mesh->mNumBones++;
  ------------------
  |  Branch (430:17): [True: 0, False: 0]
  ------------------
  431|      0|        }
  432|       |
  433|       |        // just for safety
  434|      0|        if (mesh->mNumBones) {
  ------------------
  |  Branch (434:13): [True: 0, False: 0]
  ------------------
  435|      0|            mesh->mBones = new aiBone *[mesh->mNumBones];
  436|      0|            for (unsigned int q = 0, h = 0; q < meshParser.mJoints.size(); ++q) {
  ------------------
  |  Branch (436:45): [True: 0, False: 0]
  ------------------
  437|      0|                if (!piCount[q]) continue;
  ------------------
  |  Branch (437:21): [True: 0, False: 0]
  ------------------
  438|      0|                aiBone *p = mesh->mBones[h] = new aiBone();
  439|      0|                p->mNumWeights = piCount[q];
  440|      0|                p->mWeights = new aiVertexWeight[p->mNumWeights];
  441|      0|                p->mName = aiString(meshParser.mJoints[q].mName);
  442|      0|                p->mOffsetMatrix = meshParser.mJoints[q].mInvTransform;
  443|       |
  444|       |                // store the index for later use
  445|      0|                MD5::BoneDesc &boneSrc = meshParser.mJoints[q];
  446|      0|                boneSrc.mMap = h++;
  447|       |
  448|       |                // compute w-component of quaternion
  449|      0|                MD5::ConvertQuaternion(boneSrc.mRotationQuat, boneSrc.mRotationQuatConverted);
  450|      0|            }
  451|       |
  452|      0|            pv = mesh->mVertices;
  453|      0|            for (MD5::VertexArray::const_iterator iter = meshSrc.mVertices.begin(); iter != meshSrc.mVertices.end(); ++iter, ++pv) {
  ------------------
  |  Branch (453:85): [True: 0, False: 0]
  ------------------
  454|       |                // compute the final vertex position from all single weights
  455|      0|                *pv = aiVector3D();
  456|       |
  457|       |                // there are models which have weights which don't sum to 1 ...
  458|      0|                ai_real fSum = 0.0;
  459|      0|                for (unsigned int jub = (*iter).mFirstWeight, w = jub; w < jub + (*iter).mNumWeights; ++w) {
  ------------------
  |  Branch (459:72): [True: 0, False: 0]
  ------------------
  460|      0|                    fSum += meshSrc.mWeights[w].mWeight;
  461|      0|                }
  462|      0|                if (!fSum) {
  ------------------
  |  Branch (462:21): [True: 0, False: 0]
  ------------------
  463|      0|                    ASSIMP_LOG_ERROR("MD5MESH: The sum of all vertex bone weights is 0");
  464|      0|                    continue;
  465|      0|                }
  466|       |
  467|       |                // process bone weights
  468|      0|                for (unsigned int jub = (*iter).mFirstWeight, w = jub; w < jub + (*iter).mNumWeights; ++w) {
  ------------------
  |  Branch (468:72): [True: 0, False: 0]
  ------------------
  469|      0|                    if (w >= meshSrc.mWeights.size()) {
  ------------------
  |  Branch (469:25): [True: 0, False: 0]
  ------------------
  470|      0|                        throw DeadlyImportError("MD5MESH: Invalid weight index");
  471|      0|                    }
  472|       |
  473|      0|                    MD5::WeightDesc &weightDesc = meshSrc.mWeights[w];
  474|      0|                    if (weightDesc.mWeight < AI_MD5_WEIGHT_EPSILON && weightDesc.mWeight >= -AI_MD5_WEIGHT_EPSILON) {
  ------------------
  |  |   65|      0|#define AI_MD5_WEIGHT_EPSILON Math::getEpsilon<float>()
  ------------------
                                  if (weightDesc.mWeight < AI_MD5_WEIGHT_EPSILON && weightDesc.mWeight >= -AI_MD5_WEIGHT_EPSILON) {
  ------------------
  |  |   65|      0|#define AI_MD5_WEIGHT_EPSILON Math::getEpsilon<float>()
  ------------------
  |  Branch (474:25): [True: 0, False: 0]
  |  Branch (474:71): [True: 0, False: 0]
  ------------------
  475|      0|                        continue;
  476|      0|                    }
  477|       |
  478|      0|                    const ai_real fNewWeight = weightDesc.mWeight / fSum;
  479|       |
  480|       |                    // transform the local position into worldspace
  481|      0|                    MD5::BoneDesc &boneSrc = meshParser.mJoints[weightDesc.mBone];
  482|      0|                    const aiVector3D v = boneSrc.mRotationQuatConverted.Rotate(weightDesc.vOffsetPosition);
  483|       |
  484|       |                    // use the original weight to compute the vertex position
  485|       |                    // (some MD5s seem to depend on the invalid weight values ...)
  486|      0|                    *pv += ((boneSrc.mPositionXYZ + v) * (ai_real)weightDesc.mWeight);
  487|       |
  488|      0|                    aiBone *bone = mesh->mBones[boneSrc.mMap];
  489|      0|                    *bone->mWeights++ = aiVertexWeight((unsigned int)(pv - mesh->mVertices), fNewWeight);
  490|      0|                }
  491|      0|            }
  492|       |
  493|       |            // undo our nice offset tricks ...
  494|      0|            for (unsigned int p = 0; p < mesh->mNumBones; ++p) {
  ------------------
  |  Branch (494:38): [True: 0, False: 0]
  ------------------
  495|      0|                mesh->mBones[p]->mWeights -= mesh->mBones[p]->mNumWeights;
  496|      0|            }
  497|      0|        }
  498|       |
  499|      0|        delete[] piCount;
  500|       |
  501|       |        // now setup all faces - we can directly copy the list
  502|       |        // (however, take care that the aiFace destructor doesn't delete the mIndices array)
  503|      0|        mesh->mNumFaces = (unsigned int)meshSrc.mFaces.size();
  504|      0|        mesh->mFaces = new aiFace[mesh->mNumFaces];
  505|      0|        for (unsigned int c = 0; c < mesh->mNumFaces; ++c) {
  ------------------
  |  Branch (505:34): [True: 0, False: 0]
  ------------------
  506|      0|            mesh->mFaces[c].mNumIndices = 3;
  507|      0|            mesh->mFaces[c].mIndices = meshSrc.mFaces[c].mIndices;
  508|      0|            meshSrc.mFaces[c].mIndices = nullptr;
  509|      0|        }
  510|       |
  511|       |        // generate a material for the mesh
  512|      0|        aiMaterial *mat = new aiMaterial();
  513|      0|        mScene->mMaterials[n] = mat;
  514|      0|        ++mScene->mNumMaterials;
  515|       |
  516|       |        // insert the typical doom3 textures:
  517|       |        // nnn_local.tga  - normal map
  518|       |        // nnn_h.tga      - height map
  519|       |        // nnn_s.tga      - specular map
  520|       |        // nnn_d.tga      - diffuse map
  521|      0|        if (meshSrc.mShader.length && !strchr(meshSrc.mShader.data, '.')) {
  ------------------
  |  Branch (521:13): [True: 0, False: 0]
  |  Branch (521:39): [True: 0, False: 0]
  ------------------
  522|       |
  523|      0|            aiString temp(meshSrc.mShader);
  524|      0|            temp.Append("_local.tga");
  525|      0|            mat->AddProperty(&temp, AI_MATKEY_TEXTURE_NORMALS(0));
  526|       |
  527|      0|            temp = aiString(meshSrc.mShader);
  528|      0|            temp.Append("_s.tga");
  529|      0|            mat->AddProperty(&temp, AI_MATKEY_TEXTURE_SPECULAR(0));
  530|       |
  531|      0|            temp = aiString(meshSrc.mShader);
  532|      0|            temp.Append("_d.tga");
  533|      0|            mat->AddProperty(&temp, AI_MATKEY_TEXTURE_DIFFUSE(0));
  534|       |
  535|      0|            temp = aiString(meshSrc.mShader);
  536|      0|            temp.Append("_h.tga");
  537|      0|            mat->AddProperty(&temp, AI_MATKEY_TEXTURE_HEIGHT(0));
  538|       |
  539|       |            // set this also as material name
  540|      0|            mat->AddProperty(&meshSrc.mShader, AI_MATKEY_NAME);
  541|      0|        } else {
  542|       |            mat->AddProperty(&meshSrc.mShader, AI_MATKEY_TEXTURE_DIFFUSE(0));
  543|      0|        }
  544|      0|        mesh->mMaterialIndex = n++;
  545|      0|    }
  546|      7|#endif
  547|      7|}
_ZN6Assimp11MD5Importer15LoadMD5AnimFileEv:
  551|      5|void MD5Importer::LoadMD5AnimFile() {
  552|      5|    std::string pFile = mFile + "md5anim";
  553|      5|    std::unique_ptr<IOStream> file(mIOHandler->Open(pFile, "rb"));
  554|       |
  555|       |    // Check whether we can read from the file
  556|      5|    if (!file || !file->FileSize()) {
  ------------------
  |  Branch (556:9): [True: 0, False: 5]
  |  Branch (556:18): [True: 0, False: 5]
  ------------------
  557|      0|        ASSIMP_LOG_WARN("Failed to read MD5ANIM file: ", pFile);
  558|      0|        return;
  559|      0|    }
  560|       |
  561|      5|    LoadFileIntoMemory(file.get());
  562|       |
  563|       |    // parse the basic file structure
  564|      5|    MD5::MD5Parser parser(mBuffer, mFileSize);
  565|       |
  566|       |    // load the animation information from the parse tree
  567|      5|    MD5::MD5AnimParser animParser(parser.mSections);
  568|       |
  569|       |    // generate and fill the output animation
  570|      5|    if (animParser.mAnimatedBones.empty() || animParser.mFrames.empty() ||
  ------------------
  |  Branch (570:9): [True: 3, False: 2]
  |  Branch (570:46): [True: 2, False: 0]
  ------------------
  571|      5|            animParser.mBaseFrames.size() != animParser.mAnimatedBones.size()) {
  ------------------
  |  Branch (571:13): [True: 0, False: 0]
  ------------------
  572|      5|        ASSIMP_LOG_ERROR("MD5ANIM: No frames or animated bones loaded");
  573|      5|    } else {
  574|      0|        mHadMD5Anim = true;
  575|       |
  576|      0|        mScene->mAnimations = new aiAnimation *[mScene->mNumAnimations = 1];
  577|      0|        aiAnimation *anim = mScene->mAnimations[0] = new aiAnimation();
  578|      0|        anim->mNumChannels = (unsigned int)animParser.mAnimatedBones.size();
  579|      0|        anim->mChannels = new aiNodeAnim *[anim->mNumChannels];
  580|      0|        for (unsigned int i = 0; i < anim->mNumChannels; ++i) {
  ------------------
  |  Branch (580:34): [True: 0, False: 0]
  ------------------
  581|      0|            aiNodeAnim *node = anim->mChannels[i] = new aiNodeAnim();
  582|      0|            node->mNodeName = aiString(animParser.mAnimatedBones[i].mName);
  583|       |
  584|       |            // allocate storage for the keyframes
  585|      0|            node->mPositionKeys = new aiVectorKey[animParser.mFrames.size()];
  586|      0|            node->mRotationKeys = new aiQuatKey[animParser.mFrames.size()];
  587|      0|        }
  588|       |
  589|       |        // 1 tick == 1 frame
  590|      0|        anim->mTicksPerSecond = animParser.fFrameRate;
  591|       |
  592|      0|        for (FrameArray::const_iterator iter = animParser.mFrames.begin(), iterEnd = animParser.mFrames.end(); iter != iterEnd; ++iter) {
  ------------------
  |  Branch (592:112): [True: 0, False: 0]
  ------------------
  593|      0|            double dTime = (double)(*iter).iIndex;
  594|      0|            aiNodeAnim **pcAnimNode = anim->mChannels;
  595|      0|            if (!(*iter).mValues.empty() || iter == animParser.mFrames.begin()) /* be sure we have at least one frame */
  ------------------
  |  Branch (595:17): [True: 0, False: 0]
  |  Branch (595:17): [True: 0, False: 0]
  |  Branch (595:45): [True: 0, False: 0]
  ------------------
  596|      0|            {
  597|       |                // now process all values in there ... read all joints
  598|      0|                MD5::BaseFrameDesc *pcBaseFrame = &animParser.mBaseFrames[0];
  599|      0|                for (AnimBoneArray::const_iterator iter2 = animParser.mAnimatedBones.begin(); iter2 != animParser.mAnimatedBones.end(); ++iter2,
  ------------------
  |  Branch (599:95): [True: 0, False: 0]
  ------------------
  600|      0|                                                  ++pcAnimNode, ++pcBaseFrame) {
  601|      0|                    if ((*iter2).iFirstKeyIndex >= (*iter).mValues.size()) {
  ------------------
  |  Branch (601:25): [True: 0, False: 0]
  ------------------
  602|       |
  603|       |                        // Allow for empty frames
  604|      0|                        if ((*iter2).iFlags != 0) {
  ------------------
  |  Branch (604:29): [True: 0, False: 0]
  ------------------
  605|      0|                            throw DeadlyImportError("MD5: Keyframe index is out of range");
  606|      0|                        }
  607|      0|                        continue;
  608|      0|                    }
  609|      0|                    const float *fpCur = &(*iter).mValues[(*iter2).iFirstKeyIndex];
  610|      0|                    aiNodeAnim *pcCurAnimBone = *pcAnimNode;
  611|       |
  612|      0|                    aiVectorKey *vKey = &pcCurAnimBone->mPositionKeys[pcCurAnimBone->mNumPositionKeys++];
  613|      0|                    aiQuatKey *qKey = &pcCurAnimBone->mRotationKeys[pcCurAnimBone->mNumRotationKeys++];
  614|      0|                    aiVector3D vTemp;
  615|       |
  616|       |                    // translational component
  617|      0|                    for (unsigned int i = 0; i < 3; ++i) {
  ------------------
  |  Branch (617:46): [True: 0, False: 0]
  ------------------
  618|      0|                        if ((*iter2).iFlags & (1u << i)) {
  ------------------
  |  Branch (618:29): [True: 0, False: 0]
  ------------------
  619|      0|                            vKey->mValue[i] = *fpCur++;
  620|      0|                        } else
  621|      0|                            vKey->mValue[i] = pcBaseFrame->vPositionXYZ[i];
  622|      0|                    }
  623|       |
  624|       |                    // orientation component
  625|      0|                    for (unsigned int i = 0; i < 3; ++i) {
  ------------------
  |  Branch (625:46): [True: 0, False: 0]
  ------------------
  626|      0|                        if ((*iter2).iFlags & (8u << i)) {
  ------------------
  |  Branch (626:29): [True: 0, False: 0]
  ------------------
  627|      0|                            vTemp[i] = *fpCur++;
  628|      0|                        } else
  629|      0|                            vTemp[i] = pcBaseFrame->vRotationQuat[i];
  630|      0|                    }
  631|       |
  632|      0|                    MD5::ConvertQuaternion(vTemp, qKey->mValue);
  633|      0|                    qKey->mTime = vKey->mTime = dTime;
  634|      0|                }
  635|      0|            }
  636|       |
  637|       |            // compute the duration of the animation
  638|      0|            anim->mDuration = std::max(dTime, anim->mDuration);
  639|      0|        }
  640|       |
  641|       |        // If we didn't build the hierarchy yet (== we didn't load a MD5MESH),
  642|       |        // construct it now from the data given in the MD5ANIM.
  643|      0|        if (!mScene->mRootNode) {
  ------------------
  |  Branch (643:13): [True: 0, False: 0]
  ------------------
  644|      0|            mScene->mRootNode = new aiNode();
  645|      0|            mScene->mRootNode->mName.Set("<MD5_Hierarchy>");
  646|       |
  647|      0|            AttachChilds_Anim(-1, mScene->mRootNode, animParser.mAnimatedBones, (const aiNodeAnim **)anim->mChannels);
  648|       |
  649|       |            // Call SkeletonMeshBuilder to construct a mesh to represent the shape
  650|      0|            if (mScene->mRootNode->mNumChildren) {
  ------------------
  |  Branch (650:17): [True: 0, False: 0]
  ------------------
  651|      0|                SkeletonMeshBuilder skeleton_maker(mScene, mScene->mRootNode->mChildren[0]);
  652|      0|            }
  653|      0|        }
  654|      0|    }
  655|      5|}

_ZN6Assimp11MD5ImporterD2Ev:
   68|    624|    ~MD5Importer() override = default;

_ZN6Assimp3MD59MD5ParserC2EPcj:
   61|     12|MD5Parser::MD5Parser(char *_buffer, unsigned int _fileSize) : buffer(_buffer), bufferEnd(nullptr), fileSize(_fileSize), lineNumber(0) {
   62|     12|    ai_assert(nullptr != _buffer);
   63|     12|    ai_assert(0 != _fileSize);
   64|       |
   65|     12|    bufferEnd = buffer + fileSize;
   66|     12|    ASSIMP_LOG_DEBUG("MD5Parser begin");
   67|       |
   68|       |    // parse the file header
   69|     12|    ParseHeader();
   70|       |
   71|       |    // and read all sections until we're finished
   72|     12|    bool running = true;
   73|  2.06k|    while (running) {
  ------------------
  |  Branch (73:12): [True: 2.06k, False: 0]
  ------------------
   74|  2.06k|        mSections.emplace_back();
   75|  2.06k|        Section &sec = mSections.back();
   76|  2.06k|        if (!ParseSection(sec)) {
  ------------------
  |  Branch (76:13): [True: 12, False: 2.04k]
  ------------------
   77|     12|            break;
   78|     12|        }
   79|  2.06k|    }
   80|       |
   81|     12|    if (!DefaultLogger::isNullLogger()) {
  ------------------
  |  Branch (81:9): [True: 0, False: 12]
  ------------------
   82|      0|        char szBuffer[128]; // should be sufficiently large
   83|      0|        ::ai_snprintf(szBuffer, 128, "MD5Parser end. Parsed %i sections", (int)mSections.size());
   84|       |        ASSIMP_LOG_DEBUG(szBuffer);
   85|      0|    }
   86|     12|}
_ZN6Assimp3MD59MD5Parser13ReportWarningEPKcj:
   98|  15.7k|void MD5Parser::ReportWarning(const char *warn, unsigned int line) {
   99|  15.7k|    char szBuffer[1024];
  100|  15.7k|    ::snprintf(szBuffer, sizeof(szBuffer), "[MD5] Line %u: %s", line, warn);
  101|       |    ASSIMP_LOG_WARN(szBuffer);
  102|  15.7k|}
_ZN6Assimp3MD59MD5Parser11ParseHeaderEv:
  106|     12|void MD5Parser::ParseHeader() {
  107|       |    // parse and validate the file version
  108|     12|    SkipSpaces();
  109|     12|    if (!TokenMatch(buffer, "MD5Version", 10)) {
  ------------------
  |  Branch (109:9): [True: 0, False: 12]
  ------------------
  110|      0|        ReportError("Invalid MD5 file: MD5Version tag has not been found");
  111|      0|    }
  112|     12|    SkipSpaces();
  113|     12|    unsigned int iVer = ::strtoul10(buffer, (const char **)&buffer);
  114|     12|    if (10 != iVer) {
  ------------------
  |  Branch (114:9): [True: 0, False: 12]
  ------------------
  115|      0|        ReportError("MD5 version tag is unknown (10 is expected)");
  116|      0|    }
  117|     12|    SkipLine();
  118|       |
  119|       |    // print the command line options to the console
  120|     12|    char *sz = buffer;
  121|    392|    while (buffer < bufferEnd) {
  ------------------
  |  Branch (121:12): [True: 392, False: 0]
  ------------------
  122|    392|        if (IsLineEnd(*buffer++)) {
  ------------------
  |  Branch (122:13): [True: 12, False: 380]
  ------------------
  123|     12|            break;
  124|     12|        }
  125|    392|    }
  126|       |
  127|     12|    if (buffer == bufferEnd) {
  ------------------
  |  Branch (127:9): [True: 0, False: 12]
  ------------------
  128|      0|        return;
  129|      0|    }
  130|       |
  131|     12|    ASSIMP_LOG_INFO(std::string(sz, std::min((uintptr_t)MAX_LOG_MESSAGE_LENGTH, (uintptr_t)(buffer - sz))));
  132|     12|    SkipSpacesAndLineEnd();
  133|     12|}
_ZN6Assimp3MD59MD5Parser12ParseSectionERNS0_7SectionE:
  137|  2.06k|bool MD5Parser::ParseSection(Section &out) {
  138|       |    // store the current line number for use in error messages
  139|  2.06k|    out.iLineNumber = lineNumber;
  140|       |
  141|       |    // first parse the name of the section
  142|  2.06k|    char *sz = buffer;
  143|  15.7k|    while (!IsSpaceOrNewLine(*buffer)) {
  ------------------
  |  Branch (143:12): [True: 13.7k, False: 2.06k]
  ------------------
  144|  13.7k|        ++buffer;
  145|  13.7k|        if (buffer == bufferEnd) {
  ------------------
  |  Branch (145:13): [True: 0, False: 13.7k]
  ------------------
  146|      0|            return false;
  147|      0|	    }
  148|  13.7k|    }
  149|  2.06k|    out.mName = std::string(sz, (uintptr_t)(buffer - sz));
  150|  3.35k|    while (IsSpace(*buffer)) {
  ------------------
  |  Branch (150:12): [True: 1.29k, False: 2.06k]
  ------------------
  151|  1.29k|        ++buffer;
  152|  1.29k|        if (buffer == bufferEnd) {
  ------------------
  |  Branch (152:13): [True: 0, False: 1.29k]
  ------------------
  153|      0|            return false;
  154|      0|	    }
  155|  1.29k|    }
  156|       |
  157|  2.06k|    bool running = true;
  158|  5.19k|    while (running) {
  ------------------
  |  Branch (158:12): [True: 5.19k, False: 0]
  ------------------
  159|  5.19k|        if ('{' == *buffer) {
  ------------------
  |  Branch (159:13): [True: 100, False: 5.09k]
  ------------------
  160|       |            // it is a normal section so read all lines
  161|    100|            ++buffer;
  162|    100|            if (buffer == bufferEnd) {
  ------------------
  |  Branch (162:17): [True: 0, False: 100]
  ------------------
  163|      0|                return false;
  164|      0|	        }
  165|    100|            bool run = true;
  166|  27.0k|            while (run) {
  ------------------
  |  Branch (166:20): [True: 27.0k, False: 0]
  ------------------
  167|  57.9k|                while (IsSpaceOrNewLine(*buffer)) {
  ------------------
  |  Branch (167:24): [True: 30.9k, False: 27.0k]
  ------------------
  168|  30.9k|                    ++buffer;
  169|  30.9k|                    if (buffer == bufferEnd) {
  ------------------
  |  Branch (169:25): [True: 0, False: 30.9k]
  ------------------
  170|      0|                        return false;
  171|      0|		            }
  172|  30.9k|                }
  173|  27.0k|                if ('\0' == *buffer) {
  ------------------
  |  Branch (173:21): [True: 0, False: 27.0k]
  ------------------
  174|      0|                    return false; // seems this was the last section
  175|      0|                }
  176|  27.0k|                if ('}' == *buffer) {
  ------------------
  |  Branch (176:21): [True: 90, False: 26.9k]
  ------------------
  177|     90|                    ++buffer;
  178|     90|                    break;
  179|     90|                }
  180|       |
  181|  26.9k|                out.mElements.emplace_back();
  182|  26.9k|                Element &elem = out.mElements.back();
  183|       |
  184|  26.9k|                elem.iLineNumber = lineNumber;
  185|  26.9k|                elem.szStart = buffer;
  186|  26.9k|                elem.end = bufferEnd;
  187|       |
  188|       |                // terminate the line with zero
  189|   305k|                while (!IsLineEnd(*buffer)) {
  ------------------
  |  Branch (189:24): [True: 278k, False: 26.9k]
  ------------------
  190|   278k|                    ++buffer;
  191|   278k|                    if (buffer == bufferEnd) {
  ------------------
  |  Branch (191:25): [True: 10, False: 278k]
  ------------------
  192|     10|                        return false;
  193|     10|		            }
  194|   278k|                }
  195|  26.9k|                if (*buffer) {
  ------------------
  |  Branch (195:21): [True: 19.0k, False: 7.94k]
  ------------------
  196|  19.0k|                    ++lineNumber;
  197|  19.0k|                    *buffer++ = '\0';
  198|  19.0k|                    if (buffer == bufferEnd) {
  ------------------
  |  Branch (198:25): [True: 0, False: 19.0k]
  ------------------
  199|      0|                        return false;
  200|      0|		            }
  201|  19.0k|                }
  202|  26.9k|            }
  203|     90|            break;
  204|  5.09k|        } else if (!IsSpaceOrNewLine(*buffer)) {
  ------------------
  |  Branch (204:20): [True: 3.13k, False: 1.95k]
  ------------------
  205|       |            // it is an element at global scope. Parse its value and go on
  206|  3.13k|            sz = buffer;
  207|  46.8k|            while (!IsSpaceOrNewLine(*buffer++)) {
  ------------------
  |  Branch (207:20): [True: 43.6k, False: 3.13k]
  ------------------
  208|  43.6k|                if (buffer == bufferEnd) {
  ------------------
  |  Branch (208:21): [True: 2, False: 43.6k]
  ------------------
  209|      2|                    return false;
  210|      2|		        }
  211|  43.6k|            }
  212|  3.13k|            out.mGlobalValue = std::string(sz, (uintptr_t)(buffer - sz));
  213|  3.13k|            continue;
  214|  3.13k|        }
  215|  1.95k|        break;
  216|  5.19k|    }
  217|  2.04k|    if (buffer == bufferEnd) {
  ------------------
  |  Branch (217:9): [True: 0, False: 2.04k]
  ------------------
  218|      0|        return false;
  219|      0|    }
  220|  5.48k|    while (IsSpaceOrNewLine(*buffer)) {
  ------------------
  |  Branch (220:12): [True: 3.44k, False: 2.04k]
  ------------------
  221|  3.44k|        if (buffer == bufferEnd) {
  ------------------
  |  Branch (221:13): [True: 0, False: 3.44k]
  ------------------
  222|      0|            break;
  223|      0|	    }
  224|  3.44k|        ++buffer;
  225|  3.44k|    }
  226|  2.04k|    return '\0' != *buffer;
  227|  2.04k|}
_ZN6Assimp3MD513MD5MeshParserC2ERNSt3__16vectorINS0_7SectionENS2_9allocatorIS4_EEEE:
  314|      7|MD5MeshParser::MD5MeshParser(SectionArray &mSections) {
  315|      7|    ASSIMP_LOG_DEBUG("MD5MeshParser begin");
  316|       |
  317|       |    // now parse all sections
  318|  1.33k|    for (SectionArray::const_iterator iter = mSections.begin(), iterEnd = mSections.end(); iter != iterEnd; ++iter) {
  ------------------
  |  Branch (318:92): [True: 1.33k, False: 7]
  ------------------
  319|  1.33k|        if ((*iter).mName == "numMeshes") {
  ------------------
  |  Branch (319:13): [True: 0, False: 1.33k]
  ------------------
  320|      0|            mMeshes.reserve(::strtoul10((*iter).mGlobalValue.c_str()));
  321|  1.33k|        } else if ((*iter).mName == "numJoints") {
  ------------------
  |  Branch (321:20): [True: 52, False: 1.27k]
  ------------------
  322|     52|            mJoints.reserve(::strtoul10((*iter).mGlobalValue.c_str()));
  323|  1.27k|        } else if ((*iter).mName == "joints") {
  ------------------
  |  Branch (323:20): [True: 30, False: 1.24k]
  ------------------
  324|       |            // "origin" -1 ( -0.000000 0.016430 -0.006044 ) ( 0.707107 0.000000 0.707107 )
  325|     30|            for (const auto &elem : (*iter).mElements) {
  ------------------
  |  Branch (325:35): [True: 2, False: 30]
  ------------------
  326|      2|                mJoints.emplace_back();
  327|      2|                BoneDesc &desc = mJoints.back();
  328|       |
  329|      2|                const char *sz = elem.szStart;
  330|      2|                AI_MD5_PARSE_STRING_IN_QUOTATION(&sz, elem.end, desc.mName);
  331|       |
  332|      2|                AI_MD5_SKIP_SPACES(&sz, elem.end, elem.iLineNumber);
  333|       |
  334|       |                // negative values, at least -1, is allowed here
  335|      2|                desc.mParentIndex = (int)strtol10(sz, &sz);
  336|       |
  337|      2|                AI_MD5_READ_TRIPLE(desc.mPositionXYZ, &sz, elem.end, elem.iLineNumber);
  338|      2|                AI_MD5_READ_TRIPLE(desc.mRotationQuat, &sz, elem.end, elem.iLineNumber); // normalized quaternion, so w is not there
  339|      2|            }
  340|  1.24k|        } else if ((*iter).mName == "mesh") {
  ------------------
  |  Branch (340:20): [True: 61, False: 1.18k]
  ------------------
  341|     61|            mMeshes.emplace_back();
  342|     61|            MeshDesc &desc = mMeshes.back();
  343|       |
  344|  7.99k|            for (const auto &elem : (*iter).mElements) {
  ------------------
  |  Branch (344:35): [True: 7.99k, False: 61]
  ------------------
  345|  7.99k|                const char *sz = elem.szStart;
  346|       |
  347|       |                // shader attribute
  348|  7.99k|                if (TokenMatch(sz, "shader", 6)) {
  ------------------
  |  Branch (348:21): [True: 52, False: 7.94k]
  ------------------
  349|     52|                    AI_MD5_SKIP_SPACES(&sz, elem.end, elem.iLineNumber);
  350|     52|                    AI_MD5_PARSE_STRING_IN_QUOTATION(&sz, elem.end, desc.mShader);
  351|     52|                }
  352|       |                // numverts attribute
  353|  7.94k|                else if (TokenMatch(sz, "numverts", 8)) {
  ------------------
  |  Branch (353:26): [True: 0, False: 7.94k]
  ------------------
  354|      0|                    AI_MD5_SKIP_SPACES(&sz, elem.end, elem.iLineNumber);
  355|      0|                    desc.mVertices.resize(strtoul10(sz));
  356|      0|                }
  357|       |                // numtris attribute
  358|  7.94k|                else if (TokenMatch(sz, "numtris", 7)) {
  ------------------
  |  Branch (358:26): [True: 33, False: 7.91k]
  ------------------
  359|     33|                    AI_MD5_SKIP_SPACES(&sz, elem.end, elem.iLineNumber);
  360|     33|                    desc.mFaces.resize(strtoul10(sz));
  361|     33|                }
  362|       |                // numweights attribute
  363|  7.91k|                else if (TokenMatch(sz, "numweights", 10)) {
  ------------------
  |  Branch (363:26): [True: 2, False: 7.91k]
  ------------------
  364|      2|                    AI_MD5_SKIP_SPACES(&sz, elem.end, elem.iLineNumber);
  365|      2|                    desc.mWeights.resize(strtoul10(sz));
  366|      2|                }
  367|       |                // vert attribute
  368|       |                // "vert 0 ( 0.394531 0.513672 ) 0 1"
  369|  7.91k|                else if (TokenMatch(sz, "vert", 4)) {
  ------------------
  |  Branch (369:26): [True: 44, False: 7.86k]
  ------------------
  370|     44|                    AI_MD5_SKIP_SPACES(&sz, elem.end, elem.iLineNumber);
  371|     44|                    const unsigned int idx = ::strtoul10(sz, &sz);
  372|     44|                    AI_MD5_SKIP_SPACES(&sz, elem.end, elem.iLineNumber);
  373|     44|                    if (idx >= desc.mVertices.size())
  ------------------
  |  Branch (373:25): [True: 32, False: 12]
  ------------------
  374|     32|                        desc.mVertices.resize(idx + 1);
  375|       |
  376|     44|                    VertexDesc &vert = desc.mVertices[idx];
  377|     44|                    if ('(' != *sz++)
  ------------------
  |  Branch (377:25): [True: 44, False: 0]
  ------------------
  378|     44|                        MD5Parser::ReportWarning("Unexpected token: ( was expected", elem.iLineNumber);
  379|     44|                    AI_MD5_SKIP_SPACES(&sz, elem.end, elem.iLineNumber);
  380|     44|                    sz = fast_atoreal_move(sz, vert.mUV.x);
  381|     44|                    AI_MD5_SKIP_SPACES(&sz, elem.end, elem.iLineNumber);
  382|     44|                    sz = fast_atoreal_move(sz, vert.mUV.y);
  383|     44|                    AI_MD5_SKIP_SPACES(&sz, elem.end, elem.iLineNumber);
  384|     44|                    if (')' != *sz++)
  ------------------
  |  Branch (384:25): [True: 44, False: 0]
  ------------------
  385|     44|                        MD5Parser::ReportWarning("Unexpected token: ) was expected", elem.iLineNumber);
  386|     44|                    AI_MD5_SKIP_SPACES(&sz, elem.end, elem.iLineNumber);
  387|     44|                    vert.mFirstWeight = ::strtoul10(sz, &sz);
  388|     44|                    AI_MD5_SKIP_SPACES(&sz, elem.end, elem.iLineNumber);
  389|     44|                    vert.mNumWeights = ::strtoul10(sz, &sz);
  390|     44|                }
  391|       |                // tri attribute
  392|       |                // "tri 0 15 13 12"
  393|  7.86k|                else if (TokenMatch(sz, "tri", 3)) {
  ------------------
  |  Branch (393:26): [True: 171, False: 7.69k]
  ------------------
  394|    171|                    AI_MD5_SKIP_SPACES(&sz, elem.end, elem.iLineNumber);
  395|    171|                    const unsigned int idx = strtoul10(sz, &sz);
  396|    171|                    if (idx >= desc.mFaces.size()) {
  ------------------
  |  Branch (396:25): [True: 50, False: 121]
  ------------------
  397|     50|                        desc.mFaces.resize(idx + 1);
  398|     50|					}
  399|       |
  400|    171|                    aiFace &face = desc.mFaces[idx];
  401|    171|                    if (face.mNumIndices != 3) {
  ------------------
  |  Branch (401:25): [True: 65, False: 106]
  ------------------
  402|     65|						delete [] face.mIndices;
  403|     65|						face.mIndices = new unsigned int[face.mNumIndices = 3];
  404|     65|					}
  405|    684|                    for (unsigned int i = 0; i < 3; ++i) {
  ------------------
  |  Branch (405:46): [True: 513, False: 171]
  ------------------
  406|    513|                        AI_MD5_SKIP_SPACES(&sz, elem.end, elem.iLineNumber);
  407|    513|                        face.mIndices[i] = strtoul10(sz, &sz);
  408|    513|                    }
  409|    171|                }
  410|       |                // weight attribute
  411|       |                // "weight 362 5 0.500000 ( -3.553583 11.893474 9.719339 )"
  412|  7.69k|                else if (TokenMatch(sz, "weight", 6)) {
  ------------------
  |  Branch (412:26): [True: 0, False: 7.69k]
  ------------------
  413|      0|                    AI_MD5_SKIP_SPACES(&sz, elem.end, elem.iLineNumber);
  414|      0|                    const unsigned int idx = strtoul10(sz, &sz);
  415|      0|                    AI_MD5_SKIP_SPACES(&sz, elem.end, elem.iLineNumber);
  416|      0|                    if (idx >= desc.mWeights.size())
  ------------------
  |  Branch (416:25): [True: 0, False: 0]
  ------------------
  417|      0|                        desc.mWeights.resize(idx + 1);
  418|       |
  419|      0|                    WeightDesc &weight = desc.mWeights[idx];
  420|      0|                    weight.mBone = strtoul10(sz, &sz);
  421|      0|                    AI_MD5_SKIP_SPACES(&sz, elem.end, elem.iLineNumber);
  422|      0|                    sz = fast_atoreal_move(sz, weight.mWeight);
  423|      0|                    AI_MD5_READ_TRIPLE(weight.vOffsetPosition, &sz, elem.end, elem.iLineNumber);
  424|      0|                }
  425|  7.99k|            }
  426|     61|        }
  427|  1.33k|    }
  428|       |    ASSIMP_LOG_DEBUG("MD5MeshParser end");
  429|      7|}
_ZN6Assimp3MD513MD5AnimParserC2ERNSt3__16vectorINS0_7SectionENS2_9allocatorIS4_EEEE:
  433|      5|MD5AnimParser::MD5AnimParser(SectionArray &mSections) {
  434|      5|    ASSIMP_LOG_DEBUG("MD5AnimParser begin");
  435|       |
  436|      5|    fFrameRate = 24.0f;
  437|      5|    mNumAnimatedComponents = UINT_MAX;
  438|    735|    for (SectionArray::const_iterator iter = mSections.begin(), iterEnd = mSections.end(); iter != iterEnd; ++iter) {
  ------------------
  |  Branch (438:92): [True: 730, False: 5]
  ------------------
  439|    730|        if ((*iter).mName == "hierarchy") {
  ------------------
  |  Branch (439:13): [True: 2, False: 728]
  ------------------
  440|       |            // "sheath" 0 63 6
  441|  5.20k|            for (const auto &elem : (*iter).mElements) {
  ------------------
  |  Branch (441:35): [True: 5.20k, False: 2]
  ------------------
  442|  5.20k|                mAnimatedBones.emplace_back();
  443|  5.20k|                AnimBoneDesc &desc = mAnimatedBones.back();
  444|       |
  445|  5.20k|                const char *sz = elem.szStart;
  446|  5.20k|                AI_MD5_PARSE_STRING_IN_QUOTATION(&sz, elem.end, desc.mName);
  447|  5.20k|                AI_MD5_SKIP_SPACES(&sz, elem.end, elem.iLineNumber);
  448|       |
  449|       |                // parent index - negative values are allowed (at least -1)
  450|  5.20k|                desc.mParentIndex = ::strtol10(sz, &sz);
  451|       |
  452|       |                // flags (highest is 2^6-1)
  453|  5.20k|                AI_MD5_SKIP_SPACES(&sz, elem.end, elem.iLineNumber);
  454|  5.20k|                if (63 < (desc.iFlags = ::strtoul10(sz, &sz))) {
  ------------------
  |  Branch (454:21): [True: 13, False: 5.18k]
  ------------------
  455|     13|                    MD5Parser::ReportWarning("Invalid flag combination in hierarchy section", elem.iLineNumber);
  456|     13|                }
  457|  5.20k|                AI_MD5_SKIP_SPACES(&  sz, elem.end, elem.iLineNumber);
  458|       |
  459|       |                // index of the first animation keyframe component for this joint
  460|  5.20k|                desc.iFirstKeyIndex = ::strtoul10(sz, &sz);
  461|  5.20k|            }
  462|    728|        } else if ((*iter).mName == "baseframe") {
  ------------------
  |  Branch (462:20): [True: 0, False: 728]
  ------------------
  463|       |            // ( -0.000000 0.016430 -0.006044 ) ( 0.707107 0.000242 0.707107 )
  464|      0|            for (const auto &elem : (*iter).mElements) {
  ------------------
  |  Branch (464:35): [True: 0, False: 0]
  ------------------
  465|      0|                const char *sz = elem.szStart;
  466|       |
  467|      0|                mBaseFrames.emplace_back();
  468|      0|                BaseFrameDesc &desc = mBaseFrames.back();
  469|       |
  470|      0|                AI_MD5_READ_TRIPLE(desc.vPositionXYZ, &sz, elem.end, elem.iLineNumber);
  471|      0|                AI_MD5_READ_TRIPLE(desc.vRotationQuat, &sz, elem.end, elem.iLineNumber);
  472|      0|            }
  473|    728|        } else if ((*iter).mName == "frame") {
  ------------------
  |  Branch (473:20): [True: 0, False: 728]
  ------------------
  474|      0|            if (!(*iter).mGlobalValue.length()) {
  ------------------
  |  Branch (474:17): [True: 0, False: 0]
  ------------------
  475|      0|                MD5Parser::ReportWarning("A frame section must have a frame index", (*iter).iLineNumber);
  476|      0|                continue;
  477|      0|            }
  478|       |
  479|      0|            mFrames.emplace_back();
  480|      0|            FrameDesc &desc = mFrames.back();
  481|      0|            desc.iIndex = strtoul10((*iter).mGlobalValue.c_str());
  482|       |
  483|       |            // we do already know how much storage we will presumably need
  484|      0|            if (UINT_MAX != mNumAnimatedComponents) {
  ------------------
  |  Branch (484:17): [True: 0, False: 0]
  ------------------
  485|      0|                desc.mValues.reserve(mNumAnimatedComponents);
  486|      0|            }
  487|       |
  488|       |            // now read all elements (continuous list of floats)
  489|      0|            for (const auto &elem : (*iter).mElements) {
  ------------------
  |  Branch (489:35): [True: 0, False: 0]
  ------------------
  490|      0|                const char *sz = elem.szStart;
  491|      0|                while (SkipSpacesAndLineEnd(&sz, elem.end)) {
  ------------------
  |  Branch (491:24): [True: 0, False: 0]
  ------------------
  492|      0|                    float f;
  493|      0|                    sz = fast_atoreal_move(sz, f);
  494|      0|                    desc.mValues.push_back(f);
  495|      0|                }
  496|      0|            }
  497|    728|        } else if ((*iter).mName == "numFrames") {
  ------------------
  |  Branch (497:20): [True: 0, False: 728]
  ------------------
  498|      0|            mFrames.reserve(strtoul10((*iter).mGlobalValue.c_str()));
  499|    728|        } else if ((*iter).mName == "numJoints") {
  ------------------
  |  Branch (499:20): [True: 0, False: 728]
  ------------------
  500|      0|            const unsigned int num = strtoul10((*iter).mGlobalValue.c_str());
  501|      0|            mAnimatedBones.reserve(num);
  502|       |
  503|       |            // try to guess the number of animated components if that element is not given
  504|      0|            if (UINT_MAX == mNumAnimatedComponents) {
  ------------------
  |  Branch (504:17): [True: 0, False: 0]
  ------------------
  505|      0|                mNumAnimatedComponents = num * 6;
  506|      0|            }
  507|    728|        } else if ((*iter).mName == "numAnimatedComponents") {
  ------------------
  |  Branch (507:20): [True: 0, False: 728]
  ------------------
  508|      0|            mAnimatedBones.reserve(strtoul10((*iter).mGlobalValue.c_str()));
  509|    728|        } else if ((*iter).mName == "frameRate") {
  ------------------
  |  Branch (509:20): [True: 0, False: 728]
  ------------------
  510|      0|            fast_atoreal_move((*iter).mGlobalValue.c_str(), fFrameRate);
  511|      0|        }
  512|    730|    }
  513|       |    ASSIMP_LOG_DEBUG("MD5AnimParser end");
  514|      5|}
_Z32AI_MD5_PARSE_STRING_IN_QUOTATIONPPKcS0_R8aiString:
  289|  5.25k|inline void AI_MD5_PARSE_STRING_IN_QUOTATION(const char **sz, const char *bufferEnd, aiString &out) {
  290|  5.25k|    out.length = 0u;
  291|  40.7k|    while (('\"' != **sz && '\0' != **sz) && *sz != bufferEnd) {
  ------------------
  |  Branch (291:13): [True: 40.6k, False: 99]
  |  Branch (291:29): [True: 35.5k, False: 5.15k]
  |  Branch (291:46): [True: 35.5k, False: 0]
  ------------------
  292|  35.5k|        ++*sz;
  293|  35.5k|    }
  294|  5.25k|    if ('\0' != **sz) {
  ------------------
  |  Branch (294:9): [True: 99, False: 5.15k]
  ------------------
  295|     99|        const char *szStart = ++(*sz);
  296|       |
  297|  1.00k|        while (('\"' != **sz && '\0' != **sz) && *sz != bufferEnd) {
  ------------------
  |  Branch (297:17): [True: 933, False: 74]
  |  Branch (297:33): [True: 908, False: 25]
  |  Branch (297:50): [True: 908, False: 0]
  ------------------
  298|    908|            ++*sz;
  299|    908|        }
  300|     99|        if ('\0' != **sz) {
  ------------------
  |  Branch (300:13): [True: 74, False: 25]
  ------------------
  301|     74|            const char *szEnd = *sz;
  302|     74|            ++*sz;
  303|     74|            out.length = (ai_uint32)(szEnd - szStart);
  304|     74|            if (out.length >= AI_MAXLEN)
  ------------------
  |  Branch (304:17): [True: 0, False: 74]
  ------------------
  305|      0|                out.length = AI_MAXLEN - 1;
  306|     74|            ::memcpy(out.data, szStart, out.length);
  307|     74|        }
  308|     99|    }
  309|  5.25k|    out.data[out.length] = '\0';
  310|  5.25k|}
_Z18AI_MD5_SKIP_SPACESPPKcS0_i:
  230|  16.6k|inline void AI_MD5_SKIP_SPACES(const char **sz, const char *bufferEnd, int linenumber) {
  231|  16.6k|    if (!SkipSpaces(sz, bufferEnd)) {
  ------------------
  |  Branch (231:9): [True: 15.5k, False: 1.08k]
  ------------------
  232|  15.5k|        MD5Parser::ReportWarning("Unexpected end of line", linenumber);
  233|  15.5k|    }
  234|  16.6k|}
_Z18AI_MD5_READ_TRIPLER10aiVector3tIfEPPKcS3_i:
  237|      2|inline void AI_MD5_READ_TRIPLE(aiVector3D &vec, const char **sz, const char *bufferEnd, int linenumber) {
  238|      2|    AI_MD5_SKIP_SPACES(sz, bufferEnd, linenumber);
  239|      2|    if ('(' != **sz) {
  ------------------
  |  Branch (239:9): [True: 2, False: 0]
  ------------------
  240|      2|        MD5Parser::ReportWarning("Unexpected token: ( was expected", linenumber);
  241|      2|        if (*sz == bufferEnd)
  ------------------
  |  Branch (241:13): [True: 0, False: 2]
  ------------------
  242|      0|            return;
  243|      2|        ++*sz;
  244|      2|    }
  245|      2|    if (*sz == bufferEnd)
  ------------------
  |  Branch (245:9): [True: 0, False: 2]
  ------------------
  246|      0|        return;
  247|      2|    ++*sz;
  248|      2|    AI_MD5_SKIP_SPACES(sz, bufferEnd, linenumber);
  249|      2|    *sz = fast_atoreal_move(*sz, vec.x);
  250|      2|    AI_MD5_SKIP_SPACES(sz, bufferEnd, linenumber);
  251|      2|    *sz = fast_atoreal_move(*sz, vec.y);
  252|      2|    AI_MD5_SKIP_SPACES(sz, bufferEnd, linenumber);
  253|      2|    *sz = fast_atoreal_move(*sz, vec.z);
  254|      2|    AI_MD5_SKIP_SPACES(sz, bufferEnd, linenumber);
  255|      2|    if (')' != **sz) {
  ------------------
  |  Branch (255:9): [True: 0, False: 2]
  ------------------
  256|      0|        MD5Parser::ReportWarning("Unexpected token: ) was expected", linenumber);
  257|      0|    }
  258|      2|    if (*sz == bufferEnd)
  ------------------
  |  Branch (258:9): [True: 0, False: 2]
  ------------------
  259|      0|        return;
  260|      2|    ++*sz;
  261|      2|}

_ZN6Assimp3MD510VertexDescC2Ev:
  189|    160|            : mFirstWeight(0), mNumWeights(0) {
  190|       |        // empty
  191|    160|    }
_ZN6Assimp3MD59MD5Parser8SkipLineEPKcPS3_:
  409|     12|inline bool MD5Parser::SkipLine(const char* in, const char** out) {
  410|     12|    ++lineNumber;
  411|     12|    return Assimp::SkipLine(in, out, bufferEnd);
  412|     12|}
_ZN6Assimp3MD59MD5Parser8SkipLineEv:
  415|     12|inline bool MD5Parser::SkipLine( ) {
  416|     12|    return SkipLine(buffer,(const char**)&buffer);
  417|     12|}
_ZN6Assimp3MD59MD5Parser20SkipSpacesAndLineEndEPKcPS3_:
  420|     12|inline bool MD5Parser::SkipSpacesAndLineEnd( const char* in, const char** out) {
  421|     12|    if (in == bufferEnd) {
  ------------------
  |  Branch (421:9): [True: 0, False: 12]
  ------------------
  422|      0|        *out = in;
  423|      0|        return false;
  424|      0|    }
  425|       |
  426|     12|    bool bHad = false, running = true;
  427|     12|    while (running) {
  ------------------
  |  Branch (427:12): [True: 12, False: 0]
  ------------------
  428|     12|        if( *in == '\r' || *in == '\n') {
  ------------------
  |  Branch (428:13): [True: 0, False: 12]
  |  Branch (428:28): [True: 0, False: 12]
  ------------------
  429|       |            // we open files in binary mode, so there could be \r\n sequences ...
  430|      0|            if (!bHad)  {
  ------------------
  |  Branch (430:17): [True: 0, False: 0]
  ------------------
  431|      0|                bHad = true;
  432|      0|                ++lineNumber;
  433|      0|            }
  434|     12|        } else if (*in == '\t' || *in == ' ') {
  ------------------
  |  Branch (434:20): [True: 0, False: 12]
  |  Branch (434:35): [True: 0, False: 12]
  ------------------
  435|      0|            bHad = false;
  436|     12|        } else {
  437|     12|            break;
  438|     12|        }
  439|      0|        ++in;
  440|      0|        if (in == bufferEnd) {
  ------------------
  |  Branch (440:13): [True: 0, False: 0]
  ------------------
  441|      0|            break;
  442|      0|        }
  443|      0|    }
  444|     12|    *out = in;
  445|     12|    return *in != '\0';
  446|     12|}
_ZN6Assimp3MD59MD5Parser20SkipSpacesAndLineEndEv:
  449|     12|inline bool MD5Parser::SkipSpacesAndLineEnd() {
  450|     12|    return SkipSpacesAndLineEnd(buffer,(const char**)&buffer);
  451|     12|}
_ZN6Assimp3MD59MD5Parser10SkipSpacesEv:
  454|     24|inline bool MD5Parser::SkipSpaces() {
  455|     24|    return Assimp::SkipSpaces((const char**)&buffer, bufferEnd);
  456|     24|}

_ZN6Assimp11MDCImporterC2Ev:
  102|    624|        fileSize() {
  103|       |    // empty
  104|    624|}
_ZNK6Assimp11MDCImporter7CanReadERKNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEPNS_8IOSystemEb:
  108|    410|bool MDCImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool /*checkSig*/) const {
  109|    410|    static constexpr uint32_t tokens[] = { AI_MDC_MAGIC_NUMBER_LE };
  ------------------
  |  |   65|    410|#define AI_MDC_MAGIC_NUMBER_LE  AI_MAKE_MAGIC("IDPC")
  ------------------
  110|       |    return CheckMagicToken(pIOHandler, pFile, tokens, AI_COUNT_OF(tokens));
  111|    410|}
_ZNK6Assimp11MDCImporter7GetInfoEv:
  114|    635|const aiImporterDesc *MDCImporter::GetInfo() const {
  115|    635|    return &desc;
  116|    635|}
_ZN6Assimp11MDCImporter14ValidateHeaderEv:
  120|      1|void MDCImporter::ValidateHeader() {
  121|      1|    AI_SWAP4(this->pcHeader->ulVersion);
  122|      1|    AI_SWAP4(this->pcHeader->ulFlags);
  123|      1|    AI_SWAP4(this->pcHeader->ulNumFrames);
  124|      1|    AI_SWAP4(this->pcHeader->ulNumTags);
  125|      1|    AI_SWAP4(this->pcHeader->ulNumSurfaces);
  126|      1|    AI_SWAP4(this->pcHeader->ulNumSkins);
  127|      1|    AI_SWAP4(this->pcHeader->ulOffsetBorderFrames);
  128|       |
  129|      1|    if (pcHeader->ulIdent != AI_MDC_MAGIC_NUMBER_BE &&
  ------------------
  |  |   64|      1|#define AI_MDC_MAGIC_NUMBER_BE  AI_MAKE_MAGIC("CPDI")
  ------------------
  |  Branch (129:9): [True: 0, False: 1]
  ------------------
  130|      0|            pcHeader->ulIdent != AI_MDC_MAGIC_NUMBER_LE) {
  ------------------
  |  |   65|      0|#define AI_MDC_MAGIC_NUMBER_LE  AI_MAKE_MAGIC("IDPC")
  ------------------
  |  Branch (130:13): [True: 0, False: 0]
  ------------------
  131|      0|        throw DeadlyImportError("Invalid MDC magic word: expected IDPC, found ",
  132|      0|                                ai_str_toprintable((char *)&pcHeader->ulIdent, 4));
  133|      0|    }
  134|       |
  135|      1|    if (pcHeader->ulVersion != AI_MDC_VERSION) {
  ------------------
  |  |   68|      1|#define AI_MDC_VERSION          2
  ------------------
  |  Branch (135:9): [True: 0, False: 1]
  ------------------
  136|      0|        ASSIMP_LOG_WARN("Unsupported MDC file version (2 (AI_MDC_VERSION) was expected)");
  137|      0|    }
  138|       |
  139|      1|    if (pcHeader->ulOffsetBorderFrames + pcHeader->ulNumFrames * sizeof(MDC::Frame) > this->fileSize ||
  ------------------
  |  Branch (139:9): [True: 0, False: 1]
  ------------------
  140|      1|            pcHeader->ulOffsetSurfaces + pcHeader->ulNumSurfaces * sizeof(MDC::Surface) > this->fileSize) {
  ------------------
  |  Branch (140:13): [True: 0, False: 1]
  ------------------
  141|      0|        throw DeadlyImportError("Some of the offset values in the MDC header are invalid "
  142|      0|                                "and point to something behind the file.");
  143|      0|    }
  144|       |
  145|      1|    if (this->configFrameID >= this->pcHeader->ulNumFrames) {
  ------------------
  |  Branch (145:9): [True: 0, False: 1]
  ------------------
  146|      0|        throw DeadlyImportError("The requested frame is not available");
  147|      0|    }
  148|      1|}
_ZN6Assimp11MDCImporter21ValidateSurfaceHeaderEPKNS_3MDC7SurfaceE:
  152|     19|void MDCImporter::ValidateSurfaceHeader(BE_NCONST MDC::Surface *pcSurf) {
  153|     19|    AI_SWAP4(pcSurf->ulFlags);
  154|     19|    AI_SWAP4(pcSurf->ulNumCompFrames);
  155|     19|    AI_SWAP4(pcSurf->ulNumBaseFrames);
  156|     19|    AI_SWAP4(pcSurf->ulNumShaders);
  157|     19|    AI_SWAP4(pcSurf->ulNumVertices);
  158|     19|    AI_SWAP4(pcSurf->ulNumTriangles);
  159|     19|    AI_SWAP4(pcSurf->ulOffsetTriangles);
  160|     19|    AI_SWAP4(pcSurf->ulOffsetTexCoords);
  161|     19|    AI_SWAP4(pcSurf->ulOffsetBaseVerts);
  162|     19|    AI_SWAP4(pcSurf->ulOffsetCompVerts);
  163|     19|    AI_SWAP4(pcSurf->ulOffsetShaders);
  164|     19|    AI_SWAP4(pcSurf->ulOffsetFrameBaseFrames);
  165|     19|    AI_SWAP4(pcSurf->ulOffsetFrameCompFrames);
  166|     19|    AI_SWAP4(pcSurf->ulOffsetEnd);
  167|       |
  168|     19|    const unsigned int iMax = this->fileSize - (unsigned int)((int8_t *)pcSurf - (int8_t *)pcHeader);
  169|       |
  170|     19|    if (pcSurf->ulOffsetBaseVerts + pcSurf->ulNumVertices * sizeof(MDC::BaseVertex) > iMax ||
  ------------------
  |  Branch (170:9): [True: 0, False: 19]
  ------------------
  171|     19|            (pcSurf->ulNumCompFrames && pcSurf->ulOffsetCompVerts + pcSurf->ulNumVertices * sizeof(MDC::CompressedVertex) > iMax) ||
  ------------------
  |  Branch (171:14): [True: 19, False: 0]
  |  Branch (171:41): [True: 0, False: 19]
  ------------------
  172|     19|            pcSurf->ulOffsetTriangles + pcSurf->ulNumTriangles * sizeof(MDC::Triangle) > iMax ||
  ------------------
  |  Branch (172:13): [True: 0, False: 19]
  ------------------
  173|     19|            pcSurf->ulOffsetTexCoords + pcSurf->ulNumVertices * sizeof(MDC::TexturCoord) > iMax ||
  ------------------
  |  Branch (173:13): [True: 0, False: 19]
  ------------------
  174|     19|            pcSurf->ulOffsetShaders + pcSurf->ulNumShaders * sizeof(MDC::Shader) > iMax ||
  ------------------
  |  Branch (174:13): [True: 0, False: 19]
  ------------------
  175|     19|            pcSurf->ulOffsetFrameBaseFrames + pcSurf->ulNumBaseFrames * 2 > iMax ||
  ------------------
  |  Branch (175:13): [True: 0, False: 19]
  ------------------
  176|     19|            (pcSurf->ulNumCompFrames && pcSurf->ulOffsetFrameCompFrames + pcSurf->ulNumCompFrames * 2 > iMax) ||
  ------------------
  |  Branch (176:14): [True: 19, False: 0]
  |  Branch (176:41): [True: 0, False: 19]
  ------------------
  177|     19|            pcSurf->ulOffsetEnd > iMax) {
  ------------------
  |  Branch (177:13): [True: 0, False: 19]
  ------------------
  178|      0|        throw DeadlyImportError("Some of the offset values in the MDC surface header "
  179|      0|                                "are invalid and point somewhere behind the file.");
  180|      0|    }
  181|     19|}
_ZN6Assimp11MDCImporter15SetupPropertiesEPKNS_8ImporterE:
  185|      1|void MDCImporter::SetupProperties(const Importer *pImp) {
  186|       |    // The AI_CONFIG_IMPORT_MDC_KEYFRAME option overrides the
  187|       |    // AI_CONFIG_IMPORT_GLOBAL_KEYFRAME option.
  188|      1|    if (static_cast<unsigned int>(-1) == (configFrameID = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_MDC_KEYFRAME, -1))) {
  ------------------
  |  Branch (188:9): [True: 1, False: 0]
  ------------------
  189|       |        configFrameID = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_GLOBAL_KEYFRAME, 0);
  190|      1|    }
  191|      1|}
_ZN6Assimp11MDCImporter14InternReadFileERKNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEP7aiScenePNS_8IOSystemE:
  196|      1|        const std::string &pFile, aiScene *pScene, IOSystem *pIOHandler) {
  197|      1|    std::unique_ptr<IOStream> file(pIOHandler->Open(pFile));
  198|       |
  199|       |    // Check whether we can read from the file
  200|      1|    if (file == nullptr) {
  ------------------
  |  Branch (200:9): [True: 0, False: 1]
  ------------------
  201|      0|        throw DeadlyImportError("Failed to open MDC file ", pFile, ".");
  202|      0|    }
  203|       |
  204|       |    // check whether the mdc file is large enough to contain the file header
  205|      1|    fileSize = static_cast<unsigned int>(file->FileSize());
  206|      1|    if (fileSize < sizeof(MDC::Header)) {
  ------------------
  |  Branch (206:9): [True: 0, False: 1]
  ------------------
  207|      0|        throw DeadlyImportError("MDC File is too small.");
  208|      0|    }
  209|       |
  210|      1|    std::vector<unsigned char> mBuffer2(fileSize);
  211|      1|    file->Read(&mBuffer2[0], 1, fileSize);
  212|      1|    mBuffer = &mBuffer2[0];
  213|       |
  214|       |    // validate the file header
  215|      1|    this->pcHeader = (BE_NCONST MDC::Header *)this->mBuffer;
  216|      1|    this->ValidateHeader();
  217|       |
  218|      1|    std::vector<std::string> aszShaders;
  219|       |
  220|       |    // get a pointer to the frame we want to read
  221|      1|    BE_NCONST MDC::Frame *pcFrame = (BE_NCONST MDC::Frame *)(this->mBuffer +
  222|      1|                                                             this->pcHeader->ulOffsetBorderFrames);
  223|       |
  224|       |    // no need to swap the other members, we won't need them
  225|      1|    pcFrame += configFrameID;
  226|      1|    AI_SWAP4(pcFrame->localOrigin[0]);
  227|      1|    AI_SWAP4(pcFrame->localOrigin[1]);
  228|      1|    AI_SWAP4(pcFrame->localOrigin[2]);
  229|       |
  230|       |    // get the number of valid surfaces
  231|      1|    BE_NCONST MDC::Surface *pcSurface, *pcSurface2;
  232|      1|    pcSurface = pcSurface2 = reinterpret_cast<BE_NCONST MDC::Surface *>(mBuffer + pcHeader->ulOffsetSurfaces);
  233|      1|    unsigned int iNumShaders = 0;
  234|     20|    for (unsigned int i = 0; i < pcHeader->ulNumSurfaces; ++i) {
  ------------------
  |  Branch (234:30): [True: 19, False: 1]
  ------------------
  235|       |        // validate the surface header
  236|     19|        this->ValidateSurfaceHeader(pcSurface2);
  237|       |
  238|     19|        if (pcSurface2->ulNumVertices && pcSurface2->ulNumTriangles) {
  ------------------
  |  Branch (238:13): [True: 19, False: 0]
  |  Branch (238:42): [True: 19, False: 0]
  ------------------
  239|     19|            ++pScene->mNumMeshes;
  240|     19|        }
  241|     19|        iNumShaders += pcSurface2->ulNumShaders;
  242|     19|        pcSurface2 = reinterpret_cast<BE_NCONST MDC::Surface *>((BE_NCONST int8_t *)pcSurface2 + pcSurface2->ulOffsetEnd);
  243|     19|    }
  244|      1|    aszShaders.reserve(iNumShaders);
  245|      1|    pScene->mMeshes = new aiMesh *[pScene->mNumMeshes];
  246|       |
  247|       |    // necessary that we don't crash if an exception occurs
  248|     20|    for (unsigned int i = 0; i < pScene->mNumMeshes; ++i) {
  ------------------
  |  Branch (248:30): [True: 19, False: 1]
  ------------------
  249|     19|        pScene->mMeshes[i] = nullptr;
  250|     19|    }
  251|       |
  252|       |    // now read all surfaces
  253|      1|    unsigned int iDefaultMatIndex = UINT_MAX;
  254|     20|    for (unsigned int i = 0, iNum = 0; i < pcHeader->ulNumSurfaces; ++i) {
  ------------------
  |  Branch (254:40): [True: 19, False: 1]
  ------------------
  255|     19|        if (!pcSurface->ulNumVertices || !pcSurface->ulNumTriangles) continue;
  ------------------
  |  Branch (255:13): [True: 0, False: 19]
  |  Branch (255:42): [True: 0, False: 19]
  ------------------
  256|     19|        aiMesh *pcMesh = pScene->mMeshes[iNum++] = new aiMesh();
  257|       |
  258|     19|        pcMesh->mNumFaces = pcSurface->ulNumTriangles;
  259|     19|        pcMesh->mNumVertices = pcMesh->mNumFaces * 3;
  260|       |
  261|       |        // store the name of the surface for use as node name.
  262|     19|        pcMesh->mName.Set(std::string(pcSurface->ucName, strnlen(pcSurface->ucName, AI_MDC_MAXQPATH - 1)));
  ------------------
  |  |   69|     19|#define AI_MDC_MAXQPATH         64
  ------------------
  263|       |
  264|       |        // go to the first shader in the file. ignore the others.
  265|     19|        if (pcSurface->ulNumShaders) {
  ------------------
  |  Branch (265:13): [True: 19, False: 0]
  ------------------
  266|     19|            const MDC::Shader *pcShader = (const MDC::Shader *)((int8_t *)pcSurface + pcSurface->ulOffsetShaders);
  267|     19|            pcMesh->mMaterialIndex = (unsigned int)aszShaders.size();
  268|       |
  269|       |            // create a new shader
  270|     19|            aszShaders.emplace_back(pcShader->ucName,
  271|     19|                    ::strnlen(pcShader->ucName, sizeof(pcShader->ucName)));
  272|     19|        }
  273|       |        // need to create a default material
  274|      0|        else if (UINT_MAX == iDefaultMatIndex) {
  ------------------
  |  Branch (274:18): [True: 0, False: 0]
  ------------------
  275|      0|            pcMesh->mMaterialIndex = iDefaultMatIndex = (unsigned int)aszShaders.size();
  276|      0|            aszShaders.emplace_back();
  277|      0|        }
  278|       |        // otherwise assign a reference to the default material
  279|      0|        else
  280|      0|            pcMesh->mMaterialIndex = iDefaultMatIndex;
  281|       |
  282|       |        // allocate output storage for the mesh
  283|     19|        aiVector3D *pcVertCur = pcMesh->mVertices = new aiVector3D[pcMesh->mNumVertices];
  284|     19|        aiVector3D *pcNorCur = pcMesh->mNormals = new aiVector3D[pcMesh->mNumVertices];
  285|     19|        aiVector3D *pcUVCur = pcMesh->mTextureCoords[0] = new aiVector3D[pcMesh->mNumVertices];
  286|     19|        aiFace *pcFaceCur = pcMesh->mFaces = new aiFace[pcMesh->mNumFaces];
  287|       |
  288|       |        // create all vertices/faces
  289|     19|        BE_NCONST MDC::Triangle *pcTriangle = (BE_NCONST MDC::Triangle *)((int8_t *)pcSurface + pcSurface->ulOffsetTriangles);
  290|       |
  291|     19|        BE_NCONST MDC::TexturCoord *const pcUVs = (BE_NCONST MDC::TexturCoord *)((int8_t *)pcSurface + pcSurface->ulOffsetTexCoords);
  292|       |
  293|       |        // get a pointer to the uncompressed vertices
  294|     19|        int16_t iOfs = *((int16_t *)((int8_t *)pcSurface +
  295|     19|                                     pcSurface->ulOffsetFrameBaseFrames) +
  296|     19|                         this->configFrameID);
  297|       |
  298|     19|        AI_SWAP2(iOfs);
  299|       |
  300|     19|        BE_NCONST MDC::BaseVertex *const pcVerts = (BE_NCONST MDC::BaseVertex *)((int8_t *)pcSurface + pcSurface->ulOffsetBaseVerts) +
  301|     19|                                                   ((int)iOfs * pcSurface->ulNumVertices * 4);
  302|       |
  303|       |        // do the main swapping stuff ...
  304|       |#if (defined AI_BUILD_BIG_ENDIAN)
  305|       |
  306|       |        // swap all triangles
  307|       |        for (unsigned int i = 0; i < pcSurface->ulNumTriangles; ++i) {
  308|       |            AI_SWAP4(pcTriangle[i].aiIndices[0]);
  309|       |            AI_SWAP4(pcTriangle[i].aiIndices[1]);
  310|       |            AI_SWAP4(pcTriangle[i].aiIndices[2]);
  311|       |        }
  312|       |
  313|       |        // swap all vertices
  314|       |        for (unsigned int i = 0; i < pcSurface->ulNumVertices * pcSurface->ulNumBaseFrames; ++i) {
  315|       |            AI_SWAP2(pcVerts->normal);
  316|       |            AI_SWAP2(pcVerts->x);
  317|       |            AI_SWAP2(pcVerts->y);
  318|       |            AI_SWAP2(pcVerts->z);
  319|       |        }
  320|       |
  321|       |        // swap all texture coordinates
  322|       |        for (unsigned int i = 0; i < pcSurface->ulNumVertices; ++i) {
  323|       |            AI_SWAP4(pcUVs->u);
  324|       |            AI_SWAP4(pcUVs->v);
  325|       |        }
  326|       |
  327|       |#endif
  328|       |
  329|       |        // boundary check for pcVerts
  330|     19|        auto surfStart = reinterpret_cast<const uint8_t*>(pcSurface);
  331|     19|        const uint8_t* surfEnd = surfStart + pcSurface->ulOffsetEnd;
  332|     19|        auto vertBufStart = reinterpret_cast<const uint8_t*>(pcVerts);
  333|     19|        const size_t needVertBytes = sizeof(MDC::BaseVertex) * pcSurface->ulNumVertices;
  334|     19|        if (vertBufStart < surfStart || vertBufStart + needVertBytes > surfEnd) {
  ------------------
  |  Branch (334:13): [True: 0, False: 19]
  |  Branch (334:41): [True: 0, False: 19]
  ------------------
  335|      0|            throw DeadlyImportError("MDCImporter: pcVerts points outside of surface block.");
  336|      0|        }
  337|       |
  338|     19|        const MDC::CompressedVertex *pcCVerts = nullptr;
  339|     19|        int16_t *mdcCompVert = nullptr;
  340|       |
  341|       |        // access compressed frames for large frame numbers, but never for the first
  342|     19|        if (this->configFrameID && pcSurface->ulNumCompFrames > 0) {
  ------------------
  |  Branch (342:13): [True: 0, False: 19]
  |  Branch (342:36): [True: 0, False: 0]
  ------------------
  343|      0|            mdcCompVert = (int16_t *)((int8_t *)pcSurface + pcSurface->ulOffsetFrameCompFrames) + this->configFrameID;
  344|      0|            AI_SWAP2P(mdcCompVert);
  345|      0|            if (*mdcCompVert >= 0) {
  ------------------
  |  Branch (345:17): [True: 0, False: 0]
  ------------------
  346|      0|                pcCVerts = (const MDC::CompressedVertex *)((int8_t *)pcSurface +
  347|      0|                                                           pcSurface->ulOffsetCompVerts) +
  348|      0|                           *mdcCompVert * pcSurface->ulNumVertices;
  349|      0|                auto cvertBufStart = reinterpret_cast<const uint8_t*>(pcCVerts);
  350|      0|                const size_t needCompVertBytes = sizeof(MDC::CompressedVertex) * pcSurface->ulNumVertices;
  351|      0|                if (cvertBufStart < surfStart || cvertBufStart > surfEnd ||
  ------------------
  |  Branch (351:21): [True: 0, False: 0]
  |  Branch (351:50): [True: 0, False: 0]
  ------------------
  352|      0|                    needCompVertBytes > static_cast<size_t>(surfEnd - cvertBufStart)) {
  ------------------
  |  Branch (352:21): [True: 0, False: 0]
  ------------------
  353|      0|                    throw DeadlyImportError("MDCImporter: pcCVerts points outside of surface block.");
  354|      0|                }
  355|      0|            } else
  356|      0|                mdcCompVert = nullptr;
  357|      0|        }
  358|       |
  359|       |        // copy all faces
  360|  1.38k|        for (unsigned int iFace = 0; iFace < pcSurface->ulNumTriangles; ++iFace,
  ------------------
  |  Branch (360:38): [True: 1.36k, False: 19]
  ------------------
  361|  1.36k|                          ++pcTriangle, ++pcFaceCur) {
  362|  1.36k|            const unsigned int iOutIndex = iFace * 3;
  363|  1.36k|            pcFaceCur->mNumIndices = 3;
  364|  1.36k|            pcFaceCur->mIndices = new unsigned int[3];
  365|       |
  366|  5.47k|            for (unsigned int iIndex = 0; iIndex < 3; ++iIndex,
  ------------------
  |  Branch (366:43): [True: 4.10k, False: 1.36k]
  ------------------
  367|  4.10k|                              ++pcVertCur, ++pcUVCur, ++pcNorCur) {
  368|  4.10k|                uint32_t quak = pcTriangle->aiIndices[iIndex];
  369|  4.10k|                if (quak >= pcSurface->ulNumVertices) {
  ------------------
  |  Branch (369:21): [True: 0, False: 4.10k]
  ------------------
  370|      0|                    ASSIMP_LOG_ERROR("MDC vertex index is out of range");
  371|      0|                    quak = pcSurface->ulNumVertices - 1;
  372|      0|                }
  373|       |
  374|       |                // compressed vertices?
  375|  4.10k|                if (mdcCompVert) {
  ------------------
  |  Branch (375:21): [True: 0, False: 4.10k]
  ------------------
  376|      0|                    MDC::BuildVertex(*pcFrame, pcVerts[quak], pcCVerts[quak],
  377|      0|                            *pcVertCur, *pcNorCur);
  378|  4.10k|                } else {
  379|       |                    // copy position
  380|  4.10k|                    pcVertCur->x = pcVerts[quak].x * AI_MDC_BASE_SCALING;
  ------------------
  |  |   74|  4.10k|#define AI_MDC_BASE_SCALING     (1.0f / 64.0f)
  ------------------
  381|  4.10k|                    pcVertCur->y = pcVerts[quak].y * AI_MDC_BASE_SCALING;
  ------------------
  |  |   74|  4.10k|#define AI_MDC_BASE_SCALING     (1.0f / 64.0f)
  ------------------
  382|  4.10k|                    pcVertCur->z = pcVerts[quak].z * AI_MDC_BASE_SCALING;
  ------------------
  |  |   74|  4.10k|#define AI_MDC_BASE_SCALING     (1.0f / 64.0f)
  ------------------
  383|       |
  384|       |                    // copy normals
  385|  4.10k|                    MD3::LatLngNormalToVec3(pcVerts[quak].normal, &pcNorCur->x);
  386|       |
  387|       |                    // copy texture coordinates
  388|  4.10k|                    pcUVCur->x = pcUVs[quak].u;
  389|  4.10k|                    pcUVCur->y = ai_real(1.0) - pcUVs[quak].v; // DX to OGL
  390|  4.10k|                }
  391|  4.10k|                pcVertCur->x += pcFrame->localOrigin[0];
  392|  4.10k|                pcVertCur->y += pcFrame->localOrigin[1];
  393|  4.10k|                pcVertCur->z += pcFrame->localOrigin[2];
  394|  4.10k|            }
  395|       |
  396|       |            // swap the face order - DX to OGL
  397|  1.36k|            pcFaceCur->mIndices[0] = iOutIndex + 2;
  398|  1.36k|            pcFaceCur->mIndices[1] = iOutIndex + 1;
  399|  1.36k|            pcFaceCur->mIndices[2] = iOutIndex + 0;
  400|  1.36k|        }
  401|       |
  402|     19|        pcSurface = reinterpret_cast<BE_NCONST MDC::Surface *>((BE_NCONST int8_t *)pcSurface + pcSurface->ulOffsetEnd);
  403|     19|    }
  404|       |
  405|       |    // create a flat node graph with a root node and one child for each surface
  406|      1|    if (!pScene->mNumMeshes)
  ------------------
  |  Branch (406:9): [True: 0, False: 1]
  ------------------
  407|      0|        throw DeadlyImportError("Invalid MDC file: File contains no valid mesh");
  408|      1|    else if (1 == pScene->mNumMeshes) {
  ------------------
  |  Branch (408:14): [True: 0, False: 1]
  ------------------
  409|      0|        pScene->mRootNode = new aiNode();
  410|      0|        if (nullptr != pScene->mMeshes[0]) {
  ------------------
  |  Branch (410:13): [True: 0, False: 0]
  ------------------
  411|      0|            pScene->mRootNode->mName = pScene->mMeshes[0]->mName;
  412|      0|            pScene->mRootNode->mNumMeshes = 1;
  413|      0|            pScene->mRootNode->mMeshes = new unsigned int[1];
  414|      0|            pScene->mRootNode->mMeshes[0] = 0;
  415|      0|        }
  416|      1|    } else {
  417|      1|        pScene->mRootNode = new aiNode();
  418|      1|        pScene->mRootNode->mNumChildren = pScene->mNumMeshes;
  419|      1|        pScene->mRootNode->mChildren = new aiNode *[pScene->mNumMeshes];
  420|      1|        pScene->mRootNode->mName.Set("<root>");
  421|     20|        for (unsigned int i = 0; i < pScene->mNumMeshes; ++i) {
  ------------------
  |  Branch (421:34): [True: 19, False: 1]
  ------------------
  422|     19|            aiNode *pcNode = pScene->mRootNode->mChildren[i] = new aiNode();
  423|     19|            pcNode->mParent = pScene->mRootNode;
  424|     19|            pcNode->mName = pScene->mMeshes[i]->mName;
  425|     19|            pcNode->mNumMeshes = 1;
  426|     19|            pcNode->mMeshes = new unsigned int[1];
  427|     19|            pcNode->mMeshes[0] = i;
  428|     19|        }
  429|      1|    }
  430|       |
  431|       |    // create materials
  432|      1|    pScene->mNumMaterials = (unsigned int)aszShaders.size();
  433|      1|    pScene->mMaterials = new aiMaterial *[pScene->mNumMaterials];
  434|     20|    for (unsigned int i = 0; i < pScene->mNumMaterials; ++i) {
  ------------------
  |  Branch (434:30): [True: 19, False: 1]
  ------------------
  435|     19|        aiMaterial *pcMat = new aiMaterial();
  436|     19|        pScene->mMaterials[i] = pcMat;
  437|       |
  438|     19|        const std::string &name = aszShaders[i];
  439|       |
  440|     19|        int iMode = (int)aiShadingMode_Gouraud;
  441|     19|        pcMat->AddProperty<int>(&iMode, 1, AI_MATKEY_SHADING_MODEL);
  442|       |
  443|       |        // add a small ambient color value - RtCW seems to have one
  444|     19|        aiColor3D clr;
  445|     19|        clr.b = clr.g = clr.r = 0.05f;
  446|     19|        pcMat->AddProperty<aiColor3D>(&clr, 1, AI_MATKEY_COLOR_AMBIENT);
  447|       |
  448|     19|        if (name.length())
  ------------------
  |  Branch (448:13): [True: 19, False: 0]
  ------------------
  449|     19|            clr.b = clr.g = clr.r = 1.0f;
  450|      0|        else
  451|      0|            clr.b = clr.g = clr.r = 0.6f;
  452|       |
  453|     19|        pcMat->AddProperty<aiColor3D>(&clr, 1, AI_MATKEY_COLOR_DIFFUSE);
  454|     19|        pcMat->AddProperty<aiColor3D>(&clr, 1, AI_MATKEY_COLOR_SPECULAR);
  455|       |
  456|     19|        if (name.length()) {
  ------------------
  |  Branch (456:13): [True: 19, False: 0]
  ------------------
  457|     19|            aiString path;
  458|     19|            path.Set(name);
  459|     19|            pcMat->AddProperty(&path, AI_MATKEY_TEXTURE_DIFFUSE(0));
  460|     19|        }
  461|     19|    }
  462|       |
  463|       |    // Now rotate the whole scene 90 degrees around the x axis to convert to internal coordinate system
  464|      1|    pScene->mRootNode->mTransformation = aiMatrix4x4(
  465|      1|            1.f, 0.f, 0.f, 0.f,
  466|      1|            0.f, 0.f, 1.f, 0.f,
  467|      1|            0.f, -1.f, 0.f, 0.f,
  468|      1|            0.f, 0.f, 0.f, 1.f);
  469|      1|}

_ZN6Assimp3MDL8HalfLife13HL1DataBufferC2Ev:
   70|     31|    HL1DataBuffer() AI_NO_EXCEPT : data_(nullptr),
   71|     31|                                   length_(0),
   72|     31|                                   owner_(nullptr) {}
_ZN6Assimp3MDL8HalfLife13HL1DataBufferaSEOS2_:
   90|     13|    HL1DataBuffer &operator=(HL1DataBuffer &&other) AI_NO_EXCEPT {
   91|     13|        if (this != &other) {
  ------------------
  |  Branch (91:13): [True: 13, False: 0]
  ------------------
   92|     13|            data_ = other.data_;
   93|     13|            length_ = other.length_;
   94|     13|            owner_ = std::move(other.owner_);
   95|       |
   96|     13|            other.data_ = nullptr;
   97|     13|            other.length_ = 0;
   98|     13|            other.owner_ = nullptr;
   99|     13|        }
  100|       |
  101|     13|        return *this;
  102|     13|    }
_ZN6Assimp3MDL8HalfLife13HL1DataBuffer4viewEPKhm:
  110|      4|    static HL1DataBuffer view(const unsigned char *data, size_t length) {
  111|      4|        HL1DataBuffer b;
  112|      4|        b.data_ = data;
  113|      4|        b.length_ = length;
  114|      4|        b.owner_ = nullptr;
  115|      4|        return b;
  116|      4|    }
_ZN6Assimp3MDL8HalfLife13HL1DataBuffer4viewERKS2_:
  123|      4|    static HL1DataBuffer view(const HL1DataBuffer &other) {
  124|      4|        HL1DataBuffer b;
  125|      4|        b.data_ = other.data_;
  126|      4|        b.length_ = other.length_;
  127|      4|        b.owner_ = nullptr;
  128|      4|        return b;
  129|      4|    }
_ZN6Assimp3MDL8HalfLife13HL1DataBuffer6owningENSt3__110unique_ptrIA_hNS3_14default_deleteIS5_EEEEm:
  137|      9|    static HL1DataBuffer owning(std::unique_ptr<unsigned char[]> buffer, size_t length) {
  138|      9|        HL1DataBuffer b;
  139|      9|        b.data_ = buffer.get();
  140|      9|        b.length_ = length;
  141|      9|        b.owner_ = std::move(buffer);
  142|      9|        return b;
  143|      9|    }
_ZNK6Assimp3MDL8HalfLife13HL1DataBuffer8get_dataINS1_10Header_HL1EEEPKT_ii:
  154|      8|    const DataType *get_data(int offset, int elements) const {
  155|      8|        if (offset < 0 || elements < 0) {
  ------------------
  |  Branch (155:13): [True: 0, False: 8]
  |  Branch (155:27): [True: 0, False: 8]
  ------------------
  156|      0|            throw DeadlyImportError("MDL file contains invalid data");
  157|      0|        }
  158|       |
  159|      8|        const size_t uoffset = static_cast<size_t>(offset);
  160|      8|        const size_t uelements = static_cast<size_t>(elements);
  161|       |
  162|      8|        if (uoffset > length_ || uelements > (length_ - uoffset) / sizeof(DataType)) {
  ------------------
  |  Branch (162:13): [True: 0, False: 8]
  |  Branch (162:34): [True: 0, False: 8]
  ------------------
  163|      0|            throw DeadlyImportError("MDL file contains invalid data");
  164|      0|        }
  165|       |
  166|      8|        return reinterpret_cast<const DataType *>(data_ + uoffset);
  167|      8|    }
_ZNK6Assimp3MDL8HalfLife13HL1DataBuffer8get_dataINS1_18SequenceHeader_HL1EEEPKT_ii:
  154|      9|    const DataType *get_data(int offset, int elements) const {
  155|      9|        if (offset < 0 || elements < 0) {
  ------------------
  |  Branch (155:13): [True: 0, False: 9]
  |  Branch (155:27): [True: 0, False: 9]
  ------------------
  156|      0|            throw DeadlyImportError("MDL file contains invalid data");
  157|      0|        }
  158|       |
  159|      9|        const size_t uoffset = static_cast<size_t>(offset);
  160|      9|        const size_t uelements = static_cast<size_t>(elements);
  161|       |
  162|      9|        if (uoffset > length_ || uelements > (length_ - uoffset) / sizeof(DataType)) {
  ------------------
  |  Branch (162:13): [True: 0, False: 9]
  |  Branch (162:34): [True: 0, False: 9]
  ------------------
  163|      0|            throw DeadlyImportError("MDL file contains invalid data");
  164|      0|        }
  165|       |
  166|      9|        return reinterpret_cast<const DataType *>(data_ + uoffset);
  167|      9|    }
_ZNK6Assimp3MDL8HalfLife13HL1DataBuffer8get_dataINS1_11Texture_HL1EEEPKT_ii:
  154|      8|    const DataType *get_data(int offset, int elements) const {
  155|      8|        if (offset < 0 || elements < 0) {
  ------------------
  |  Branch (155:13): [True: 0, False: 8]
  |  Branch (155:27): [True: 0, False: 8]
  ------------------
  156|      0|            throw DeadlyImportError("MDL file contains invalid data");
  157|      0|        }
  158|       |
  159|      8|        const size_t uoffset = static_cast<size_t>(offset);
  160|      8|        const size_t uelements = static_cast<size_t>(elements);
  161|       |
  162|      8|        if (uoffset > length_ || uelements > (length_ - uoffset) / sizeof(DataType)) {
  ------------------
  |  Branch (162:13): [True: 0, False: 8]
  |  Branch (162:34): [True: 0, False: 8]
  ------------------
  163|      0|            throw DeadlyImportError("MDL file contains invalid data");
  164|      0|        }
  165|       |
  166|      8|        return reinterpret_cast<const DataType *>(data_ + uoffset);
  167|      8|    }
_ZNK6Assimp3MDL8HalfLife13HL1DataBuffer8get_dataIhEEPKT_ii:
  154|     14|    const DataType *get_data(int offset, int elements) const {
  155|     14|        if (offset < 0 || elements < 0) {
  ------------------
  |  Branch (155:13): [True: 0, False: 14]
  |  Branch (155:27): [True: 0, False: 14]
  ------------------
  156|      0|            throw DeadlyImportError("MDL file contains invalid data");
  157|      0|        }
  158|       |
  159|     14|        const size_t uoffset = static_cast<size_t>(offset);
  160|     14|        const size_t uelements = static_cast<size_t>(elements);
  161|       |
  162|     14|        if (uoffset > length_ || uelements > (length_ - uoffset) / sizeof(DataType)) {
  ------------------
  |  Branch (162:13): [True: 0, False: 14]
  |  Branch (162:34): [True: 0, False: 14]
  ------------------
  163|      0|            throw DeadlyImportError("MDL file contains invalid data");
  164|      0|        }
  165|       |
  166|     14|        return reinterpret_cast<const DataType *>(data_ + uoffset);
  167|     14|    }
_ZNK6Assimp3MDL8HalfLife13HL1DataBuffer8get_dataIsEEPKT_ii:
  154|      4|    const DataType *get_data(int offset, int elements) const {
  155|      4|        if (offset < 0 || elements < 0) {
  ------------------
  |  Branch (155:13): [True: 0, False: 4]
  |  Branch (155:27): [True: 0, False: 4]
  ------------------
  156|      0|            throw DeadlyImportError("MDL file contains invalid data");
  157|      0|        }
  158|       |
  159|      4|        const size_t uoffset = static_cast<size_t>(offset);
  160|      4|        const size_t uelements = static_cast<size_t>(elements);
  161|       |
  162|      4|        if (uoffset > length_ || uelements > (length_ - uoffset) / sizeof(DataType)) {
  ------------------
  |  Branch (162:13): [True: 0, False: 4]
  |  Branch (162:34): [True: 0, False: 4]
  ------------------
  163|      0|            throw DeadlyImportError("MDL file contains invalid data");
  164|      0|        }
  165|       |
  166|      4|        return reinterpret_cast<const DataType *>(data_ + uoffset);
  167|      4|    }
_ZNK6Assimp3MDL8HalfLife13HL1DataBuffer8get_dataINS1_8Bone_HL1EEEPKT_ii:
  154|      9|    const DataType *get_data(int offset, int elements) const {
  155|      9|        if (offset < 0 || elements < 0) {
  ------------------
  |  Branch (155:13): [True: 0, False: 9]
  |  Branch (155:27): [True: 0, False: 9]
  ------------------
  156|      0|            throw DeadlyImportError("MDL file contains invalid data");
  157|      0|        }
  158|       |
  159|      9|        const size_t uoffset = static_cast<size_t>(offset);
  160|      9|        const size_t uelements = static_cast<size_t>(elements);
  161|       |
  162|      9|        if (uoffset > length_ || uelements > (length_ - uoffset) / sizeof(DataType)) {
  ------------------
  |  Branch (162:13): [True: 0, False: 9]
  |  Branch (162:34): [True: 0, False: 9]
  ------------------
  163|      0|            throw DeadlyImportError("MDL file contains invalid data");
  164|      0|        }
  165|       |
  166|      9|        return reinterpret_cast<const DataType *>(data_ + uoffset);
  167|      9|    }
_ZNK6Assimp3MDL8HalfLife13HL1DataBuffer8get_dataINS1_12Bodypart_HL1EEEPKT_ii:
  154|     12|    const DataType *get_data(int offset, int elements) const {
  155|     12|        if (offset < 0 || elements < 0) {
  ------------------
  |  Branch (155:13): [True: 0, False: 12]
  |  Branch (155:27): [True: 0, False: 12]
  ------------------
  156|      0|            throw DeadlyImportError("MDL file contains invalid data");
  157|      0|        }
  158|       |
  159|     12|        const size_t uoffset = static_cast<size_t>(offset);
  160|     12|        const size_t uelements = static_cast<size_t>(elements);
  161|       |
  162|     12|        if (uoffset > length_ || uelements > (length_ - uoffset) / sizeof(DataType)) {
  ------------------
  |  Branch (162:13): [True: 0, False: 12]
  |  Branch (162:34): [True: 0, False: 12]
  ------------------
  163|      0|            throw DeadlyImportError("MDL file contains invalid data");
  164|      0|        }
  165|       |
  166|     12|        return reinterpret_cast<const DataType *>(data_ + uoffset);
  167|     12|    }
_ZNK6Assimp3MDL8HalfLife13HL1DataBuffer8get_dataINS1_9Model_HL1EEEPKT_ii:
  154|     12|    const DataType *get_data(int offset, int elements) const {
  155|     12|        if (offset < 0 || elements < 0) {
  ------------------
  |  Branch (155:13): [True: 0, False: 12]
  |  Branch (155:27): [True: 0, False: 12]
  ------------------
  156|      0|            throw DeadlyImportError("MDL file contains invalid data");
  157|      0|        }
  158|       |
  159|     12|        const size_t uoffset = static_cast<size_t>(offset);
  160|     12|        const size_t uelements = static_cast<size_t>(elements);
  161|       |
  162|     12|        if (uoffset > length_ || uelements > (length_ - uoffset) / sizeof(DataType)) {
  ------------------
  |  Branch (162:13): [True: 0, False: 12]
  |  Branch (162:34): [True: 0, False: 12]
  ------------------
  163|      0|            throw DeadlyImportError("MDL file contains invalid data");
  164|      0|        }
  165|       |
  166|     12|        return reinterpret_cast<const DataType *>(data_ + uoffset);
  167|     12|    }
_ZNK6Assimp3MDL8HalfLife13HL1DataBuffer8get_dataINS1_8Mesh_HL1EEEPKT_ii:
  154|      3|    const DataType *get_data(int offset, int elements) const {
  155|      3|        if (offset < 0 || elements < 0) {
  ------------------
  |  Branch (155:13): [True: 0, False: 3]
  |  Branch (155:27): [True: 0, False: 3]
  ------------------
  156|      0|            throw DeadlyImportError("MDL file contains invalid data");
  157|      0|        }
  158|       |
  159|      3|        const size_t uoffset = static_cast<size_t>(offset);
  160|      3|        const size_t uelements = static_cast<size_t>(elements);
  161|       |
  162|      3|        if (uoffset > length_ || uelements > (length_ - uoffset) / sizeof(DataType)) {
  ------------------
  |  Branch (162:13): [True: 0, False: 3]
  |  Branch (162:34): [True: 0, False: 3]
  ------------------
  163|      0|            throw DeadlyImportError("MDL file contains invalid data");
  164|      0|        }
  165|       |
  166|      3|        return reinterpret_cast<const DataType *>(data_ + uoffset);
  167|      3|    }
_ZNK6Assimp3MDL8HalfLife13HL1DataBuffer8get_dataIA3_fEEPKT_ii:
  154|      6|    const DataType *get_data(int offset, int elements) const {
  155|      6|        if (offset < 0 || elements < 0) {
  ------------------
  |  Branch (155:13): [True: 0, False: 6]
  |  Branch (155:27): [True: 0, False: 6]
  ------------------
  156|      0|            throw DeadlyImportError("MDL file contains invalid data");
  157|      0|        }
  158|       |
  159|      6|        const size_t uoffset = static_cast<size_t>(offset);
  160|      6|        const size_t uelements = static_cast<size_t>(elements);
  161|       |
  162|      6|        if (uoffset > length_ || uelements > (length_ - uoffset) / sizeof(DataType)) {
  ------------------
  |  Branch (162:13): [True: 0, False: 6]
  |  Branch (162:34): [True: 0, False: 6]
  ------------------
  163|      0|            throw DeadlyImportError("MDL file contains invalid data");
  164|      0|        }
  165|       |
  166|      6|        return reinterpret_cast<const DataType *>(data_ + uoffset);
  167|      6|    }
_ZNK6Assimp3MDL8HalfLife13HL1DataBuffer8get_dataINS1_16SequenceDesc_HL1EEEPKT_ii:
  154|     11|    const DataType *get_data(int offset, int elements) const {
  155|     11|        if (offset < 0 || elements < 0) {
  ------------------
  |  Branch (155:13): [True: 0, False: 11]
  |  Branch (155:27): [True: 0, False: 11]
  ------------------
  156|      0|            throw DeadlyImportError("MDL file contains invalid data");
  157|      0|        }
  158|       |
  159|     11|        const size_t uoffset = static_cast<size_t>(offset);
  160|     11|        const size_t uelements = static_cast<size_t>(elements);
  161|       |
  162|     11|        if (uoffset > length_ || uelements > (length_ - uoffset) / sizeof(DataType)) {
  ------------------
  |  Branch (162:13): [True: 0, False: 11]
  |  Branch (162:34): [True: 0, False: 11]
  ------------------
  163|      0|            throw DeadlyImportError("MDL file contains invalid data");
  164|      0|        }
  165|       |
  166|     11|        return reinterpret_cast<const DataType *>(data_ + uoffset);
  167|     11|    }
_ZNK6Assimp3MDL8HalfLife13HL1DataBuffer8get_dataINS1_17SequenceGroup_HL1EEEPKT_ii:
  154|     10|    const DataType *get_data(int offset, int elements) const {
  155|     10|        if (offset < 0 || elements < 0) {
  ------------------
  |  Branch (155:13): [True: 1, False: 9]
  |  Branch (155:27): [True: 0, False: 9]
  ------------------
  156|      1|            throw DeadlyImportError("MDL file contains invalid data");
  157|      1|        }
  158|       |
  159|      9|        const size_t uoffset = static_cast<size_t>(offset);
  160|      9|        const size_t uelements = static_cast<size_t>(elements);
  161|       |
  162|      9|        if (uoffset > length_ || uelements > (length_ - uoffset) / sizeof(DataType)) {
  ------------------
  |  Branch (162:13): [True: 0, False: 9]
  |  Branch (162:34): [True: 0, False: 9]
  ------------------
  163|      0|            throw DeadlyImportError("MDL file contains invalid data");
  164|      0|        }
  165|       |
  166|      9|        return reinterpret_cast<const DataType *>(data_ + uoffset);
  167|      9|    }
_ZNK6Assimp3MDL8HalfLife13HL1DataBuffer8get_dataINS1_19AnimValueOffset_HL1EEEPKT_ii:
  154|      5|    const DataType *get_data(int offset, int elements) const {
  155|      5|        if (offset < 0 || elements < 0) {
  ------------------
  |  Branch (155:13): [True: 0, False: 5]
  |  Branch (155:27): [True: 0, False: 5]
  ------------------
  156|      0|            throw DeadlyImportError("MDL file contains invalid data");
  157|      0|        }
  158|       |
  159|      5|        const size_t uoffset = static_cast<size_t>(offset);
  160|      5|        const size_t uelements = static_cast<size_t>(elements);
  161|       |
  162|      5|        if (uoffset > length_ || uelements > (length_ - uoffset) / sizeof(DataType)) {
  ------------------
  |  Branch (162:13): [True: 0, False: 5]
  |  Branch (162:34): [True: 0, False: 5]
  ------------------
  163|      0|            throw DeadlyImportError("MDL file contains invalid data");
  164|      0|        }
  165|       |
  166|      5|        return reinterpret_cast<const DataType *>(data_ + uoffset);
  167|      5|    }
_ZNK6Assimp3MDL8HalfLife13HL1DataBuffer8get_dataINS1_10Hitbox_HL1EEEPKT_ii:
  154|      2|    const DataType *get_data(int offset, int elements) const {
  155|      2|        if (offset < 0 || elements < 0) {
  ------------------
  |  Branch (155:13): [True: 0, False: 2]
  |  Branch (155:27): [True: 0, False: 2]
  ------------------
  156|      0|            throw DeadlyImportError("MDL file contains invalid data");
  157|      0|        }
  158|       |
  159|      2|        const size_t uoffset = static_cast<size_t>(offset);
  160|      2|        const size_t uelements = static_cast<size_t>(elements);
  161|       |
  162|      2|        if (uoffset > length_ || uelements > (length_ - uoffset) / sizeof(DataType)) {
  ------------------
  |  Branch (162:13): [True: 0, False: 2]
  |  Branch (162:34): [True: 0, False: 2]
  ------------------
  163|      0|            throw DeadlyImportError("MDL file contains invalid data");
  164|      0|        }
  165|       |
  166|      2|        return reinterpret_cast<const DataType *>(data_ + uoffset);
  167|      2|    }

_ZN6Assimp3MDL8HalfLife17HL1ImportSettingsC2Ev:
   57|  1.24k|        read_animations(false),
   58|  1.24k|        read_animation_events(false),
   59|  1.24k|        read_blend_controllers(false),
   60|  1.24k|        read_sequence_groups_info(false),
   61|  1.24k|        read_sequence_transitions(false),
   62|  1.24k|        read_attachments(false),
   63|  1.24k|        read_bone_controllers(false),
   64|  1.24k|        read_hitboxes(false),
   65|  1.24k|        read_textures(false),
   66|  1.24k|        read_misc_global_info(false),
   67|  1.24k|        transform_coord_system(true) {
   68|  1.24k|    }

_ZN6Assimp3MDL8HalfLife12HL1MDLLoaderC2EP7aiScenePNS_8IOSystemEPKhmRKNSt3__112basic_stringIcNS9_11char_traitsIcEENS9_9allocatorIcEEEERKNS1_17HL1ImportSettingsE:
   84|      4|    scene_(scene),
   85|      4|    io_(io),
   86|      4|    buffer_(HL1DataBuffer::view(buffer, buffer_length)),
   87|      4|    file_path_(file_path),
   88|      4|    import_settings_(import_settings),
   89|      4|    header_(nullptr),
   90|      4|    texture_header_(nullptr),
   91|      4|    anim_headers_(),
   92|      4|    texture_buffer_(),
   93|      4|    anim_buffers_(),
   94|      4|    num_sequence_groups_(0),
   95|      4|    rootnode_children_(),
   96|      4|    unique_name_generator_(),
   97|      4|    unique_sequence_names_(),
   98|      4|    unique_sequence_groups_names_(),
   99|      4|    temp_bones_(),
  100|      4|    num_blend_controllers_(0),
  101|      4|    total_models_(0) {
  102|      4|    load_file();
  103|      4|}
_ZN6Assimp3MDL8HalfLife12HL1MDLLoaderD2Ev:
  106|      3|HL1MDLLoader::~HL1MDLLoader() {
  107|      3|    release_resources();
  108|      3|}
_ZN6Assimp3MDL8HalfLife12HL1MDLLoader17release_resourcesEv:
  111|      7|void HL1MDLLoader::release_resources() {
  112|       |    // Root has some children nodes. so let's proceed them
  113|      7|    if (!rootnode_children_.empty()) {
  ------------------
  |  Branch (113:9): [True: 1, False: 6]
  ------------------
  114|       |        // Here, it means that the nodes were not added to the
  115|       |        // scene root node. We still have to delete them.
  116|      4|        for (auto it = rootnode_children_.begin(); it != rootnode_children_.end(); ++it) {
  ------------------
  |  Branch (116:52): [True: 3, False: 1]
  ------------------
  117|      3|            if (*it) {
  ------------------
  |  Branch (117:17): [True: 3, False: 0]
  ------------------
  118|      3|                delete *it;
  119|      3|            }
  120|      3|        }
  121|       |        // Ensure this happens only once.
  122|      1|        rootnode_children_.clear();
  123|      1|    }
  124|      7|}
_ZN6Assimp3MDL8HalfLife12HL1MDLLoader9load_fileEv:
  127|      4|void HL1MDLLoader::load_file() {
  128|      4|    try {
  129|      4|        header_ = get_buffer_data<Header_HL1>(0, 1);
  130|      4|        validate_header(header_, false);
  131|       |
  132|       |        // Create the root scene node.
  133|      4|        scene_->mRootNode = new aiNode(AI_MDL_HL1_NODE_ROOT);
  ------------------
  |  |   49|      4|#define AI_MDL_HL1_NODE_ROOT "<MDL_root>"
  ------------------
  134|       |
  135|      4|        load_texture_file();
  136|       |
  137|      4|        if (import_settings_.read_animations) {
  ------------------
  |  Branch (137:13): [True: 4, False: 0]
  ------------------
  138|      4|            load_sequence_groups_files();
  139|      4|        }
  140|       |
  141|      4|        read_textures();
  142|      4|        read_skins();
  143|       |
  144|      4|        read_bones();
  145|      4|        read_meshes();
  146|       |
  147|      4|        if (import_settings_.read_animations) {
  ------------------
  |  Branch (147:13): [True: 4, False: 0]
  ------------------
  148|      4|            read_sequence_groups_info();
  149|      4|            read_animations();
  150|      4|            read_sequence_infos();
  151|      4|            if (import_settings_.read_sequence_transitions)
  ------------------
  |  Branch (151:17): [True: 3, False: 1]
  ------------------
  152|      3|                read_sequence_transitions();
  153|      4|        }
  154|       |
  155|      4|        if (import_settings_.read_attachments) {
  ------------------
  |  Branch (155:13): [True: 3, False: 1]
  ------------------
  156|      3|            read_attachments();
  157|      3|        }
  158|       |
  159|      4|        if (import_settings_.read_hitboxes) {
  ------------------
  |  Branch (159:13): [True: 3, False: 1]
  ------------------
  160|      3|            read_hitboxes();
  161|      3|        }
  162|       |
  163|      4|        if (import_settings_.read_bone_controllers) {
  ------------------
  |  Branch (163:13): [True: 3, False: 1]
  ------------------
  164|      3|            read_bone_controllers();
  165|      3|        }
  166|       |
  167|      4|        read_global_info();
  168|       |
  169|      4|        if (!header_->numbodyparts) {
  ------------------
  |  Branch (169:13): [True: 0, False: 4]
  ------------------
  170|       |            // This could be an MDL external texture file. In this case,
  171|       |            // add this flag to allow the scene to be loaded even if it
  172|       |            // has no meshes.
  173|      0|            scene_->mFlags |= AI_SCENE_FLAGS_INCOMPLETE;
  174|      0|        }
  175|       |
  176|       |        // Append children to root node.
  177|      4|        if (rootnode_children_.size()) {
  ------------------
  |  Branch (177:13): [True: 3, False: 1]
  ------------------
  178|      3|            scene_->mRootNode->addChildren(
  179|      3|                    static_cast<unsigned int>(rootnode_children_.size()),
  180|      3|                    rootnode_children_.data());
  181|       |
  182|       |            // Clear the list of nodes so they will not be destroyed
  183|       |            // when resources are released.
  184|      3|            rootnode_children_.clear();
  185|      3|        }
  186|       |
  187|      4|        release_resources();
  188|       |
  189|      4|    } catch (...) {
  190|      1|        release_resources();
  191|      1|        throw;
  192|      1|    }
  193|      4|}
_ZN6Assimp3MDL8HalfLife12HL1MDLLoader15validate_headerEPKNS1_10Header_HL1Eb:
  196|      8|void HL1MDLLoader::validate_header(const Header_HL1 *header, bool is_texture_header) {
  197|      8|    if (is_texture_header) {
  ------------------
  |  Branch (197:9): [True: 4, False: 4]
  ------------------
  198|       |        // Every single Half-Life model is assumed to have at least one texture.
  199|      4|        if (!header->numtextures) {
  ------------------
  |  Branch (199:13): [True: 0, False: 4]
  ------------------
  200|      0|            throw DeadlyImportError(MDL_HALFLIFE_LOG_HEADER "There are no textures in the file");
  ------------------
  |  |   65|      0|#define MDL_HALFLIFE_LOG_HEADER "[Half-Life 1 MDL] "
  ------------------
  201|      0|        }
  202|       |
  203|      4|        if (header->numtextures > AI_MDL_HL1_MAX_TEXTURES) {
  ------------------
  |  |  555|      4|#define AI_MDL_HL1_MAX_TEXTURES 100
  ------------------
  |  Branch (203:13): [True: 0, False: 4]
  ------------------
  204|      0|            log_warning_limit_exceeded<AI_MDL_HL1_MAX_TEXTURES>(header->numtextures, "textures");
  205|      0|        }
  206|       |
  207|      4|        if (header->numskinfamilies > AI_MDL_HL1_MAX_SKIN_FAMILIES) {
  ------------------
  |  |  558|      4|#define AI_MDL_HL1_MAX_SKIN_FAMILIES 100
  ------------------
  |  Branch (207:13): [True: 0, False: 4]
  ------------------
  208|      0|            log_warning_limit_exceeded<AI_MDL_HL1_MAX_SKIN_FAMILIES>(header->numskinfamilies, "skin families");
  209|      0|        }
  210|       |
  211|      4|    } else {
  212|       |
  213|      4|        if (header->numbodyparts > AI_MDL_HL1_MAX_BODYPARTS) {
  ------------------
  |  |  564|      4|#define AI_MDL_HL1_MAX_BODYPARTS 32
  ------------------
  |  Branch (213:13): [True: 0, False: 4]
  ------------------
  214|      0|            log_warning_limit_exceeded<AI_MDL_HL1_MAX_BODYPARTS>(header->numbodyparts, "bodyparts");
  215|      0|        }
  216|       |
  217|      4|        if (header->numbones > AI_MDL_HL1_MAX_BONES) {
  ------------------
  |  |  561|      4|#define AI_MDL_HL1_MAX_BONES 128
  ------------------
  |  Branch (217:13): [True: 0, False: 4]
  ------------------
  218|      0|            log_warning_limit_exceeded<AI_MDL_HL1_MAX_BONES>(header->numbones, "bones");
  219|      0|        }
  220|       |
  221|      4|        if (header->numbonecontrollers > AI_MDL_HL1_MAX_BONE_CONTROLLERS) {
  ------------------
  |  |  576|      4|#define AI_MDL_HL1_MAX_BONE_CONTROLLERS 8
  ------------------
  |  Branch (221:13): [True: 0, False: 4]
  ------------------
  222|      0|            log_warning_limit_exceeded<AI_MDL_HL1_MAX_BONE_CONTROLLERS>(header->numbonecontrollers, "bone controllers");
  223|      0|        }
  224|       |
  225|      4|        if (header->numseq > AI_MDL_HL1_MAX_SEQUENCES) {
  ------------------
  |  |  549|      4|#define AI_MDL_HL1_MAX_SEQUENCES 2048
  ------------------
  |  Branch (225:13): [True: 0, False: 4]
  ------------------
  226|      0|            log_warning_limit_exceeded<AI_MDL_HL1_MAX_SEQUENCES>(header->numseq, "sequences");
  227|      0|        }
  228|       |
  229|      4|        if (header->numseqgroups > AI_MDL_HL1_MAX_SEQUENCE_GROUPS) {
  ------------------
  |  |  552|      4|#define AI_MDL_HL1_MAX_SEQUENCE_GROUPS 32
  ------------------
  |  Branch (229:13): [True: 0, False: 4]
  ------------------
  230|      0|            log_warning_limit_exceeded<AI_MDL_HL1_MAX_SEQUENCE_GROUPS>(header->numseqgroups, "sequence groups");
  231|      0|        }
  232|       |
  233|      4|        if (header->numattachments > AI_MDL_HL1_MAX_ATTACHMENTS) {
  ------------------
  |  |  579|      4|#define AI_MDL_HL1_MAX_ATTACHMENTS 512
  ------------------
  |  Branch (233:13): [True: 0, False: 4]
  ------------------
  234|      0|            log_warning_limit_exceeded<AI_MDL_HL1_MAX_ATTACHMENTS>(header->numattachments, "attachments");
  235|      0|        }
  236|      4|    }
  237|      8|}
_ZN6Assimp3MDL8HalfLife12HL1MDLLoader17load_texture_fileEv:
  257|      4|void HL1MDLLoader::load_texture_file() {
  258|      4|    if (header_->numtextures == 0) {
  ------------------
  |  Branch (258:9): [True: 0, False: 4]
  ------------------
  259|       |        // Load an external MDL texture file.
  260|      0|        std::string texture_file_path =
  261|      0|                DefaultIOSystem::absolutePath(file_path_) + io_->getOsSeparator() +
  262|      0|                DefaultIOSystem::completeBaseName(file_path_) + "T." +
  263|      0|                BaseImporter::GetExtension(file_path_);
  264|       |
  265|      0|        load_file_into_buffer<Header_HL1>(texture_file_path, texture_buffer_);
  266|      4|    } else {
  267|       |        // Model has no external texture file. This means the texture is stored inside the main MDL file.
  268|      4|        texture_buffer_ = HL1DataBuffer::view(buffer_);
  269|      4|    }
  270|       |
  271|      4|    texture_header_ = get_texture_buffer_data<Header_HL1>(0, 1);
  272|       |
  273|       |    // Validate texture header.
  274|      4|    validate_header(texture_header_, true);
  275|      4|}
_ZN6Assimp3MDL8HalfLife12HL1MDLLoader26load_sequence_groups_filesEv:
  293|      4|void HL1MDLLoader::load_sequence_groups_files() {
  294|      4|    if (header_->numseqgroups <= 1) {
  ------------------
  |  Branch (294:9): [True: 3, False: 1]
  ------------------
  295|      3|        return;
  296|      3|    }
  297|       |
  298|      1|    num_sequence_groups_ = header_->numseqgroups;
  299|       |
  300|      1|    anim_buffers_.resize(num_sequence_groups_);
  301|      1|    anim_headers_.resize(num_sequence_groups_, nullptr);
  302|       |
  303|      1|    std::string file_path_without_extension =
  304|      1|            DefaultIOSystem::absolutePath(file_path_) +
  305|      1|            io_->getOsSeparator() +
  306|      1|            DefaultIOSystem::completeBaseName(file_path_);
  307|       |
  308|     10|    for (int i = 1; i < num_sequence_groups_; ++i) {
  ------------------
  |  Branch (308:21): [True: 9, False: 1]
  ------------------
  309|      9|        std::stringstream ss;
  310|      9|        ss << file_path_without_extension;
  311|      9|        ss << std::setw(2) << std::setfill('0') << i;
  312|      9|        ss << '.' << BaseImporter::GetExtension(file_path_);
  313|       |
  314|      9|        std::string sequence_file_path = ss.str();
  315|       |
  316|      9|        load_file_into_buffer<SequenceHeader_HL1>(sequence_file_path, anim_buffers_[i]);
  317|       |
  318|      9|        anim_headers_[i] = get_anim_buffer_data<SequenceHeader_HL1>(i, 0, 1);
  319|      9|    }
  320|      1|}
_ZN6Assimp3MDL8HalfLife12HL1MDLLoader12read_textureEPKNS1_11Texture_HL1EPKhS7_P9aiTextureR9aiColor3D:
  326|      4|        aiColor3D &last_palette_color) {
  327|      4|    pResult->mFilename = ptexture->name;
  328|      4|    pResult->mWidth = static_cast<unsigned int>(ptexture->width);
  329|      4|    pResult->mHeight = static_cast<unsigned int>(ptexture->height);
  330|      4|    pResult->achFormatHint[0] = 'r';
  331|      4|    pResult->achFormatHint[1] = 'g';
  332|      4|    pResult->achFormatHint[2] = 'b';
  333|      4|    pResult->achFormatHint[3] = 'a';
  334|      4|    pResult->achFormatHint[4] = '8';
  335|      4|    pResult->achFormatHint[5] = '8';
  336|      4|    pResult->achFormatHint[6] = '8';
  337|      4|    pResult->achFormatHint[7] = '8';
  338|      4|    pResult->achFormatHint[8] = '\0';
  339|       |
  340|      4|    const size_t num_pixels = pResult->mWidth * pResult->mHeight;
  341|      4|    aiTexel *out = pResult->pcData = new aiTexel[num_pixels];
  342|       |
  343|       |    // Convert indexed 8 bit to 32 bit RGBA.
  344|   270k|    for (size_t i = 0; i < num_pixels; ++i, ++out) {
  ------------------
  |  Branch (344:24): [True: 270k, False: 4]
  ------------------
  345|   270k|        out->r = pal[data[i] * 3];
  346|   270k|        out->g = pal[data[i] * 3 + 1];
  347|   270k|        out->b = pal[data[i] * 3 + 2];
  348|   270k|        out->a = 255;
  349|   270k|    }
  350|       |
  351|       |    // Get the last palette color.
  352|      4|    last_palette_color.r = pal[255 * 3];
  353|      4|    last_palette_color.g = pal[255 * 3 + 1];
  354|      4|    last_palette_color.b = pal[255 * 3 + 2];
  355|      4|}
_ZN6Assimp3MDL8HalfLife12HL1MDLLoader13read_texturesEv:
  358|      4|void HL1MDLLoader::read_textures() {
  359|      4|    scene_->mTextures = new aiTexture *[texture_header_->numtextures];
  360|      4|    scene_->mMaterials = new aiMaterial *[texture_header_->numtextures];
  361|       |
  362|      4|    const Texture_HL1 *ptexture = get_texture_buffer_data<Texture_HL1>(texture_header_->textureindex, texture_header_->numtextures);
  363|       |
  364|      8|    for (int i = 0; i < texture_header_->numtextures; ++i) {
  ------------------
  |  Branch (364:21): [True: 4, False: 4]
  ------------------
  365|      4|        scene_->mTextures[i] = new aiTexture();
  366|      4|        ++scene_->mNumTextures;
  367|       |
  368|      4|        const uint8_t *data = get_texture_buffer_data<uint8_t>(ptexture[i].index, ptexture[i].width * ptexture[i].height);
  369|      4|        const uint8_t *pal = get_texture_buffer_data<uint8_t>(ptexture[i].index + ptexture[i].width * ptexture[i].height, 256 * 3);
  370|       |
  371|      4|        aiColor3D last_palette_color;
  372|      4|        read_texture(&ptexture[i], data, pal, scene_->mTextures[i], last_palette_color);
  373|       |
  374|      4|        aiMaterial *scene_material = new aiMaterial();
  375|      4|        scene_->mMaterials[i] = scene_material;
  376|      4|        ++scene_->mNumMaterials;
  377|       |
  378|      4|        const aiTextureType texture_type = aiTextureType_DIFFUSE;
  379|      4|        aiString texture_name(ptexture[i].name);
  380|      4|        scene_material->AddProperty(&texture_name, AI_MATKEY_TEXTURE(texture_type, 0));
  381|       |
  382|       |        // Is this a chrome texture?
  383|      4|        int chrome = ptexture[i].flags & AI_MDL_HL1_STUDIO_NF_CHROME ? 1 : 0;
  ------------------
  |  |  587|      4|#define AI_MDL_HL1_STUDIO_NF_CHROME 0x0002
  ------------------
  |  Branch (383:22): [True: 2, False: 2]
  ------------------
  384|      4|        scene_material->AddProperty(&chrome, 1, AI_MDL_HL1_MATKEY_CHROME(texture_type, 0));
  ------------------
  |  |   62|      4|#define AI_MDL_HL1_MATKEY_CHROME(type, N) "$mat.HL1.chrome", type, N
  ------------------
  385|       |
  386|      4|        if (ptexture[i].flags & AI_MDL_HL1_STUDIO_NF_FLATSHADE) {
  ------------------
  |  |  584|      4|#define AI_MDL_HL1_STUDIO_NF_FLATSHADE 0x0001
  ------------------
  |  Branch (386:13): [True: 2, False: 2]
  ------------------
  387|       |            // Flat shading.
  388|      2|            const aiShadingMode shading_mode = aiShadingMode_Flat;
  389|      2|            scene_material->AddProperty(&shading_mode, 1, AI_MATKEY_SHADING_MODEL);
  390|      2|        }
  391|       |
  392|      4|        if (ptexture[i].flags & AI_MDL_HL1_STUDIO_NF_ADDITIVE) {
  ------------------
  |  |  590|      4|#define AI_MDL_HL1_STUDIO_NF_ADDITIVE 0x0020
  ------------------
  |  Branch (392:13): [True: 1, False: 3]
  ------------------
  393|       |            // Additive texture.
  394|      1|            const aiBlendMode blend_mode = aiBlendMode_Additive;
  395|      1|            scene_material->AddProperty(&blend_mode, 1, AI_MATKEY_BLEND_FUNC);
  396|      3|        } else if (ptexture[i].flags & AI_MDL_HL1_STUDIO_NF_MASKED) {
  ------------------
  |  |  593|      3|#define AI_MDL_HL1_STUDIO_NF_MASKED 0x0040
  ------------------
  |  Branch (396:20): [True: 1, False: 2]
  ------------------
  397|       |            // Texture with 1 bit alpha test.
  398|      1|            const aiTextureFlags use_alpha = aiTextureFlags_UseAlpha;
  399|      1|            scene_material->AddProperty(&use_alpha, 1, AI_MATKEY_TEXFLAGS(texture_type, 0));
  400|       |            scene_material->AddProperty(&last_palette_color, 1, AI_MATKEY_COLOR_TRANSPARENT);
  401|      1|        }
  402|      4|    }
  403|      4|}
_ZN6Assimp3MDL8HalfLife12HL1MDLLoader10read_skinsEv:
  406|      4|void HL1MDLLoader::read_skins() {
  407|       |    // Read skins, if any.
  408|      4|    if (texture_header_->numskinfamilies <= 1) {
  ------------------
  |  Branch (408:9): [True: 4, False: 0]
  ------------------
  409|      4|        return;
  410|      4|    }
  411|       |
  412|       |    // Pointer to base texture index.
  413|      0|    const short *default_skin_ptr = get_texture_buffer_data<short>(
  414|      0|            texture_header_->skinindex,
  415|      0|            texture_header_->numskinref);
  416|       |
  417|       |    // Start at first replacement skin.
  418|      0|    const short *replacement_skin_ptr = get_texture_buffer_data<short>(
  419|      0|            texture_header_->skinindex + texture_header_->numskinref * sizeof(short),
  420|      0|            (texture_header_->numskinfamilies - 1) * texture_header_->numskinref);
  421|       |
  422|      0|    for (int i = 1; i < texture_header_->numskinfamilies; ++i, replacement_skin_ptr += texture_header_->numskinref) {
  ------------------
  |  Branch (422:21): [True: 0, False: 0]
  ------------------
  423|      0|        for (int j = 0; j < texture_header_->numskinref; ++j) {
  ------------------
  |  Branch (423:25): [True: 0, False: 0]
  ------------------
  424|      0|            if (default_skin_ptr[j] != replacement_skin_ptr[j]) {
  ------------------
  |  Branch (424:17): [True: 0, False: 0]
  ------------------
  425|       |                // Save replacement textures.
  426|      0|                aiString skinMaterialId(scene_->mTextures[replacement_skin_ptr[j]]->mFilename);
  427|       |                scene_->mMaterials[default_skin_ptr[j]]->AddProperty(&skinMaterialId, AI_MATKEY_TEXTURE_DIFFUSE(i));
  428|      0|            }
  429|      0|        }
  430|      0|    }
  431|      0|}
_ZN6Assimp3MDL8HalfLife12HL1MDLLoader10read_bonesEv:
  434|      4|void HL1MDLLoader::read_bones() {
  435|      4|    if (!header_->numbones) {
  ------------------
  |  Branch (435:9): [True: 0, False: 4]
  ------------------
  436|      0|        return;
  437|      0|    }
  438|       |
  439|      4|    const Bone_HL1 *pbone = get_buffer_data<Bone_HL1>(header_->boneindex, header_->numbones);
  440|       |
  441|      4|    std::vector<std::string> unique_bones_names(header_->numbones);
  442|     26|    for (int i = 0; i < header_->numbones; ++i) {
  ------------------
  |  Branch (442:21): [True: 22, False: 4]
  ------------------
  443|     22|        unique_bones_names[i] = pbone[i].name;
  444|     22|    }
  445|       |
  446|       |    // Ensure bones have unique names.
  447|      4|    unique_name_generator_.set_template_name("Bone");
  448|      4|    unique_name_generator_.make_unique(unique_bones_names);
  449|       |
  450|      4|    temp_bones_.resize(header_->numbones);
  451|       |
  452|       |    // Create the main 'bones' node that will contain all MDL root bones.
  453|      4|    aiNode *bones_node = new aiNode(AI_MDL_HL1_NODE_BONES);
  ------------------
  |  |   51|      4|#define AI_MDL_HL1_NODE_BONES "<MDL_bones>"
  ------------------
  454|      4|    rootnode_children_.push_back(bones_node);
  455|       |
  456|       |    // Store roots bones IDs temporarily.
  457|      4|    std::vector<int> roots;
  458|       |
  459|       |    // Create bone matrices in local space.
  460|     26|    for (int i = 0; i < header_->numbones; ++i) {
  ------------------
  |  Branch (460:21): [True: 22, False: 4]
  ------------------
  461|     22|        aiNode *bone_node = temp_bones_[i].node = new aiNode(unique_bones_names[i]);
  462|       |
  463|     22|        aiVector3D angles(pbone[i].value[3], pbone[i].value[4], pbone[i].value[5]);
  464|     22|        temp_bones_[i].absolute_transform = bone_node->mTransformation =
  465|     22|                aiMatrix4x4(aiVector3D(1), aiQuaternion(angles.y, angles.z, angles.x),
  466|     22|                        aiVector3D(pbone[i].value[0], pbone[i].value[1], pbone[i].value[2]));
  467|       |
  468|     22|        if (pbone[i].parent == -1) {
  ------------------
  |  Branch (468:13): [True: 6, False: 16]
  ------------------
  469|      6|            bone_node->mParent = bones_node;
  470|      6|            roots.push_back(i); // This bone has no parent. Add it to the roots list.
  471|     16|        } else {
  472|     16|            bone_node->mParent = temp_bones_[pbone[i].parent].node;
  473|     16|            temp_bones_[pbone[i].parent].children.push_back(i); // Add this bone to the parent bone's children list.
  474|       |
  475|     16|            temp_bones_[i].absolute_transform =
  476|     16|                    temp_bones_[pbone[i].parent].absolute_transform * bone_node->mTransformation;
  477|     16|        }
  478|       |
  479|     22|        temp_bones_[i].offset_matrix = temp_bones_[i].absolute_transform;
  480|     22|        temp_bones_[i].offset_matrix.Inverse();
  481|     22|    }
  482|       |
  483|       |    // Allocate memory for each MDL root bone.
  484|      4|    bones_node->mNumChildren = static_cast<unsigned int>(roots.size());
  485|      4|    bones_node->mChildren = new aiNode *[bones_node->mNumChildren];
  486|       |
  487|       |    // Build all bones children hierarchy starting from each MDL root bone.
  488|     10|    for (size_t i = 0; i < roots.size(); ++i)
  ------------------
  |  Branch (488:24): [True: 6, False: 4]
  ------------------
  489|      6|    {
  490|      6|        const TempBone &root_bone = temp_bones_[roots[i]];
  491|      6|        bones_node->mChildren[i] = root_bone.node;
  492|      6|        build_bone_children_hierarchy(root_bone);
  493|      6|    }
  494|      4|}
_ZN6Assimp3MDL8HalfLife12HL1MDLLoader29build_bone_children_hierarchyERKNS2_8TempBoneE:
  497|     22|{
  498|     22|    if (bone.children.empty())
  ------------------
  |  Branch (498:9): [True: 13, False: 9]
  ------------------
  499|     13|        return;
  500|       |
  501|      9|    aiNode* bone_node = bone.node;
  502|      9|    bone_node->mNumChildren = static_cast<unsigned int>(bone.children.size());
  503|      9|    bone_node->mChildren = new aiNode *[bone_node->mNumChildren];
  504|       |
  505|       |    // Build each child bone's hierarchy recursively.
  506|     25|    for (size_t i = 0; i < bone.children.size(); ++i)
  ------------------
  |  Branch (506:24): [True: 16, False: 9]
  ------------------
  507|     16|    {
  508|     16|        const TempBone &child_bone = temp_bones_[bone.children[i]];
  509|     16|        bone_node->mChildren[i] = child_bone.node;
  510|     16|        build_bone_children_hierarchy(child_bone);
  511|     16|    }
  512|      9|}
_ZN6Assimp3MDL8HalfLife12HL1MDLLoader11read_meshesEv:
  562|      4|void HL1MDLLoader::read_meshes() {
  563|      4|    if (!header_->numbodyparts) {
  ------------------
  |  Branch (563:9): [True: 0, False: 4]
  ------------------
  564|      0|        return;
  565|      0|    }
  566|       |
  567|      4|    int total_verts = 0;
  568|      4|    int total_triangles = 0;
  569|      4|    total_models_ = 0;
  570|       |
  571|      4|    const Bodypart_HL1 *pbodypart = get_buffer_data<Bodypart_HL1>(header_->bodypartindex, header_->numbodyparts);
  572|      4|    const Model_HL1 *pmodel = nullptr;
  573|      4|    const Mesh_HL1 *pmesh = nullptr;
  574|       |
  575|      4|    const Texture_HL1 *ptexture = get_texture_buffer_data<Texture_HL1>(texture_header_->textureindex, texture_header_->numtextures);
  576|      4|    const short *pskinref = get_texture_buffer_data<short>(texture_header_->skinindex, texture_header_->numskinref);
  577|       |
  578|      4|    scene_->mNumMeshes = 0;
  579|       |
  580|      4|    std::vector<std::string> unique_bodyparts_names;
  581|      4|    unique_bodyparts_names.resize(header_->numbodyparts);
  582|       |
  583|       |    // Count the number of meshes.
  584|       |
  585|      8|    for (int i = 0; i < header_->numbodyparts; ++i, ++pbodypart) {
  ------------------
  |  Branch (585:21): [True: 4, False: 4]
  ------------------
  586|      4|        unique_bodyparts_names[i] = pbodypart->name;
  587|       |
  588|      4|        pmodel = get_buffer_data<Model_HL1>(pbodypart->modelindex, pbodypart->nummodels);
  589|      7|        for (int j = 0; j < pbodypart->nummodels; ++j, ++pmodel) {
  ------------------
  |  Branch (589:25): [True: 3, False: 4]
  ------------------
  590|      3|            scene_->mNumMeshes += pmodel->nummesh;
  591|      3|            total_verts += pmodel->numverts;
  592|      3|        }
  593|       |
  594|      4|        total_models_ += pbodypart->nummodels;
  595|      4|    }
  596|       |
  597|       |    // Display limit infos.
  598|      4|    if (total_verts > AI_MDL_HL1_MAX_VERTICES) {
  ------------------
  |  |  546|      4|#define AI_MDL_HL1_MAX_VERTICES 2048
  ------------------
  |  Branch (598:9): [True: 0, False: 4]
  ------------------
  599|      0|        log_warning_limit_exceeded<AI_MDL_HL1_MAX_VERTICES>(total_verts, "vertices");
  600|      0|    }
  601|       |
  602|      4|    if (scene_->mNumMeshes > AI_MDL_HL1_MAX_MESHES) {
  ------------------
  |  |  570|      4|#define AI_MDL_HL1_MAX_MESHES 256
  ------------------
  |  Branch (602:9): [True: 0, False: 4]
  ------------------
  603|      0|        log_warning_limit_exceeded<AI_MDL_HL1_MAX_MESHES>(scene_->mNumMeshes, "meshes");
  604|      0|    }
  605|       |
  606|      4|    if (total_models_ > AI_MDL_HL1_MAX_MODELS) {
  ------------------
  |  |  567|      4|#define AI_MDL_HL1_MAX_MODELS 32
  ------------------
  |  Branch (606:9): [True: 0, False: 4]
  ------------------
  607|      0|        log_warning_limit_exceeded<AI_MDL_HL1_MAX_MODELS>(total_models_, "models");
  608|      0|    }
  609|       |
  610|       |    // Ensure bodyparts have unique names.
  611|      4|    unique_name_generator_.set_template_name("Bodypart");
  612|      4|    unique_name_generator_.make_unique(unique_bodyparts_names);
  613|       |
  614|       |    // Now do the same for each model.
  615|      4|    pbodypart = get_buffer_data<Bodypart_HL1>(header_->bodypartindex, header_->numbodyparts);
  616|       |
  617|       |    // Prepare template name for bodypart models.
  618|      4|    std::vector<std::string> unique_models_names;
  619|      4|    unique_models_names.resize(total_models_);
  620|       |
  621|      4|    unsigned int model_index = 0;
  622|       |
  623|      8|    for (int i = 0; i < header_->numbodyparts; ++i, ++pbodypart) {
  ------------------
  |  Branch (623:21): [True: 4, False: 4]
  ------------------
  624|      4|        pmodel = get_buffer_data<Model_HL1>(pbodypart->modelindex, pbodypart->nummodels);
  625|      7|        for (int j = 0; j < pbodypart->nummodels; ++j, ++pmodel, ++model_index)
  ------------------
  |  Branch (625:25): [True: 3, False: 4]
  ------------------
  626|      3|            unique_models_names[model_index] = pmodel->name;
  627|      4|    }
  628|       |
  629|      4|    unique_name_generator_.set_template_name("Model");
  630|      4|    unique_name_generator_.make_unique(unique_models_names);
  631|       |
  632|      4|    unsigned int mesh_index = 0;
  633|       |
  634|      4|    scene_->mMeshes = new aiMesh *[scene_->mNumMeshes];
  635|       |
  636|      4|    pbodypart = get_buffer_data<Bodypart_HL1>(header_->bodypartindex, header_->numbodyparts);
  637|       |
  638|       |    /* Create a node that will represent the mesh hierarchy.
  639|       |
  640|       |        <MDL_bodyparts>
  641|       |            |
  642|       |            +-- bodypart --+-- model -- [mesh index, mesh index, ...]
  643|       |            |              |
  644|       |            |              +-- model -- [mesh index, mesh index, ...]
  645|       |            |              |
  646|       |            |              ...
  647|       |            |
  648|       |            |-- bodypart -- ...
  649|       |            |
  650|       |            ...
  651|       |     */
  652|      4|    aiNode *bodyparts_node = new aiNode(AI_MDL_HL1_NODE_BODYPARTS);
  ------------------
  |  |   50|      4|#define AI_MDL_HL1_NODE_BODYPARTS "<MDL_bodyparts>"
  ------------------
  653|      4|    rootnode_children_.push_back(bodyparts_node);
  654|      4|    bodyparts_node->mNumChildren = static_cast<unsigned int>(header_->numbodyparts);
  655|      4|    bodyparts_node->mChildren = new aiNode *[bodyparts_node->mNumChildren];
  656|      4|    aiNode **bodyparts_node_ptr = bodyparts_node->mChildren;
  657|       |
  658|       |    // The following variables are defined here so they don't have
  659|       |    // to be recreated every iteration.
  660|       |
  661|       |    // Model_HL1 vertices, in bind pose space.
  662|      4|    std::vector<aiVector3D> bind_pose_vertices;
  663|       |
  664|       |    // Model_HL1 normals, in bind pose space.
  665|      4|    std::vector<aiVector3D> bind_pose_normals;
  666|       |
  667|       |    // Used to contain temporary information for building a mesh.
  668|      4|    std::vector<HL1MeshTrivert> triverts;
  669|       |
  670|      4|    std::vector<short> tricmds;
  671|       |
  672|       |    // Which triverts to use for the mesh.
  673|      4|    std::vector<short> mesh_triverts_indices;
  674|       |
  675|      4|    std::vector<HL1MeshFace> mesh_faces;
  676|       |
  677|       |    /* triverts that have the same vertindex, but have different normindex,s,t values.
  678|       |       Similar triverts are mapped from vertindex to a list of similar triverts. */
  679|      4|    std::map<short, std::set<short>> triverts_similars;
  680|       |
  681|       |    // triverts per bone.
  682|      4|    std::map<int, std::set<short>> bone_triverts;
  683|       |
  684|       |    /** This function adds a trivert index to the list of triverts per bone.
  685|       |     * \param[in] bone The bone that affects the trivert at index \p trivert_index.
  686|       |     * \param[in] trivert_index The trivert index.
  687|       |     */
  688|      4|    auto AddTrivertToBone = [&](int bone, short trivert_index) {
  689|      4|        if (bone_triverts.count(bone) == 0)
  690|      4|            bone_triverts.insert({ bone, std::set<short>{ trivert_index }});
  691|      4|        else
  692|      4|            bone_triverts[bone].insert(trivert_index);
  693|      4|    };
  694|       |
  695|       |    /** This function creates and appends a new trivert to the list of triverts.
  696|       |     * \param[in] trivert The trivert to use as a prototype.
  697|       |     * \param[in] bone The bone that affects \p trivert.
  698|       |     */
  699|      4|    auto AddSimilarTrivert = [&](const Trivert &trivert, const int bone) {
  700|      4|        HL1MeshTrivert new_trivert(trivert);
  701|      4|        new_trivert.localindex = static_cast<short>(mesh_triverts_indices.size());
  702|       |
  703|      4|        short new_trivert_index = static_cast<short>(triverts.size());
  704|       |
  705|      4|        if (triverts_similars.count(trivert.vertindex) == 0)
  706|      4|            triverts_similars.insert({ trivert.vertindex, std::set<short>{ new_trivert_index }});
  707|      4|        else
  708|      4|            triverts_similars[trivert.vertindex].insert(new_trivert_index);
  709|       |
  710|      4|        triverts.push_back(new_trivert);
  711|       |
  712|      4|        mesh_triverts_indices.push_back(new_trivert_index);
  713|      4|        tricmds.push_back(new_trivert.localindex);
  714|      4|        AddTrivertToBone(bone, new_trivert.localindex);
  715|      4|    };
  716|       |
  717|      4|    model_index = 0;
  718|       |
  719|      8|    for (int i = 0; i < header_->numbodyparts; ++i, ++pbodypart, ++bodyparts_node_ptr) {
  ------------------
  |  Branch (719:21): [True: 4, False: 4]
  ------------------
  720|      4|        pmodel = get_buffer_data<Model_HL1>(pbodypart->modelindex, pbodypart->nummodels);
  721|       |
  722|       |        // Create bodypart node for the mesh tree hierarchy.
  723|      4|        aiNode *bodypart_node = (*bodyparts_node_ptr) = new aiNode(unique_bodyparts_names[i]);
  724|      4|        bodypart_node->mParent = bodyparts_node;
  725|      4|        bodypart_node->mMetaData = aiMetadata::Alloc(1);
  726|      4|        bodypart_node->mMetaData->Set(0, "Base", pbodypart->base);
  727|       |
  728|      4|        bodypart_node->mNumChildren = static_cast<unsigned int>(pbodypart->nummodels);
  729|      4|        bodypart_node->mChildren = new aiNode *[bodypart_node->mNumChildren];
  730|      4|        aiNode **bodypart_models_ptr = bodypart_node->mChildren;
  731|       |
  732|      7|        for (int j = 0; j < pbodypart->nummodels;
  ------------------
  |  Branch (732:25): [True: 3, False: 4]
  ------------------
  733|      4|                ++j, ++pmodel, ++bodypart_models_ptr, ++model_index) {
  734|       |
  735|      3|            pmesh = get_buffer_data<Mesh_HL1>(pmodel->meshindex, pmodel->nummesh);
  736|       |
  737|      3|            const uint8_t *pvertbone = get_buffer_data<uint8_t>(pmodel->vertinfoindex, pmodel->numverts);
  738|      3|            const uint8_t *pnormbone = get_buffer_data<uint8_t>(pmodel->norminfoindex, pmodel->numnorms);
  739|      3|            const vec3_t *pstudioverts = get_buffer_data<vec3_t>(pmodel->vertindex, pmodel->numverts);
  740|      3|            const vec3_t *pstudionorms = get_buffer_data<vec3_t>(pmodel->normindex, pmodel->numnorms);
  741|       |
  742|       |            // Each vertex and normal is in local space, so transform
  743|       |            // each of them to bring them in bind pose.
  744|      3|            bind_pose_vertices.resize(pmodel->numverts);
  745|      3|            bind_pose_normals.resize(pmodel->numnorms);
  746|    405|            for (size_t k = 0; k < bind_pose_vertices.size(); ++k) {
  ------------------
  |  Branch (746:32): [True: 402, False: 3]
  ------------------
  747|    402|                const vec3_t &vert = pstudioverts[k];
  748|    402|                bind_pose_vertices[k] = temp_bones_[pvertbone[k]].absolute_transform * aiVector3D(vert[0], vert[1], vert[2]);
  749|    402|            }
  750|    421|            for (size_t k = 0; k < bind_pose_normals.size(); ++k) {
  ------------------
  |  Branch (750:32): [True: 418, False: 3]
  ------------------
  751|    418|                const vec3_t &norm = pstudionorms[k];
  752|       |                // Compute the normal matrix to transform the normal into bind pose,
  753|       |                // without affecting its length.
  754|    418|                const aiMatrix4x4 normal_matrix = aiMatrix4x4(temp_bones_[pnormbone[k]].absolute_transform).Inverse().Transpose();
  755|    418|                bind_pose_normals[k] = normal_matrix * aiVector3D(norm[0], norm[1], norm[2]);
  756|    418|            }
  757|       |
  758|       |            // Create model node for the mesh tree hierarchy.
  759|      3|            aiNode *model_node = (*bodypart_models_ptr) = new aiNode(unique_models_names[model_index]);
  760|      3|            model_node->mParent = bodypart_node;
  761|      3|            model_node->mNumMeshes = static_cast<unsigned int>(pmodel->nummesh);
  762|      3|            model_node->mMeshes = new unsigned int[model_node->mNumMeshes];
  763|      3|            unsigned int *model_meshes_ptr = model_node->mMeshes;
  764|       |
  765|      6|            for (int k = 0; k < pmodel->nummesh; ++k, ++pmesh, ++mesh_index, ++model_meshes_ptr) {
  ------------------
  |  Branch (765:29): [True: 3, False: 3]
  ------------------
  766|      3|                *model_meshes_ptr = mesh_index;
  767|       |
  768|       |                // Read triverts.
  769|      3|                short *ptricmds = (short *)((uint8_t *)header_ + pmesh->triindex);
  770|      3|                float texcoords_s_scale = 1.0f / (float)ptexture[pskinref[pmesh->skinref]].width;
  771|      3|                float texcoords_t_scale = 1.0f / (float)ptexture[pskinref[pmesh->skinref]].height;
  772|       |
  773|       |                // Reset the data for the upcoming mesh.
  774|      3|                triverts.clear();
  775|      3|                triverts.resize(pmodel->numverts);
  776|      3|                mesh_triverts_indices.clear();
  777|      3|                mesh_faces.clear();
  778|      3|                triverts_similars.clear();
  779|      3|                bone_triverts.clear();
  780|       |
  781|      3|                int l;
  782|    157|                while ((l = *(ptricmds++))) {
  ------------------
  |  Branch (782:24): [True: 154, False: 3]
  ------------------
  783|    154|                    bool is_triangle_fan = false;
  784|       |
  785|    154|                    if (l < 0) {
  ------------------
  |  Branch (785:25): [True: 12, False: 142]
  ------------------
  786|     12|                        l = -l;
  787|     12|                        is_triangle_fan = true;
  788|     12|                    }
  789|       |
  790|       |                    // Clear the list of tris for the upcoming tris.
  791|    154|                    tricmds.clear();
  792|       |
  793|  1.18k|                    for (; l > 0; l--, ptricmds += 4) {
  ------------------
  |  Branch (793:28): [True: 1.02k, False: 154]
  ------------------
  794|  1.02k|                        const Trivert *input_trivert = reinterpret_cast<const Trivert *>(ptricmds);
  795|  1.02k|                        const int bone = pvertbone[input_trivert->vertindex];
  796|       |
  797|  1.02k|                        HL1MeshTrivert *private_trivert = &triverts[input_trivert->vertindex];
  798|  1.02k|                        if (private_trivert->localindex == -1) {
  ------------------
  |  Branch (798:29): [True: 402, False: 626]
  ------------------
  799|       |                            // First time referenced.
  800|    402|                            *private_trivert = *input_trivert;
  801|    402|                            private_trivert->localindex = static_cast<short>(mesh_triverts_indices.size());
  802|    402|                            mesh_triverts_indices.push_back(input_trivert->vertindex);
  803|    402|                            tricmds.push_back(private_trivert->localindex);
  804|    402|                            AddTrivertToBone(bone, private_trivert->localindex);
  805|    626|                        } else if (*private_trivert == *input_trivert) {
  ------------------
  |  Branch (805:36): [True: 420, False: 206]
  ------------------
  806|       |                            // Exists and is the same.
  807|    420|                            tricmds.push_back(private_trivert->localindex);
  808|    420|                        } else {
  809|       |                            // No similar trivert associated to the trivert currently processed.
  810|    206|                            if (triverts_similars.count(input_trivert->vertindex) == 0)
  ------------------
  |  Branch (810:33): [True: 160, False: 46]
  ------------------
  811|    160|                                AddSimilarTrivert(*input_trivert, bone);
  812|     46|                            else {
  813|       |                                // Search in the list of similar triverts to see if the
  814|       |                                // trivert in process is already registered.
  815|     46|                                short similar_index = -1;
  816|     46|                                for (auto it = triverts_similars[input_trivert->vertindex].cbegin();
  817|     92|                                        similar_index == -1 && it != triverts_similars[input_trivert->vertindex].cend();
  ------------------
  |  Branch (817:41): [True: 92, False: 0]
  |  Branch (817:41): [True: 46, False: 46]
  |  Branch (817:64): [True: 46, False: 46]
  ------------------
  818|     46|                                        ++it) {
  819|     46|                                    if (triverts[*it] == *input_trivert)
  ------------------
  |  Branch (819:41): [True: 0, False: 46]
  ------------------
  820|      0|                                        similar_index = *it;
  821|     46|                                }
  822|       |
  823|       |                                // If a similar trivert has been found, reuse it.
  824|       |                                // Otherwise, add it.
  825|     46|                                if (similar_index == -1)
  ------------------
  |  Branch (825:37): [True: 46, False: 0]
  ------------------
  826|     46|                                    AddSimilarTrivert(*input_trivert, bone);
  827|      0|                                else
  828|      0|                                    tricmds.push_back(triverts[similar_index].localindex);
  829|     46|                            }
  830|    206|                        }
  831|  1.02k|                    }
  832|       |
  833|       |                    // Build mesh faces.
  834|    154|                    const int num_faces = static_cast<int>(tricmds.size() - 2);
  835|    154|                    mesh_faces.reserve(num_faces);
  836|       |
  837|    154|                    if (is_triangle_fan) {
  ------------------
  |  Branch (837:25): [True: 12, False: 142]
  ------------------
  838|     79|                        for (int faceIdx = 0; faceIdx < num_faces; ++faceIdx) {
  ------------------
  |  Branch (838:47): [True: 67, False: 12]
  ------------------
  839|     67|                            mesh_faces.push_back(HL1MeshFace{
  840|     67|                                    tricmds[0],
  841|     67|                                    tricmds[faceIdx + 1],
  842|     67|                                    tricmds[faceIdx + 2] });
  843|     67|                        }
  844|    142|                    } else {
  845|    795|                        for (int faceIdx = 0; faceIdx < num_faces; ++faceIdx) {
  ------------------
  |  Branch (845:47): [True: 653, False: 142]
  ------------------
  846|    653|                            if (faceIdx & 1) {
  ------------------
  |  Branch (846:33): [True: 297, False: 356]
  ------------------
  847|       |                                // Preserve winding order.
  848|    297|                                mesh_faces.push_back(HL1MeshFace{
  849|    297|                                        tricmds[faceIdx + 1],
  850|    297|                                        tricmds[faceIdx],
  851|    297|                                        tricmds[faceIdx + 2] });
  852|    356|                            } else {
  853|    356|                                mesh_faces.push_back(HL1MeshFace{
  854|    356|                                        tricmds[faceIdx],
  855|    356|                                        tricmds[faceIdx + 1],
  856|    356|                                        tricmds[faceIdx + 2] });
  857|    356|                            }
  858|    653|                        }
  859|    142|                    }
  860|       |
  861|    154|                    total_triangles += num_faces;
  862|    154|                }
  863|       |
  864|       |                // Create the scene mesh.
  865|      3|                aiMesh *scene_mesh = scene_->mMeshes[mesh_index] = new aiMesh();
  866|      3|                scene_mesh->mPrimitiveTypes = aiPrimitiveType::aiPrimitiveType_TRIANGLE;
  867|      3|                scene_mesh->mMaterialIndex = pskinref[pmesh->skinref];
  868|       |
  869|      3|                scene_mesh->mNumVertices = static_cast<unsigned int>(mesh_triverts_indices.size());
  870|       |
  871|      3|                if (scene_mesh->mNumVertices) {
  ------------------
  |  Branch (871:21): [True: 3, False: 0]
  ------------------
  872|      3|                    scene_mesh->mVertices = new aiVector3D[scene_mesh->mNumVertices];
  873|      3|                    scene_mesh->mNormals = new aiVector3D[scene_mesh->mNumVertices];
  874|       |
  875|      3|                    scene_mesh->mNumUVComponents[0] = 2;
  876|      3|                    scene_mesh->mTextureCoords[0] = new aiVector3D[scene_mesh->mNumVertices];
  877|       |
  878|       |                    // Add vertices.
  879|    611|                    for (unsigned int v = 0; v < scene_mesh->mNumVertices; ++v) {
  ------------------
  |  Branch (879:46): [True: 608, False: 3]
  ------------------
  880|    608|                        const HL1MeshTrivert *pTrivert = &triverts[mesh_triverts_indices[v]];
  881|    608|                        scene_mesh->mVertices[v] = bind_pose_vertices[pTrivert->vertindex];
  882|    608|                        scene_mesh->mNormals[v] = bind_pose_normals[pTrivert->normindex];
  883|    608|                        scene_mesh->mTextureCoords[0][v] = aiVector3D(
  884|    608|                                pTrivert->s * texcoords_s_scale,
  885|    608|                                pTrivert->t * -texcoords_t_scale, 0);
  886|    608|                    }
  887|       |
  888|       |                    // Add face and indices.
  889|      3|                    scene_mesh->mNumFaces = static_cast<unsigned int>(mesh_faces.size());
  890|      3|                    scene_mesh->mFaces = new aiFace[scene_mesh->mNumFaces];
  891|       |
  892|    723|                    for (unsigned int f = 0; f < scene_mesh->mNumFaces; ++f) {
  ------------------
  |  Branch (892:46): [True: 720, False: 3]
  ------------------
  893|    720|                        aiFace *face = &scene_mesh->mFaces[f];
  894|    720|                        face->mNumIndices = 3;
  895|    720|                        face->mIndices = new unsigned int[3];
  896|    720|                        face->mIndices[0] = mesh_faces[f].v2;
  897|    720|                        face->mIndices[1] = mesh_faces[f].v1;
  898|    720|                        face->mIndices[2] = mesh_faces[f].v0;
  899|    720|                    }
  900|       |
  901|       |                    // Add mesh bones.
  902|      3|                    scene_mesh->mNumBones = static_cast<unsigned int>(bone_triverts.size());
  903|      3|                    scene_mesh->mBones = new aiBone *[scene_mesh->mNumBones];
  904|       |
  905|      3|                    aiBone **scene_bone_ptr = scene_mesh->mBones;
  906|       |
  907|      3|                    for (auto bone_it = bone_triverts.cbegin();
  908|     24|                            bone_it != bone_triverts.cend();
  ------------------
  |  Branch (908:29): [True: 21, False: 3]
  ------------------
  909|     21|                            ++bone_it, ++scene_bone_ptr) {
  910|     21|                        const int bone_index = bone_it->first;
  911|       |
  912|     21|                        aiBone *scene_bone = (*scene_bone_ptr) = new aiBone();
  913|     21|                        scene_bone->mName = temp_bones_[bone_index].node->mName;
  914|       |
  915|     21|                        scene_bone->mOffsetMatrix = temp_bones_[bone_index].offset_matrix;
  916|       |
  917|     21|                        auto vertex_ids = bone_triverts.at(bone_index);
  918|       |
  919|       |                        // Add vertex weight per bone.
  920|     21|                        scene_bone->mNumWeights = static_cast<unsigned int>(vertex_ids.size());
  921|     21|                        aiVertexWeight *vertex_weight_ptr = scene_bone->mWeights = new aiVertexWeight[scene_bone->mNumWeights];
  922|       |
  923|     21|                        for (auto vertex_it = vertex_ids.begin();
  924|    629|                                vertex_it != vertex_ids.end();
  ------------------
  |  Branch (924:33): [True: 608, False: 21]
  ------------------
  925|    608|                                ++vertex_it, ++vertex_weight_ptr) {
  926|    608|                            vertex_weight_ptr->mVertexId = *vertex_it;
  927|    608|                            vertex_weight_ptr->mWeight = 1.0f;
  928|    608|                        }
  929|     21|                    }
  930|      3|                }
  931|      3|            }
  932|      3|        }
  933|      4|    }
  934|       |
  935|      4|    if (total_triangles > AI_MDL_HL1_MAX_TRIANGLES) {
  ------------------
  |  |  543|      4|#define AI_MDL_HL1_MAX_TRIANGLES 20000
  ------------------
  |  Branch (935:9): [True: 0, False: 4]
  ------------------
  936|      0|        log_warning_limit_exceeded<AI_MDL_HL1_MAX_TRIANGLES>(total_triangles, "triangles");
  937|      0|    }
  938|      4|}
_ZN6Assimp3MDL8HalfLife12HL1MDLLoader15read_animationsEv:
  941|      4|void HL1MDLLoader::read_animations() {
  942|      4|    if (!header_->numseq) {
  ------------------
  |  Branch (942:9): [True: 0, False: 4]
  ------------------
  943|      0|        return;
  944|      0|    }
  945|       |
  946|      4|    const SequenceDesc_HL1 *pseqdesc = get_buffer_data<SequenceDesc_HL1>(header_->seqindex, header_->numseq);
  947|      4|    const SequenceGroup_HL1 *pseqgroup = nullptr;
  948|      4|    const AnimValueOffset_HL1 *panim = nullptr;
  949|      4|    const AnimValue_HL1 *panimvalue = nullptr;
  950|       |
  951|      4|    unique_sequence_names_.resize(header_->numseq);
  952|     16|    for (int i = 0; i < header_->numseq; ++i)
  ------------------
  |  Branch (952:21): [True: 12, False: 4]
  ------------------
  953|     12|        unique_sequence_names_[i] = pseqdesc[i].label;
  954|       |
  955|       |    // Ensure sequences have unique names.
  956|      4|    unique_name_generator_.set_template_name("Sequence");
  957|      4|    unique_name_generator_.make_unique(unique_sequence_names_);
  958|       |
  959|      4|    scene_->mNumAnimations = 0;
  960|       |
  961|      4|    int highest_num_blend_animations = SequenceBlendMode_HL1::NoBlend;
  962|       |
  963|       |    // Count the total number of animations.
  964|     16|    for (int i = 0; i < header_->numseq; ++i, ++pseqdesc) {
  ------------------
  |  Branch (964:21): [True: 12, False: 4]
  ------------------
  965|     12|        scene_->mNumAnimations += pseqdesc->numblends;
  966|     12|        highest_num_blend_animations = std::max(pseqdesc->numblends, highest_num_blend_animations);
  967|     12|    }
  968|       |
  969|       |    // Get the number of available blend controllers for global info.
  970|      4|    get_num_blend_controllers(highest_num_blend_animations, num_blend_controllers_);
  971|       |
  972|      4|    pseqdesc = get_buffer_data<SequenceDesc_HL1>(header_->seqindex, header_->numseq);
  973|       |
  974|      4|    aiAnimation **scene_animations_ptr = scene_->mAnimations = new aiAnimation *[scene_->mNumAnimations]();
  975|       |
  976|     10|    for (int sequence = 0; sequence < header_->numseq; ++sequence, ++pseqdesc) {
  ------------------
  |  Branch (976:28): [True: 6, False: 4]
  ------------------
  977|      6|        pseqgroup = get_buffer_data<SequenceGroup_HL1>(header_->seqgroupindex + pseqdesc->seqgroup * sizeof(SequenceGroup_HL1), 1);
  978|       |
  979|      6|        if (pseqdesc->seqgroup == 0) {
  ------------------
  |  Branch (979:13): [True: 3, False: 3]
  ------------------
  980|      3|            panim = get_buffer_data<AnimValueOffset_HL1>(pseqgroup->unused2 + pseqdesc->animindex, pseqdesc->numblends * header_->numbones);
  981|      3|        } else {
  982|      3|            panim = get_anim_buffer_data<AnimValueOffset_HL1>(pseqdesc->seqgroup, pseqdesc->animindex, pseqdesc->numblends * header_->numbones);
  983|      3|        }
  984|       |
  985|     11|        for (int blend = 0; blend < pseqdesc->numblends; ++blend, ++scene_animations_ptr) {
  ------------------
  |  Branch (985:29): [True: 5, False: 6]
  ------------------
  986|       |
  987|      5|            const Bone_HL1 *pbone = get_buffer_data<Bone_HL1>(header_->boneindex, header_->numbones);
  988|       |
  989|      5|            aiAnimation *scene_animation = (*scene_animations_ptr) = new aiAnimation();
  990|       |
  991|      5|            scene_animation->mName = unique_sequence_names_[sequence];
  992|      5|            scene_animation->mTicksPerSecond = pseqdesc->fps;
  993|      5|            scene_animation->mDuration = static_cast<double>(pseqdesc->fps) * pseqdesc->numframes;
  994|      5|            scene_animation->mNumChannels = static_cast<unsigned int>(header_->numbones);
  995|      5|            scene_animation->mChannels = new aiNodeAnim *[scene_animation->mNumChannels]();
  996|       |
  997|     28|            for (int bone = 0; bone < header_->numbones; bone++, ++pbone, ++panim) {
  ------------------
  |  Branch (997:32): [True: 23, False: 5]
  ------------------
  998|     23|                aiNodeAnim *node_anim = scene_animation->mChannels[bone] = new aiNodeAnim();
  999|     23|                node_anim->mNodeName = temp_bones_[bone].node->mName;
 1000|       |
 1001|     23|                node_anim->mNumPositionKeys = pseqdesc->numframes;
 1002|     23|                node_anim->mNumRotationKeys = node_anim->mNumPositionKeys;
 1003|     23|                node_anim->mNumScalingKeys = 0;
 1004|       |
 1005|     23|                node_anim->mPositionKeys = new aiVectorKey[node_anim->mNumPositionKeys];
 1006|     23|                node_anim->mRotationKeys = new aiQuatKey[node_anim->mNumRotationKeys];
 1007|       |
 1008|    291|                for (int frame = 0; frame < pseqdesc->numframes; ++frame) {
  ------------------
  |  Branch (1008:37): [True: 268, False: 23]
  ------------------
 1009|    268|                    aiVectorKey *position_key = &node_anim->mPositionKeys[frame];
 1010|    268|                    aiQuatKey *rotation_key = &node_anim->mRotationKeys[frame];
 1011|       |
 1012|    268|                    aiVector3D angle1;
 1013|  1.07k|                    for (int j = 0; j < 3; ++j) {
  ------------------
  |  Branch (1013:37): [True: 804, False: 268]
  ------------------
 1014|    804|                        if (panim->offset[j + 3] != 0) {
  ------------------
  |  Branch (1014:29): [True: 672, False: 132]
  ------------------
 1015|       |                            // Read compressed rotation delta.
 1016|    672|                            panimvalue = (const AnimValue_HL1 *)((uint8_t *)panim + panim->offset[j + 3]);
 1017|    672|                            extract_anim_value(panimvalue, frame, pbone->scale[j + 3], angle1[j]);
 1018|    672|                        }
 1019|       |
 1020|       |                        // Add the default rotation value.
 1021|    804|                        angle1[j] += pbone->value[j + 3];
 1022|       |
 1023|    804|                        if (panim->offset[j] != 0) {
  ------------------
  |  Branch (1023:29): [True: 12, False: 792]
  ------------------
 1024|       |                            // Read compressed position delta.
 1025|     12|                            panimvalue = (const AnimValue_HL1 *)((uint8_t *)panim + panim->offset[j]);
 1026|     12|                            extract_anim_value(panimvalue, frame, pbone->scale[j], position_key->mValue[j]);
 1027|     12|                        }
 1028|       |
 1029|       |                        // Add the default position value.
 1030|    804|                        position_key->mValue[j] += pbone->value[j];
 1031|    804|                    }
 1032|       |
 1033|    268|                    position_key->mTime = rotation_key->mTime = static_cast<double>(frame);
 1034|       |                    /* The Half-Life engine uses X as forward, Y as left, Z as up. Therefore,
 1035|       |                       pitch,yaw,roll is represented as (YZX). */
 1036|    268|                    rotation_key->mValue = aiQuaternion(angle1.y, angle1.z, angle1.x);
 1037|    268|                    rotation_key->mValue.Normalize();
 1038|    268|                }
 1039|     23|            }
 1040|      5|        }
 1041|      6|    }
 1042|      4|}
_ZN6Assimp3MDL8HalfLife12HL1MDLLoader25read_sequence_groups_infoEv:
 1045|      4|void HL1MDLLoader::read_sequence_groups_info() {
 1046|      4|    if (!header_->numseqgroups) {
  ------------------
  |  Branch (1046:9): [True: 0, False: 4]
  ------------------
 1047|      0|        return;
 1048|      0|    }
 1049|       |
 1050|      4|    aiNode *sequence_groups_node = new aiNode(AI_MDL_HL1_NODE_SEQUENCE_GROUPS);
  ------------------
  |  |   54|      4|#define AI_MDL_HL1_NODE_SEQUENCE_GROUPS "<MDL_sequence_groups>"
  ------------------
 1051|      4|    rootnode_children_.push_back(sequence_groups_node);
 1052|       |
 1053|      4|    sequence_groups_node->mNumChildren = static_cast<unsigned int>(header_->numseqgroups);
 1054|      4|    sequence_groups_node->mChildren = new aiNode *[sequence_groups_node->mNumChildren];
 1055|       |
 1056|      4|    const SequenceGroup_HL1 *pseqgroup = get_buffer_data<SequenceGroup_HL1>(header_->seqgroupindex, header_->numseqgroups);
 1057|       |
 1058|      4|    unique_sequence_groups_names_.resize(header_->numseqgroups);
 1059|     17|    for (int i = 0; i < header_->numseqgroups; ++i) {
  ------------------
  |  Branch (1059:21): [True: 13, False: 4]
  ------------------
 1060|     13|        unique_sequence_groups_names_[i] = pseqgroup[i].label;
 1061|     13|    }
 1062|       |
 1063|       |    // Ensure sequence groups have unique names.
 1064|      4|    unique_name_generator_.set_template_name("SequenceGroup");
 1065|      4|    unique_name_generator_.make_unique(unique_sequence_groups_names_);
 1066|       |
 1067|     17|    for (int i = 0; i < header_->numseqgroups; ++i, ++pseqgroup) {
  ------------------
  |  Branch (1067:21): [True: 13, False: 4]
  ------------------
 1068|     13|        aiNode *sequence_group_node = sequence_groups_node->mChildren[i] = new aiNode(unique_sequence_groups_names_[i]);
 1069|     13|        sequence_group_node->mParent = sequence_groups_node;
 1070|       |
 1071|     13|        aiMetadata *md = sequence_group_node->mMetaData = aiMetadata::Alloc(1);
 1072|     13|        if (i == 0) {
  ------------------
  |  Branch (1072:13): [True: 4, False: 9]
  ------------------
 1073|       |            /* StudioMDL does not write the file name for the default sequence group,
 1074|       |               so we will write it. */
 1075|      4|            md->Set(0, "File", aiString(file_path_));
 1076|      9|        } else {
 1077|      9|            md->Set(0, "File", aiString(pseqgroup->name));
 1078|      9|        }
 1079|     13|    }
 1080|      4|}
_ZN6Assimp3MDL8HalfLife12HL1MDLLoader19read_sequence_infosEv:
 1083|      3|void HL1MDLLoader::read_sequence_infos() {
 1084|      3|    if (!header_->numseq) {
  ------------------
  |  Branch (1084:9): [True: 0, False: 3]
  ------------------
 1085|      0|        return;
 1086|      0|    }
 1087|       |
 1088|      3|    const SequenceDesc_HL1 *pseqdesc = get_buffer_data<SequenceDesc_HL1>(header_->seqindex, header_->numseq);
 1089|       |
 1090|      3|    aiNode *sequence_infos_node = new aiNode(AI_MDL_HL1_NODE_SEQUENCE_INFOS);
  ------------------
  |  |   53|      3|#define AI_MDL_HL1_NODE_SEQUENCE_INFOS "<MDL_sequence_infos>"
  ------------------
 1091|      3|    rootnode_children_.push_back(sequence_infos_node);
 1092|       |
 1093|      3|    sequence_infos_node->mNumChildren = static_cast<unsigned int>(header_->numseq);
 1094|      3|    sequence_infos_node->mChildren = new aiNode *[sequence_infos_node->mNumChildren];
 1095|       |
 1096|      3|    std::vector<aiNode *> sequence_info_node_children;
 1097|       |
 1098|      3|    int animation_index = 0;
 1099|      6|    for (int i = 0; i < header_->numseq; ++i, ++pseqdesc) {
  ------------------
  |  Branch (1099:21): [True: 3, False: 3]
  ------------------
 1100|       |        // Clear the list of children for the upcoming sequence info node.
 1101|      3|        sequence_info_node_children.clear();
 1102|       |
 1103|      3|        aiNode *sequence_info_node = sequence_infos_node->mChildren[i] = new aiNode(unique_sequence_names_[i]);
 1104|      3|        sequence_info_node->mParent = sequence_infos_node;
 1105|       |
 1106|       |        // Setup sequence info node Metadata.
 1107|      3|        aiMetadata *md = sequence_info_node->mMetaData = aiMetadata::Alloc(16);
 1108|      3|        md->Set(0, "AnimationIndex", animation_index);
 1109|      3|        animation_index += pseqdesc->numblends;
 1110|       |
 1111|       |        // Reference the sequence group by name. This allows us to search a particular
 1112|       |        // sequence group by name using aiNode(s).
 1113|      3|        md->Set(1, "SequenceGroup", aiString(unique_sequence_groups_names_[pseqdesc->seqgroup]));
 1114|      3|        md->Set(2, "FramesPerSecond", pseqdesc->fps);
 1115|      3|        md->Set(3, "NumFrames", pseqdesc->numframes);
 1116|      3|        md->Set(4, "NumBlends", pseqdesc->numblends);
 1117|      3|        md->Set(5, "Activity", pseqdesc->activity);
 1118|      3|        md->Set(6, "ActivityWeight", pseqdesc->actweight);
 1119|      3|        md->Set(7, "MotionFlags", pseqdesc->motiontype);
 1120|      3|        md->Set(8, "MotionBone", temp_bones_[pseqdesc->motionbone].node->mName);
 1121|      3|        md->Set(9, "LinearMovement", aiVector3D(pseqdesc->linearmovement[0], pseqdesc->linearmovement[1], pseqdesc->linearmovement[2]));
 1122|      3|        md->Set(10, "BBMin", aiVector3D(pseqdesc->bbmin[0], pseqdesc->bbmin[1], pseqdesc->bbmin[2]));
 1123|      3|        md->Set(11, "BBMax", aiVector3D(pseqdesc->bbmax[0], pseqdesc->bbmax[1], pseqdesc->bbmax[2]));
 1124|      3|        md->Set(12, "EntryNode", pseqdesc->entrynode);
 1125|      3|        md->Set(13, "ExitNode", pseqdesc->exitnode);
 1126|      3|        md->Set(14, "NodeFlags", pseqdesc->nodeflags);
 1127|      3|        md->Set(15, "Flags", pseqdesc->flags);
 1128|       |
 1129|      3|        if (import_settings_.read_blend_controllers) {
  ------------------
  |  Branch (1129:13): [True: 3, False: 0]
  ------------------
 1130|      3|            int num_blend_controllers;
 1131|      3|            if (get_num_blend_controllers(pseqdesc->numblends, num_blend_controllers) && num_blend_controllers) {
  ------------------
  |  Branch (1131:17): [True: 3, False: 0]
  |  Branch (1131:90): [True: 0, False: 3]
  ------------------
 1132|       |                // Read blend controllers info.
 1133|      0|                aiNode *blend_controllers_node = new aiNode(AI_MDL_HL1_NODE_BLEND_CONTROLLERS);
  ------------------
  |  |   60|      0|#define AI_MDL_HL1_NODE_BLEND_CONTROLLERS "BlendControllers"
  ------------------
 1134|      0|                sequence_info_node_children.push_back(blend_controllers_node);
 1135|      0|                blend_controllers_node->mParent = sequence_info_node;
 1136|      0|                blend_controllers_node->mNumChildren = static_cast<unsigned int>(num_blend_controllers);
 1137|      0|                blend_controllers_node->mChildren = new aiNode *[blend_controllers_node->mNumChildren];
 1138|       |
 1139|      0|                for (unsigned int j = 0; j < blend_controllers_node->mNumChildren; ++j) {
  ------------------
  |  Branch (1139:42): [True: 0, False: 0]
  ------------------
 1140|      0|                    aiNode *blend_controller_node = blend_controllers_node->mChildren[j] = new aiNode();
 1141|      0|                    blend_controller_node->mParent = blend_controllers_node;
 1142|       |
 1143|      0|                    aiMetadata *metaData = blend_controller_node->mMetaData = aiMetadata::Alloc(3);
 1144|      0|                    metaData->Set(0, "Start", pseqdesc->blendstart[j]);
 1145|      0|                    metaData->Set(1, "End", pseqdesc->blendend[j]);
 1146|      0|                    metaData->Set(2, "MotionFlags", pseqdesc->blendtype[j]);
 1147|      0|                }
 1148|      0|            }
 1149|      3|        }
 1150|       |
 1151|      3|        if (import_settings_.read_animation_events && pseqdesc->numevents) {
  ------------------
  |  Branch (1151:13): [True: 3, False: 0]
  |  Branch (1151:55): [True: 0, False: 3]
  ------------------
 1152|       |            // Read animation events.
 1153|       |
 1154|      0|            if (pseqdesc->numevents > AI_MDL_HL1_MAX_EVENTS) {
  ------------------
  |  |  573|      0|#define AI_MDL_HL1_MAX_EVENTS 1024
  ------------------
  |  Branch (1154:17): [True: 0, False: 0]
  ------------------
 1155|      0|                log_warning_limit_exceeded<AI_MDL_HL1_MAX_EVENTS>(
 1156|      0|                        "Sequence " + std::string(pseqdesc->label),
 1157|      0|                        pseqdesc->numevents, "animation events");
 1158|      0|            }
 1159|       |
 1160|      0|            const AnimEvent_HL1 *pevent = get_buffer_data<AnimEvent_HL1>(pseqdesc->eventindex, pseqdesc->numevents);
 1161|       |
 1162|      0|            aiNode *pEventsNode = new aiNode(AI_MDL_HL1_NODE_ANIMATION_EVENTS);
  ------------------
  |  |   59|      0|#define AI_MDL_HL1_NODE_ANIMATION_EVENTS "AnimationEvents"
  ------------------
 1163|      0|            sequence_info_node_children.push_back(pEventsNode);
 1164|      0|            pEventsNode->mParent = sequence_info_node;
 1165|      0|            pEventsNode->mNumChildren = static_cast<unsigned int>(pseqdesc->numevents);
 1166|      0|            pEventsNode->mChildren = new aiNode *[pEventsNode->mNumChildren];
 1167|       |
 1168|      0|            for (unsigned int j = 0; j < pEventsNode->mNumChildren; ++j, ++pevent) {
  ------------------
  |  Branch (1168:38): [True: 0, False: 0]
  ------------------
 1169|      0|                aiNode *pEvent = pEventsNode->mChildren[j] = new aiNode();
 1170|      0|                pEvent->mParent = pEventsNode;
 1171|       |
 1172|      0|                aiMetadata *metaData = pEvent->mMetaData = aiMetadata::Alloc(3);
 1173|      0|                metaData->Set(0, "Frame", pevent->frame);
 1174|      0|                metaData->Set(1, "ScriptEvent", pevent->event);
 1175|      0|                metaData->Set(2, "Options", aiString(pevent->options));
 1176|      0|            }
 1177|      0|        }
 1178|       |
 1179|      3|        if (sequence_info_node_children.size()) {
  ------------------
  |  Branch (1179:13): [True: 0, False: 3]
  ------------------
 1180|      0|            sequence_info_node->addChildren(
 1181|      0|                    static_cast<unsigned int>(sequence_info_node_children.size()),
 1182|      0|                    sequence_info_node_children.data());
 1183|      0|        }
 1184|      3|    }
 1185|      3|}
_ZN6Assimp3MDL8HalfLife12HL1MDLLoader25read_sequence_transitionsEv:
 1188|      3|void HL1MDLLoader::read_sequence_transitions() {
 1189|      3|    if (!header_->numtransitions) {
  ------------------
  |  Branch (1189:9): [True: 3, False: 0]
  ------------------
 1190|      3|        return;
 1191|      3|    }
 1192|       |
 1193|       |    // Read sequence transition graph.
 1194|      0|    aiNode *transition_graph_node = new aiNode(AI_MDL_HL1_NODE_SEQUENCE_TRANSITION_GRAPH);
  ------------------
  |  |   55|      0|#define AI_MDL_HL1_NODE_SEQUENCE_TRANSITION_GRAPH "<MDL_sequence_transition_graph>"
  ------------------
 1195|      0|    rootnode_children_.push_back(transition_graph_node);
 1196|       |
 1197|      0|    const uint8_t *ptransitions = get_buffer_data<uint8_t>(header_->transitionindex, header_->numtransitions * header_->numtransitions);
 1198|      0|    aiMetadata *md = transition_graph_node->mMetaData = aiMetadata::Alloc(header_->numtransitions * header_->numtransitions);
 1199|      0|    for (unsigned int i = 0; i < md->mNumProperties; ++i)
  ------------------
  |  Branch (1199:30): [True: 0, False: 0]
  ------------------
 1200|      0|        md->Set(i, std::to_string(i), static_cast<int>(ptransitions[i]));
 1201|      0|}
_ZN6Assimp3MDL8HalfLife12HL1MDLLoader16read_attachmentsEv:
 1203|      3|void HL1MDLLoader::read_attachments() {
 1204|      3|    if (!header_->numattachments) {
  ------------------
  |  Branch (1204:9): [True: 3, False: 0]
  ------------------
 1205|      3|        return;
 1206|      3|    }
 1207|       |
 1208|      0|    const Attachment_HL1 *pattach = get_buffer_data<Attachment_HL1>(header_->attachmentindex, header_->numattachments);
 1209|       |
 1210|      0|    aiNode *attachments_node = new aiNode(AI_MDL_HL1_NODE_ATTACHMENTS);
  ------------------
  |  |   56|      0|#define AI_MDL_HL1_NODE_ATTACHMENTS "<MDL_attachments>"
  ------------------
 1211|      0|    rootnode_children_.push_back(attachments_node);
 1212|      0|    attachments_node->mNumChildren = static_cast<unsigned int>(header_->numattachments);
 1213|      0|    attachments_node->mChildren = new aiNode *[attachments_node->mNumChildren];
 1214|       |
 1215|      0|    for (int i = 0; i < header_->numattachments; ++i, ++pattach) {
  ------------------
  |  Branch (1215:21): [True: 0, False: 0]
  ------------------
 1216|      0|        aiNode *attachment_node = attachments_node->mChildren[i] = new aiNode();
 1217|      0|        attachment_node->mParent = attachments_node;
 1218|      0|        attachment_node->mMetaData = aiMetadata::Alloc(2);
 1219|      0|        attachment_node->mMetaData->Set(0, "Position", aiVector3D(pattach->org[0], pattach->org[1], pattach->org[2]));
 1220|       |        // Reference the bone by name. This allows us to search a particular
 1221|       |        // bone by name using aiNode(s).
 1222|      0|        attachment_node->mMetaData->Set(1, "Bone", temp_bones_[pattach->bone].node->mName);
 1223|      0|    }
 1224|      0|}
_ZN6Assimp3MDL8HalfLife12HL1MDLLoader13read_hitboxesEv:
 1227|      3|void HL1MDLLoader::read_hitboxes() {
 1228|      3|    if (!header_->numhitboxes) {
  ------------------
  |  Branch (1228:9): [True: 1, False: 2]
  ------------------
 1229|      1|        return;
 1230|      1|    }
 1231|       |
 1232|      2|    const Hitbox_HL1 *phitbox = get_buffer_data<Hitbox_HL1>(header_->hitboxindex, header_->numhitboxes);
 1233|       |
 1234|      2|    aiNode *hitboxes_node = new aiNode(AI_MDL_HL1_NODE_HITBOXES);
  ------------------
  |  |   57|      2|#define AI_MDL_HL1_NODE_HITBOXES "<MDL_hitboxes>"
  ------------------
 1235|      2|    rootnode_children_.push_back(hitboxes_node);
 1236|      2|    hitboxes_node->mNumChildren = static_cast<unsigned int>(header_->numhitboxes);
 1237|      2|    hitboxes_node->mChildren = new aiNode *[hitboxes_node->mNumChildren];
 1238|       |
 1239|      4|    for (int i = 0; i < header_->numhitboxes; ++i, ++phitbox) {
  ------------------
  |  Branch (1239:21): [True: 2, False: 2]
  ------------------
 1240|      2|        aiNode *hitbox_node = hitboxes_node->mChildren[i] = new aiNode();
 1241|      2|        hitbox_node->mParent = hitboxes_node;
 1242|       |
 1243|      2|        aiMetadata *md = hitbox_node->mMetaData = aiMetadata::Alloc(4);
 1244|       |        // Reference the bone by name. This allows us to search a particular
 1245|       |        // bone by name using aiNode(s).
 1246|      2|        md->Set(0, "Bone", temp_bones_[phitbox->bone].node->mName);
 1247|      2|        md->Set(1, "HitGroup", phitbox->group);
 1248|      2|        md->Set(2, "BBMin", aiVector3D(phitbox->bbmin[0], phitbox->bbmin[1], phitbox->bbmin[2]));
 1249|      2|        md->Set(3, "BBMax", aiVector3D(phitbox->bbmax[0], phitbox->bbmax[1], phitbox->bbmax[2]));
 1250|      2|    }
 1251|      2|}
_ZN6Assimp3MDL8HalfLife12HL1MDLLoader21read_bone_controllersEv:
 1254|      3|void HL1MDLLoader::read_bone_controllers() {
 1255|      3|    if (!header_->numbonecontrollers) {
  ------------------
  |  Branch (1255:9): [True: 3, False: 0]
  ------------------
 1256|      3|        return;
 1257|      3|    }
 1258|       |
 1259|      0|    const BoneController_HL1 *pbonecontroller = get_buffer_data<BoneController_HL1>(
 1260|      0|            header_->bonecontrollerindex,
 1261|      0|            header_->numbonecontrollers);
 1262|       |
 1263|      0|    aiNode *bones_controller_node = new aiNode(AI_MDL_HL1_NODE_BONE_CONTROLLERS);
  ------------------
  |  |   52|      0|#define AI_MDL_HL1_NODE_BONE_CONTROLLERS "<MDL_bone_controllers>"
  ------------------
 1264|      0|    rootnode_children_.push_back(bones_controller_node);
 1265|      0|    bones_controller_node->mNumChildren = static_cast<unsigned int>(header_->numbonecontrollers);
 1266|      0|    bones_controller_node->mChildren = new aiNode *[bones_controller_node->mNumChildren];
 1267|       |
 1268|      0|    for (int i = 0; i < header_->numbonecontrollers; ++i, ++pbonecontroller) {
  ------------------
  |  Branch (1268:21): [True: 0, False: 0]
  ------------------
 1269|      0|        aiNode *bone_controller_node = bones_controller_node->mChildren[i] = new aiNode();
 1270|      0|        bone_controller_node->mParent = bones_controller_node;
 1271|       |
 1272|      0|        aiMetadata *md = bone_controller_node->mMetaData = aiMetadata::Alloc(5);
 1273|       |        // Reference the bone by name. This allows us to search a particular
 1274|       |        // bone by name using aiNode(s).
 1275|      0|        md->Set(0, "Bone", temp_bones_[pbonecontroller->bone].node->mName);
 1276|      0|        md->Set(1, "MotionFlags", pbonecontroller->type);
 1277|      0|        md->Set(2, "Start", pbonecontroller->start);
 1278|      0|        md->Set(3, "End", pbonecontroller->end);
 1279|      0|        md->Set(4, "Channel", pbonecontroller->index);
 1280|      0|    }
 1281|      0|}
_ZN6Assimp3MDL8HalfLife12HL1MDLLoader16read_global_infoEv:
 1284|      3|void HL1MDLLoader::read_global_info() {
 1285|      3|    aiNode *global_info_node = new aiNode(AI_MDL_HL1_NODE_GLOBAL_INFO);
  ------------------
  |  |   58|      3|#define AI_MDL_HL1_NODE_GLOBAL_INFO "<MDL_global_info>"
  ------------------
 1286|      3|    rootnode_children_.push_back(global_info_node);
 1287|       |
 1288|      3|    aiMetadata *md = global_info_node->mMetaData = aiMetadata::Alloc(import_settings_.read_misc_global_info ? 16 : 11);
  ------------------
  |  Branch (1288:70): [True: 3, False: 0]
  ------------------
 1289|      3|    md->Set(0, "Version", AI_MDL_HL1_VERSION);
  ------------------
  |  |  540|      3|#define AI_MDL_HL1_VERSION 10
  ------------------
 1290|      3|    md->Set(1, "NumBodyparts", header_->numbodyparts);
 1291|      3|    md->Set(2, "NumModels", total_models_);
 1292|      3|    md->Set(3, "NumBones", header_->numbones);
 1293|      3|    md->Set(4, "NumAttachments", import_settings_.read_attachments ? header_->numattachments : 0);
  ------------------
  |  Branch (1293:34): [True: 3, False: 0]
  ------------------
 1294|      3|    md->Set(5, "NumSkinFamilies", texture_header_->numskinfamilies);
 1295|      3|    md->Set(6, "NumHitboxes", import_settings_.read_hitboxes ? header_->numhitboxes : 0);
  ------------------
  |  Branch (1295:31): [True: 3, False: 0]
  ------------------
 1296|      3|    md->Set(7, "NumBoneControllers", import_settings_.read_bone_controllers ? header_->numbonecontrollers : 0);
  ------------------
  |  Branch (1296:38): [True: 3, False: 0]
  ------------------
 1297|      3|    md->Set(8, "NumSequences", import_settings_.read_animations ? header_->numseq : 0);
  ------------------
  |  Branch (1297:32): [True: 3, False: 0]
  ------------------
 1298|      3|    md->Set(9, "NumBlendControllers", import_settings_.read_blend_controllers ? num_blend_controllers_ : 0);
  ------------------
  |  Branch (1298:39): [True: 3, False: 0]
  ------------------
 1299|      3|    md->Set(10, "NumTransitionNodes", import_settings_.read_sequence_transitions ? header_->numtransitions : 0);
  ------------------
  |  Branch (1299:39): [True: 3, False: 0]
  ------------------
 1300|       |
 1301|      3|    if (import_settings_.read_misc_global_info) {
  ------------------
  |  Branch (1301:9): [True: 3, False: 0]
  ------------------
 1302|      3|        md->Set(11, "EyePosition", aiVector3D(header_->eyeposition[0], header_->eyeposition[1], header_->eyeposition[2]));
 1303|      3|        md->Set(12, "HullMin", aiVector3D(header_->min[0], header_->min[1], header_->min[2]));
 1304|      3|        md->Set(13, "HullMax", aiVector3D(header_->max[0], header_->max[1], header_->max[2]));
 1305|      3|        md->Set(14, "CollisionMin", aiVector3D(header_->bbmin[0], header_->bbmin[1], header_->bbmin[2]));
 1306|      3|        md->Set(15, "CollisionMax", aiVector3D(header_->bbmax[0], header_->bbmax[1], header_->bbmax[2]));
 1307|      3|    }
 1308|      3|}
_ZN6Assimp3MDL8HalfLife12HL1MDLLoader18extract_anim_valueEPKNS1_13AnimValue_HL1EifRf:
 1328|    684|        int frame, float bone_scale, ai_real &value) {
 1329|    684|    int k = frame;
 1330|       |
 1331|       |    // find span of values that includes the frame we want
 1332|    847|    while (panimvalue->num.total <= k) {
  ------------------
  |  Branch (1332:12): [True: 163, False: 684]
  ------------------
 1333|    163|        k -= panimvalue->num.total;
 1334|    163|        panimvalue += panimvalue->num.valid + 1;
 1335|    163|    }
 1336|       |
 1337|       |    // Bah, missing blend!
 1338|    684|    if (panimvalue->num.valid > k) {
  ------------------
  |  Branch (1338:9): [True: 670, False: 14]
  ------------------
 1339|    670|        value = panimvalue[k + 1].value * bone_scale;
 1340|    670|    } else {
 1341|     14|        value = panimvalue[panimvalue->num.valid].value * bone_scale;
 1342|     14|    }
 1343|    684|}
_ZN6Assimp3MDL8HalfLife12HL1MDLLoader25get_num_blend_controllersEiRi:
 1347|      7|bool HL1MDLLoader::get_num_blend_controllers(const int num_blend_animations, int &num_blend_controllers) {
 1348|       |
 1349|      7|    switch (num_blend_animations) {
 1350|      6|        case SequenceBlendMode_HL1::NoBlend:
  ------------------
  |  Branch (1350:9): [True: 6, False: 1]
  ------------------
 1351|      6|            num_blend_controllers = 0;
 1352|      6|            return true;
 1353|      0|        case SequenceBlendMode_HL1::TwoWayBlending:
  ------------------
  |  Branch (1353:9): [True: 0, False: 7]
  ------------------
 1354|      0|            num_blend_controllers = 1;
 1355|      0|            return true;
 1356|      0|        case SequenceBlendMode_HL1::FourWayBlending:
  ------------------
  |  Branch (1356:9): [True: 0, False: 7]
  ------------------
 1357|      0|            num_blend_controllers = 2;
 1358|      0|            return true;
 1359|      1|        default:
  ------------------
  |  Branch (1359:9): [True: 1, False: 6]
  ------------------
 1360|      1|            num_blend_controllers = 0;
 1361|       |            ASSIMP_LOG_WARN(MDL_HALFLIFE_LOG_HEADER "Unsupported number of blend animations (", num_blend_animations, ")");
 1362|      1|            return false;
 1363|      7|    }
 1364|      7|}
HL1MDLLoader.cpp:_ZZN6Assimp3MDL8HalfLife12HL1MDLLoader11read_meshesEvENK3$_0clEis:
  688|    608|    auto AddTrivertToBone = [&](int bone, short trivert_index) {
  689|    608|        if (bone_triverts.count(bone) == 0)
  ------------------
  |  Branch (689:13): [True: 21, False: 587]
  ------------------
  690|     21|            bone_triverts.insert({ bone, std::set<short>{ trivert_index }});
  691|    587|        else
  692|    587|            bone_triverts[bone].insert(trivert_index);
  693|    608|    };
HL1MDLLoader.cpp:_ZZN6Assimp3MDL8HalfLife12HL1MDLLoader11read_meshesEvENK3$_1clERKNS1_7TrivertEi:
  699|    206|    auto AddSimilarTrivert = [&](const Trivert &trivert, const int bone) {
  700|    206|        HL1MeshTrivert new_trivert(trivert);
  701|    206|        new_trivert.localindex = static_cast<short>(mesh_triverts_indices.size());
  702|       |
  703|    206|        short new_trivert_index = static_cast<short>(triverts.size());
  704|       |
  705|    206|        if (triverts_similars.count(trivert.vertindex) == 0)
  ------------------
  |  Branch (705:13): [True: 160, False: 46]
  ------------------
  706|    160|            triverts_similars.insert({ trivert.vertindex, std::set<short>{ new_trivert_index }});
  707|     46|        else
  708|     46|            triverts_similars[trivert.vertindex].insert(new_trivert_index);
  709|       |
  710|    206|        triverts.push_back(new_trivert);
  711|       |
  712|    206|        mesh_triverts_indices.push_back(new_trivert_index);
  713|    206|        tricmds.push_back(new_trivert.localindex);
  714|    206|        AddTrivertToBone(bone, new_trivert.localindex);
  715|    206|    };

_ZN6Assimp3MDL8HalfLife12HL1MDLLoader8TempBoneC2Ev:
  231|     22|            node(nullptr),
  232|     22|            absolute_transform(),
  233|     22|            offset_matrix(),
  234|     22|            children() {}
_ZN6Assimp3MDL8HalfLife12HL1MDLLoader15get_buffer_dataINS1_10Header_HL1EEEPKT_ii:
  290|      4|const DataType *HL1MDLLoader::get_buffer_data(int offset, int elements) {
  291|      4|    return buffer_.get_data<DataType>(offset, elements);
  292|      4|}
_ZN6Assimp3MDL8HalfLife12HL1MDLLoader23get_texture_buffer_dataINS1_10Header_HL1EEEPKT_ii:
  276|      4|const DataType *HL1MDLLoader::get_texture_buffer_data(int offset, int elements) {
  277|      4|    return texture_buffer_.get_data<DataType>(offset, elements);
  278|      4|}
_ZN6Assimp3MDL8HalfLife12HL1MDLLoader21load_file_into_bufferINS1_18SequenceHeader_HL1EEEvRKNSt3__112basic_stringIcNS5_11char_traitsIcEENS5_9allocatorIcEEEERNS1_13HL1DataBufferE:
  253|      9|void HL1MDLLoader::load_file_into_buffer(const std::string &file_path, HL1DataBuffer &buffer) {
  254|      9|    if (!io_->Exists(file_path))
  ------------------
  |  Branch (254:9): [True: 0, False: 9]
  ------------------
  255|      0|        throw DeadlyImportError("Missing file ", DefaultIOSystem::fileName(file_path), ".");
  256|       |
  257|      9|    std::unique_ptr<IOStream> file(io_->Open(file_path));
  258|       |
  259|      9|    if (file == nullptr) {
  ------------------
  |  Branch (259:9): [True: 0, False: 9]
  ------------------
  260|      0|        throw DeadlyImportError("Failed to open MDL file ", DefaultIOSystem::fileName(file_path), ".");
  261|      0|    }
  262|       |
  263|      9|    const size_t file_size = file->FileSize();
  264|      9|    if (file_size < sizeof(MDLFileHeader)) {
  ------------------
  |  Branch (264:9): [True: 0, False: 9]
  ------------------
  265|      0|        throw DeadlyImportError("MDL file is too small.");
  266|      0|    }
  267|       |
  268|      9|    std::unique_ptr<unsigned char[]> data(new unsigned char[1 + file_size]);
  269|      9|    file->Read(data.get(), 1, file_size);
  270|      9|    data[file_size] = '\0';
  271|       |
  272|      9|    buffer = HL1DataBuffer::owning(std::move(data), file_size);
  273|      9|}
_ZN6Assimp3MDL8HalfLife12HL1MDLLoader20get_anim_buffer_dataINS1_18SequenceHeader_HL1EEEPKT_iii:
  281|      9|const DataType *HL1MDLLoader::get_anim_buffer_data(int animation, int offset, int elements) {
  282|      9|    if (animation < 0 || animation >= num_sequence_groups_) {
  ------------------
  |  Branch (282:9): [True: 0, False: 9]
  |  Branch (282:26): [True: 0, False: 9]
  ------------------
  283|      0|        throw DeadlyImportError("MDL file contains invalid sequence group index (", animation, ")");
  284|      0|    }
  285|       |
  286|      9|    return anim_buffers_[animation].get_data<DataType>(offset, elements);
  287|      9|}
_ZN6Assimp3MDL8HalfLife12HL1MDLLoader23get_texture_buffer_dataINS1_11Texture_HL1EEEPKT_ii:
  276|      8|const DataType *HL1MDLLoader::get_texture_buffer_data(int offset, int elements) {
  277|      8|    return texture_buffer_.get_data<DataType>(offset, elements);
  278|      8|}
_ZN6Assimp3MDL8HalfLife12HL1MDLLoader23get_texture_buffer_dataIhEEPKT_ii:
  276|      8|const DataType *HL1MDLLoader::get_texture_buffer_data(int offset, int elements) {
  277|      8|    return texture_buffer_.get_data<DataType>(offset, elements);
  278|      8|}
_ZN6Assimp3MDL8HalfLife12HL1MDLLoader23get_texture_buffer_dataIsEEPKT_ii:
  276|      4|const DataType *HL1MDLLoader::get_texture_buffer_data(int offset, int elements) {
  277|      4|    return texture_buffer_.get_data<DataType>(offset, elements);
  278|      4|}
_ZN6Assimp3MDL8HalfLife12HL1MDLLoader15get_buffer_dataINS1_8Bone_HL1EEEPKT_ii:
  290|      9|const DataType *HL1MDLLoader::get_buffer_data(int offset, int elements) {
  291|      9|    return buffer_.get_data<DataType>(offset, elements);
  292|      9|}
_ZN6Assimp3MDL8HalfLife12HL1MDLLoader15get_buffer_dataINS1_12Bodypart_HL1EEEPKT_ii:
  290|     12|const DataType *HL1MDLLoader::get_buffer_data(int offset, int elements) {
  291|     12|    return buffer_.get_data<DataType>(offset, elements);
  292|     12|}
_ZN6Assimp3MDL8HalfLife12HL1MDLLoader15get_buffer_dataINS1_9Model_HL1EEEPKT_ii:
  290|     12|const DataType *HL1MDLLoader::get_buffer_data(int offset, int elements) {
  291|     12|    return buffer_.get_data<DataType>(offset, elements);
  292|     12|}
_ZN6Assimp3MDL8HalfLife12HL1MDLLoader15get_buffer_dataINS1_8Mesh_HL1EEEPKT_ii:
  290|      3|const DataType *HL1MDLLoader::get_buffer_data(int offset, int elements) {
  291|      3|    return buffer_.get_data<DataType>(offset, elements);
  292|      3|}
_ZN6Assimp3MDL8HalfLife12HL1MDLLoader15get_buffer_dataIhEEPKT_ii:
  290|      6|const DataType *HL1MDLLoader::get_buffer_data(int offset, int elements) {
  291|      6|    return buffer_.get_data<DataType>(offset, elements);
  292|      6|}
_ZN6Assimp3MDL8HalfLife12HL1MDLLoader15get_buffer_dataIA3_fEEPKT_ii:
  290|      6|const DataType *HL1MDLLoader::get_buffer_data(int offset, int elements) {
  291|      6|    return buffer_.get_data<DataType>(offset, elements);
  292|      6|}
_ZN6Assimp3MDL8HalfLife12HL1MDLLoader15get_buffer_dataINS1_16SequenceDesc_HL1EEEPKT_ii:
  290|     11|const DataType *HL1MDLLoader::get_buffer_data(int offset, int elements) {
  291|     11|    return buffer_.get_data<DataType>(offset, elements);
  292|     11|}
_ZN6Assimp3MDL8HalfLife12HL1MDLLoader15get_buffer_dataINS1_17SequenceGroup_HL1EEEPKT_ii:
  290|     10|const DataType *HL1MDLLoader::get_buffer_data(int offset, int elements) {
  291|     10|    return buffer_.get_data<DataType>(offset, elements);
  292|     10|}
_ZN6Assimp3MDL8HalfLife12HL1MDLLoader15get_buffer_dataINS1_19AnimValueOffset_HL1EEEPKT_ii:
  290|      3|const DataType *HL1MDLLoader::get_buffer_data(int offset, int elements) {
  291|      3|    return buffer_.get_data<DataType>(offset, elements);
  292|      3|}
_ZN6Assimp3MDL8HalfLife12HL1MDLLoader20get_anim_buffer_dataINS1_19AnimValueOffset_HL1EEEPKT_iii:
  281|      2|const DataType *HL1MDLLoader::get_anim_buffer_data(int animation, int offset, int elements) {
  282|      2|    if (animation < 0 || animation >= num_sequence_groups_) {
  ------------------
  |  Branch (282:9): [True: 0, False: 2]
  |  Branch (282:26): [True: 0, False: 2]
  ------------------
  283|      0|        throw DeadlyImportError("MDL file contains invalid sequence group index (", animation, ")");
  284|      0|    }
  285|       |
  286|      2|    return anim_buffers_[animation].get_data<DataType>(offset, elements);
  287|      2|}
_ZN6Assimp3MDL8HalfLife12HL1MDLLoader15get_buffer_dataINS1_10Hitbox_HL1EEEPKT_ii:
  290|      2|const DataType *HL1MDLLoader::get_buffer_data(int offset, int elements) {
  291|      2|    return buffer_.get_data<DataType>(offset, elements);
  292|      2|}

_ZN6Assimp3MDL8HalfLife14HL1MeshTrivertaSERKNS1_7TrivertE:
  105|    402|    inline HL1MeshTrivert &operator=(const Trivert &other) {
  106|    402|        vertindex = other.vertindex;
  107|    402|        normindex = other.normindex;
  108|    402|        s = other.s;
  109|    402|        t = other.t;
  110|    402|        return *this;
  111|    402|    }
_ZNK6Assimp3MDL8HalfLife14HL1MeshTriverteqERKNS1_7TrivertE:
   82|    672|    inline bool operator==(const Trivert &a) const {
   83|    672|        return vertindex == a.vertindex &&
  ------------------
  |  Branch (83:16): [True: 672, False: 0]
  ------------------
   84|    672|               normindex == a.normindex &&
  ------------------
  |  Branch (84:16): [True: 458, False: 214]
  ------------------
   85|    458|               s == a.s &&
  ------------------
  |  Branch (85:16): [True: 458, False: 0]
  ------------------
   86|    458|               t == a.t;
  ------------------
  |  Branch (86:16): [True: 420, False: 38]
  ------------------
   87|    672|    }
_ZN6Assimp3MDL8HalfLife14HL1MeshTrivertC2ERKNS1_7TrivertE:
   75|    206|            vertindex(a.vertindex),
   76|    206|            normindex(a.normindex),
   77|    206|            s(a.s),
   78|    206|            t(a.t),
   79|    206|            localindex(-1) {
   80|    206|    }
_ZN6Assimp3MDL8HalfLife14HL1MeshTrivertC2Ev:
   59|    402|            vertindex(-1),
   60|    402|            normindex(-1),
   61|    402|            s(0),
   62|    402|            t(0),
   63|    402|            localindex(-1) {
   64|    402|    }

_ZN6Assimp3MDL8HalfLife19UniqueNameGeneratorC2Ev:
   57|      4|    template_name_("unnamed"),
   58|      4|    separator_("_") {
   59|      4|}
_ZN6Assimp3MDL8HalfLife19UniqueNameGeneratorD2Ev:
   71|      4|UniqueNameGenerator::~UniqueNameGenerator() = default;
_ZN6Assimp3MDL8HalfLife19UniqueNameGenerator11make_uniqueERNSt3__16vectorINS3_12basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEENS8_ISA_EEEE:
   73|     20|void UniqueNameGenerator::make_unique(std::vector<std::string> &names) {
   74|     20|    struct DuplicateInfo {
   75|     20|        DuplicateInfo() :
   76|     20|            indices(),
   77|     20|            next_id(0) {
   78|     20|        }
   79|       |
   80|     20|        std::list<size_t> indices;
   81|     20|        size_t next_id;
   82|     20|    };
   83|       |
   84|     20|    std::vector<size_t> empty_names_indices;
   85|     20|    std::vector<size_t> template_name_duplicates;
   86|     20|    std::map<std::string, DuplicateInfo> names_to_duplicates;
   87|       |
   88|     20|    const std::string template_name_with_separator(template_name_ + separator_);
   89|       |
   90|     20|    auto format_name = [&](const std::string &base_name, size_t id) -> std::string {
   91|     20|        return base_name + separator_ + std::to_string(id);
   92|     20|    };
   93|       |
   94|     20|    auto generate_unique_name = [&](const std::string &base_name) -> std::string {
   95|     20|        auto *duplicate_info = &names_to_duplicates[base_name];
   96|       |
   97|     20|        std::string new_name;
   98|       |
   99|     20|        bool found_identical_name;
  100|     20|        bool tried_with_base_name_only = false;
  101|     20|        do {
  102|       |            // Assume that no identical name exists.
  103|     20|            found_identical_name = false;
  104|       |
  105|     20|            if (!tried_with_base_name_only) {
  106|       |                // First try with only the base name.
  107|     20|                new_name = base_name;
  108|     20|            } else {
  109|       |                // Create the name expected to be unique.
  110|     20|                new_name = format_name(base_name, duplicate_info->next_id);
  111|     20|            }
  112|       |
  113|       |            // Check in the list of duplicates for an identical name.
  114|     20|            for (size_t i = 0;
  115|     20|                    i < names.size() &&
  116|     20|                    !found_identical_name;
  117|     20|                    ++i) {
  118|     20|                if (new_name == names[i])
  119|     20|                    found_identical_name = true;
  120|     20|            }
  121|       |
  122|     20|            if (tried_with_base_name_only)
  123|     20|                ++duplicate_info->next_id;
  124|       |
  125|     20|            tried_with_base_name_only = true;
  126|       |
  127|     20|        } while (found_identical_name);
  128|       |
  129|     20|        return new_name;
  130|     20|    };
  131|       |
  132|     74|    for (size_t i = 0; i < names.size(); ++i) {
  ------------------
  |  Branch (132:24): [True: 54, False: 20]
  ------------------
  133|       |        // Check for empty names.
  134|     54|        if (names[i].find_first_not_of(' ') == std::string::npos) {
  ------------------
  |  Branch (134:13): [True: 10, False: 44]
  ------------------
  135|     10|            empty_names_indices.push_back(i);
  136|     10|            continue;
  137|     10|        }
  138|       |
  139|       |        /* Check for potential duplicate.
  140|       |        a) Either if this name is the same as the template name or
  141|       |        b) <template name><separator> is found at the beginning. */
  142|     44|        if (names[i] == template_name_ ||
  ------------------
  |  Branch (142:13): [True: 3, False: 41]
  |  Branch (142:13): [True: 3, False: 41]
  ------------------
  143|     41|                names[i].substr(0, template_name_with_separator.length()) == template_name_with_separator)
  ------------------
  |  Branch (143:17): [True: 0, False: 41]
  ------------------
  144|      3|            template_name_duplicates.push_back(i);
  145|       |
  146|       |        // Map each unique name to it's duplicate.
  147|     44|        if (names_to_duplicates.count(names[i]) == 0)
  ------------------
  |  Branch (147:13): [True: 41, False: 3]
  ------------------
  148|     41|            names_to_duplicates.insert({ names[i], DuplicateInfo()});
  149|      3|        else
  150|      3|            names_to_duplicates[names[i]].indices.push_back(i);
  151|     44|    }
  152|       |
  153|       |    // Make every non-empty name unique.
  154|     20|    for (auto it = names_to_duplicates.begin();
  155|     61|            it != names_to_duplicates.end(); ++it) {
  ------------------
  |  Branch (155:13): [True: 41, False: 20]
  ------------------
  156|     41|        for (auto it2 = it->second.indices.begin();
  157|     44|                it2 != it->second.indices.end();
  ------------------
  |  Branch (157:17): [True: 3, False: 41]
  ------------------
  158|     41|                ++it2)
  159|      3|            names[*it2] = generate_unique_name(it->first);
  160|     41|    }
  161|       |
  162|       |    // Generate a unique name for every empty string.
  163|     20|    if (template_name_duplicates.size()) {
  ------------------
  |  Branch (163:9): [True: 3, False: 17]
  ------------------
  164|       |        // At least one string ressembles to <template name>.
  165|      3|        for (auto it = empty_names_indices.begin();
  166|      3|                it != empty_names_indices.end(); ++it)
  ------------------
  |  Branch (166:17): [True: 0, False: 3]
  ------------------
  167|      0|            names[*it] = generate_unique_name(template_name_);
  168|     17|    } else {
  169|       |        // No string alike <template name> exists.
  170|     17|        size_t i = 0;
  171|     17|        for (auto it = empty_names_indices.begin();
  172|     27|                it != empty_names_indices.end(); ++it, ++i)
  ------------------
  |  Branch (172:17): [True: 10, False: 17]
  ------------------
  173|     10|            names[*it] = format_name(template_name_, i);
  174|     17|    }
  175|     20|}
UniqueNameGenerator.cpp:_ZZN6Assimp3MDL8HalfLife19UniqueNameGenerator11make_uniqueERNSt3__16vectorINS3_12basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEENS8_ISA_EEEEEN13DuplicateInfoC2Ev:
   76|     41|            indices(),
   77|     41|            next_id(0) {
   78|     41|        }
UniqueNameGenerator.cpp:_ZZN6Assimp3MDL8HalfLife19UniqueNameGenerator11make_uniqueERNSt3__16vectorINS3_12basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEENS8_ISA_EEEEENK3$_0clERKSA_:
   94|      3|    auto generate_unique_name = [&](const std::string &base_name) -> std::string {
   95|      3|        auto *duplicate_info = &names_to_duplicates[base_name];
   96|       |
   97|      3|        std::string new_name;
   98|       |
   99|      3|        bool found_identical_name;
  100|      3|        bool tried_with_base_name_only = false;
  101|      6|        do {
  102|       |            // Assume that no identical name exists.
  103|      6|            found_identical_name = false;
  104|       |
  105|      6|            if (!tried_with_base_name_only) {
  ------------------
  |  Branch (105:17): [True: 3, False: 3]
  ------------------
  106|       |                // First try with only the base name.
  107|      3|                new_name = base_name;
  108|      3|            } else {
  109|       |                // Create the name expected to be unique.
  110|      3|                new_name = format_name(base_name, duplicate_info->next_id);
  111|      3|            }
  112|       |
  113|       |            // Check in the list of duplicates for an identical name.
  114|      6|            for (size_t i = 0;
  115|     51|                    i < names.size() &&
  ------------------
  |  Branch (115:21): [True: 48, False: 3]
  ------------------
  116|     48|                    !found_identical_name;
  ------------------
  |  Branch (116:21): [True: 45, False: 3]
  ------------------
  117|     45|                    ++i) {
  118|     45|                if (new_name == names[i])
  ------------------
  |  Branch (118:21): [True: 3, False: 42]
  ------------------
  119|      3|                    found_identical_name = true;
  120|     45|            }
  121|       |
  122|      6|            if (tried_with_base_name_only)
  ------------------
  |  Branch (122:17): [True: 3, False: 3]
  ------------------
  123|      3|                ++duplicate_info->next_id;
  124|       |
  125|      6|            tried_with_base_name_only = true;
  126|       |
  127|      6|        } while (found_identical_name);
  ------------------
  |  Branch (127:18): [True: 3, False: 3]
  ------------------
  128|       |
  129|      3|        return new_name;
  130|      3|    };
UniqueNameGenerator.cpp:_ZZN6Assimp3MDL8HalfLife19UniqueNameGenerator11make_uniqueERNSt3__16vectorINS3_12basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEENS8_ISA_EEEEENK3$_1clERKSA_m:
   90|     13|    auto format_name = [&](const std::string &base_name, size_t id) -> std::string {
   91|     13|        return base_name + separator_ + std::to_string(id);
   92|     13|    };

_ZN6Assimp3MDL8HalfLife19UniqueNameGenerator17set_template_nameEPKc:
   63|     20|    inline void set_template_name(const char *template_name) {
   64|     20|        template_name_ = template_name;
   65|     20|    }

_ZN6Assimp3MDL12IntFace_MDL7C2Ev:
  721|  2.40k|    IntFace_MDL7() AI_NO_EXCEPT {
  722|  2.40k|        ::memset( mIndices, 0, sizeof(uint32_t) *3);
  723|  2.40k|        ::memset( iMatIndex, 0, sizeof( unsigned int) *2);
  724|  2.40k|    }
_ZN6Assimp3MDL17IntGroupInfo_MDL7C2EPKNS0_10Group_MDL7Ej:
  816|     23|        :   iIndex(_iIndex)
  817|     23|        ,   pcGroup(_pcGroup)
  818|       |        ,   pcGroupUVs()
  819|       |        ,   pcGroupTris()
  820|       |        ,   pcGroupVerts()
  821|     23|    {}
_ZN6Assimp3MDL17IntGroupData_MDL7C2Ev:
  844|     20|        : bNeed2UV(false)
  845|     20|    {}
_ZN6Assimp3MDL18IntSharedData_MDL7C2Ev:
  877|      4|    {
  878|      4|        abNeedMaterials.reserve(12);
  879|      4|    }
_ZN6Assimp3MDL18IntSharedData_MDL7D2Ev:
  883|      4|    {
  884|       |        // kill all bones
  885|      4|        if (this->apcOutBones)
  ------------------
  |  Branch (885:13): [True: 0, False: 4]
  ------------------
  886|      0|        {
  887|      0|            for (unsigned int m = 0; m < iNum;++m)
  ------------------
  |  Branch (887:38): [True: 0, False: 0]
  ------------------
  888|      0|                delete this->apcOutBones[m];
  889|      0|            delete[] this->apcOutBones;
  890|      0|        }
  891|      4|    }
_ZN6Assimp3MDL22IntSplitGroupData_MDL7C2ERNS0_18IntSharedData_MDL7ERNSt3__16vectorIP6aiMeshNS4_9allocatorIS7_EEEE:
  914|     20|        : aiSplit(), shared(_shared), avOutList(_avOutList)
  915|     20|    {
  916|     20|    }
_ZN6Assimp3MDL22IntSplitGroupData_MDL7D2Ev:
  920|     20|    {
  921|       |        // kill all face lists
  922|     20|        if(this->aiSplit)
  ------------------
  |  Branch (922:12): [True: 20, False: 0]
  ------------------
  923|     20|        {
  924|     80|            for (unsigned int m = 0; m < shared.pcMats.size();++m)
  ------------------
  |  Branch (924:38): [True: 60, False: 20]
  ------------------
  925|     60|                delete this->aiSplit[m];
  926|     20|            delete[] this->aiSplit;
  927|     20|        }
  928|     20|    }

_ZN6Assimp11MDLImporterC2Ev:
   96|  1.24k|        configFrameID(), mBuffer(), iGSFileVersion(), mIOHandler(nullptr), pScene(), iFileSize() {
   97|       |    // empty
   98|  1.24k|}
_ZNK6Assimp11MDLImporter7CanReadERKNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEPNS_8IOSystemEb:
  102|    464|bool MDLImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool /*checkSig*/) const {
  103|    464|    static constexpr uint32_t tokens[] = {
  104|    464|        AI_MDL_MAGIC_NUMBER_LE_HL2a,
  ------------------
  |  |   60|    464|#define AI_MDL_MAGIC_NUMBER_LE_HL2a AI_MAKE_MAGIC("TSDI")
  ------------------
  105|    464|        AI_MDL_MAGIC_NUMBER_LE_HL2b,
  ------------------
  |  |   62|    464|#define AI_MDL_MAGIC_NUMBER_LE_HL2b AI_MAKE_MAGIC("QSDI")
  ------------------
  106|    464|        AI_MDL_MAGIC_NUMBER_LE_GS7,
  ------------------
  |  |   91|    464|#define AI_MDL_MAGIC_NUMBER_LE_GS7  AI_MAKE_MAGIC("7LDM")
  ------------------
  107|    464|        AI_MDL_MAGIC_NUMBER_LE_GS5b,
  ------------------
  |  |   87|    464|#define AI_MDL_MAGIC_NUMBER_LE_GS5b AI_MAKE_MAGIC("5LDM")
  ------------------
  108|    464|        AI_MDL_MAGIC_NUMBER_LE_GS5a,
  ------------------
  |  |   85|    464|#define AI_MDL_MAGIC_NUMBER_LE_GS5a AI_MAKE_MAGIC("4LDM")
  ------------------
  109|    464|        AI_MDL_MAGIC_NUMBER_LE_GS4,
  ------------------
  |  |   81|    464|#define AI_MDL_MAGIC_NUMBER_LE_GS4  AI_MAKE_MAGIC("3LDM")
  ------------------
  110|    464|        AI_MDL_MAGIC_NUMBER_LE_GS3,
  ------------------
  |  |   77|    464|#define AI_MDL_MAGIC_NUMBER_LE_GS3  AI_MAKE_MAGIC("2LDM")
  ------------------
  111|    464|        AI_MDL_MAGIC_NUMBER_LE
  ------------------
  |  |   73|    464|#define AI_MDL_MAGIC_NUMBER_LE  AI_MAKE_MAGIC("OPDI")
  ------------------
  112|    464|    };
  113|       |    return CheckMagicToken(pIOHandler, pFile, tokens, AI_COUNT_OF(tokens));
  114|    464|}
_ZN6Assimp11MDLImporter15SetupPropertiesEPKNS_8ImporterE:
  118|     11|void MDLImporter::SetupProperties(const Importer *pImp) {
  119|     11|    configFrameID = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_MDL_KEYFRAME, -1);
  120|       |
  121|       |    // The
  122|       |    // AI_CONFIG_IMPORT_MDL_KEYFRAME option overrides the
  123|       |    // AI_CONFIG_IMPORT_GLOBAL_KEYFRAME option.
  124|     11|    if (static_cast<unsigned int>(-1) == configFrameID) {
  ------------------
  |  Branch (124:9): [True: 11, False: 0]
  ------------------
  125|     11|        configFrameID = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_GLOBAL_KEYFRAME, 0);
  126|     11|    }
  127|       |
  128|       |    // AI_CONFIG_IMPORT_MDL_COLORMAP - palette file
  129|     11|    configPalette = pImp->GetPropertyString(AI_CONFIG_IMPORT_MDL_COLORMAP, "colormap.lmp");
  130|       |
  131|       |    // Read configuration specific to MDL (Half-Life 1).
  132|     11|    mHL1ImportSettings.read_animations = pImp->GetPropertyBool(AI_CONFIG_IMPORT_MDL_HL1_READ_ANIMATIONS, true);
  133|     11|    if (mHL1ImportSettings.read_animations) {
  ------------------
  |  Branch (133:9): [True: 11, False: 0]
  ------------------
  134|     11|        mHL1ImportSettings.read_animation_events = pImp->GetPropertyBool(AI_CONFIG_IMPORT_MDL_HL1_READ_ANIMATION_EVENTS, true);
  135|     11|        mHL1ImportSettings.read_blend_controllers = pImp->GetPropertyBool(AI_CONFIG_IMPORT_MDL_HL1_READ_BLEND_CONTROLLERS, true);
  136|     11|        mHL1ImportSettings.read_sequence_transitions = pImp->GetPropertyBool(AI_CONFIG_IMPORT_MDL_HL1_READ_SEQUENCE_TRANSITIONS, true);
  137|     11|    }
  138|     11|    mHL1ImportSettings.read_attachments = pImp->GetPropertyBool(AI_CONFIG_IMPORT_MDL_HL1_READ_ATTACHMENTS, true);
  139|     11|    mHL1ImportSettings.read_bone_controllers = pImp->GetPropertyBool(AI_CONFIG_IMPORT_MDL_HL1_READ_BONE_CONTROLLERS, true);
  140|     11|    mHL1ImportSettings.read_hitboxes = pImp->GetPropertyBool(AI_CONFIG_IMPORT_MDL_HL1_READ_HITBOXES, true);
  141|     11|    mHL1ImportSettings.read_misc_global_info = pImp->GetPropertyBool(AI_CONFIG_IMPORT_MDL_HL1_READ_MISC_GLOBAL_INFO, true);
  142|       |    mHL1ImportSettings.transform_coord_system = pImp->GetPropertyBool(AI_CONFIG_IMPORT_MDL_HL1_TRANSFORM_COORD_SYSTEM);
  143|     11|}
_ZNK6Assimp11MDLImporter7GetInfoEv:
  147|    645|const aiImporterDesc *MDLImporter::GetInfo() const {
  148|    645|    return &desc;
  149|    645|}
_ZN6Assimp11MDLImporter14InternReadFileERKNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEP7aiScenePNS_8IOSystemE:
  168|     11|        aiScene *_pScene, IOSystem *pIOHandler) {
  169|     11|    pScene = _pScene;
  170|     11|    mIOHandler = pIOHandler;
  171|     11|    std::unique_ptr<IOStream> file(pIOHandler->Open(pFile));
  172|       |
  173|       |    // Check whether we can read from the file
  174|     11|    if (file == nullptr) {
  ------------------
  |  Branch (174:9): [True: 0, False: 11]
  ------------------
  175|      0|        throw DeadlyImportError("Failed to open MDL file ", pFile, ".");
  176|      0|    }
  177|       |
  178|       |    // This should work for all other types of MDL files, too ...
  179|       |    // the HL1 sequence group header is one of the smallest, afaik
  180|     11|    iFileSize = (unsigned int)file->FileSize();
  181|     11|    if (iFileSize < sizeof(MDL::HalfLife::SequenceHeader_HL1)) {
  ------------------
  |  Branch (181:9): [True: 0, False: 11]
  ------------------
  182|      0|        throw DeadlyImportError("MDL File is too small.");
  183|      0|    }
  184|       |
  185|       |    // delete the file buffer and cleanup.
  186|     11|    auto DeleteBufferAndCleanup = [&]() {
  187|     11|        if (mBuffer) {
  188|     11|            delete[] mBuffer;
  189|     11|            mBuffer = nullptr;
  190|     11|        }
  191|     11|        AI_DEBUG_INVALIDATE_PTR(mIOHandler);
  192|     11|        AI_DEBUG_INVALIDATE_PTR(pScene);
  193|     11|    };
  194|       |
  195|     11|    try {
  196|       |        // Allocate storage and copy the contents of the file to a memory buffer
  197|     11|        mBuffer = new unsigned char[iFileSize + 1];
  198|     11|        file->Read((void *)mBuffer, 1, iFileSize);
  199|       |
  200|       |        // Append a binary zero to the end of the buffer.
  201|       |        // this is just for safety that string parsing routines
  202|       |        // find the end of the buffer ...
  203|     11|        mBuffer[iFileSize] = '\0';
  204|     11|        const uint32_t iMagicWord = *((uint32_t *)mBuffer);
  205|       |
  206|       |        // Determine the file subtype and call the appropriate member function
  207|     11|        bool is_half_life = false;
  208|       |
  209|       |        // Original Quake1 format
  210|     11|        if (AI_MDL_MAGIC_NUMBER_BE == iMagicWord || AI_MDL_MAGIC_NUMBER_LE == iMagicWord) {
  ------------------
  |  |   72|     11|#define AI_MDL_MAGIC_NUMBER_BE  AI_MAKE_MAGIC("IDPO")
  ------------------
                      if (AI_MDL_MAGIC_NUMBER_BE == iMagicWord || AI_MDL_MAGIC_NUMBER_LE == iMagicWord) {
  ------------------
  |  |   73|     11|#define AI_MDL_MAGIC_NUMBER_LE  AI_MAKE_MAGIC("OPDI")
  ------------------
  |  Branch (210:13): [True: 0, False: 11]
  |  Branch (210:53): [True: 0, False: 11]
  ------------------
  211|      0|            ASSIMP_LOG_DEBUG("MDL subtype: Quake 1, magic word is IDPO");
  212|      0|            iGSFileVersion = 0;
  213|      0|            InternReadFile_Quake1();
  214|      0|        }
  215|       |        // GameStudio A<old> MDL2 format - used by some test models that come with 3DGS
  216|     11|        else if (AI_MDL_MAGIC_NUMBER_BE_GS3 == iMagicWord || AI_MDL_MAGIC_NUMBER_LE_GS3 == iMagicWord) {
  ------------------
  |  |   76|     11|#define AI_MDL_MAGIC_NUMBER_BE_GS3  AI_MAKE_MAGIC("MDL2")
  ------------------
                      else if (AI_MDL_MAGIC_NUMBER_BE_GS3 == iMagicWord || AI_MDL_MAGIC_NUMBER_LE_GS3 == iMagicWord) {
  ------------------
  |  |   77|     11|#define AI_MDL_MAGIC_NUMBER_LE_GS3  AI_MAKE_MAGIC("2LDM")
  ------------------
  |  Branch (216:18): [True: 0, False: 11]
  |  Branch (216:62): [True: 0, False: 11]
  ------------------
  217|      0|            ASSIMP_LOG_DEBUG("MDL subtype: 3D GameStudio A2, magic word is MDL2");
  218|      0|            iGSFileVersion = 2;
  219|      0|            InternReadFile_Quake1();
  220|      0|        }
  221|       |        // GameStudio A4 MDL3 format
  222|     11|        else if (AI_MDL_MAGIC_NUMBER_BE_GS4 == iMagicWord || AI_MDL_MAGIC_NUMBER_LE_GS4 == iMagicWord) {
  ------------------
  |  |   80|     11|#define AI_MDL_MAGIC_NUMBER_BE_GS4  AI_MAKE_MAGIC("MDL3")
  ------------------
                      else if (AI_MDL_MAGIC_NUMBER_BE_GS4 == iMagicWord || AI_MDL_MAGIC_NUMBER_LE_GS4 == iMagicWord) {
  ------------------
  |  |   81|     11|#define AI_MDL_MAGIC_NUMBER_LE_GS4  AI_MAKE_MAGIC("3LDM")
  ------------------
  |  Branch (222:18): [True: 0, False: 11]
  |  Branch (222:62): [True: 0, False: 11]
  ------------------
  223|      0|            ASSIMP_LOG_DEBUG("MDL subtype: 3D GameStudio A4, magic word is MDL3");
  224|      0|            iGSFileVersion = 3;
  225|      0|            InternReadFile_3DGS_MDL345();
  226|      0|        }
  227|       |        // GameStudio A5+ MDL4 format
  228|     11|        else if (AI_MDL_MAGIC_NUMBER_BE_GS5a == iMagicWord || AI_MDL_MAGIC_NUMBER_LE_GS5a == iMagicWord) {
  ------------------
  |  |   84|     11|#define AI_MDL_MAGIC_NUMBER_BE_GS5a AI_MAKE_MAGIC("MDL4")
  ------------------
                      else if (AI_MDL_MAGIC_NUMBER_BE_GS5a == iMagicWord || AI_MDL_MAGIC_NUMBER_LE_GS5a == iMagicWord) {
  ------------------
  |  |   85|     11|#define AI_MDL_MAGIC_NUMBER_LE_GS5a AI_MAKE_MAGIC("4LDM")
  ------------------
  |  Branch (228:18): [True: 0, False: 11]
  |  Branch (228:63): [True: 0, False: 11]
  ------------------
  229|      0|            ASSIMP_LOG_DEBUG("MDL subtype: 3D GameStudio A4, magic word is MDL4");
  230|      0|            iGSFileVersion = 4;
  231|      0|            InternReadFile_3DGS_MDL345();
  232|      0|        }
  233|       |        // GameStudio A5+ MDL5 format
  234|     11|        else if (AI_MDL_MAGIC_NUMBER_BE_GS5b == iMagicWord || AI_MDL_MAGIC_NUMBER_LE_GS5b == iMagicWord) {
  ------------------
  |  |   86|     11|#define AI_MDL_MAGIC_NUMBER_BE_GS5b AI_MAKE_MAGIC("MDL5")
  ------------------
                      else if (AI_MDL_MAGIC_NUMBER_BE_GS5b == iMagicWord || AI_MDL_MAGIC_NUMBER_LE_GS5b == iMagicWord) {
  ------------------
  |  |   87|     11|#define AI_MDL_MAGIC_NUMBER_LE_GS5b AI_MAKE_MAGIC("5LDM")
  ------------------
  |  Branch (234:18): [True: 0, False: 11]
  |  Branch (234:63): [True: 3, False: 8]
  ------------------
  235|      3|            ASSIMP_LOG_DEBUG("MDL subtype: 3D GameStudio A5, magic word is MDL5");
  236|      3|            iGSFileVersion = 5;
  237|      3|            InternReadFile_3DGS_MDL345();
  238|      3|        }
  239|       |        // GameStudio A7 MDL7 format
  240|      8|        else if (AI_MDL_MAGIC_NUMBER_BE_GS7 == iMagicWord || AI_MDL_MAGIC_NUMBER_LE_GS7 == iMagicWord) {
  ------------------
  |  |   90|      8|#define AI_MDL_MAGIC_NUMBER_BE_GS7  AI_MAKE_MAGIC("MDL7")
  ------------------
                      else if (AI_MDL_MAGIC_NUMBER_BE_GS7 == iMagicWord || AI_MDL_MAGIC_NUMBER_LE_GS7 == iMagicWord) {
  ------------------
  |  |   91|      8|#define AI_MDL_MAGIC_NUMBER_LE_GS7  AI_MAKE_MAGIC("7LDM")
  ------------------
  |  Branch (240:18): [True: 0, False: 8]
  |  Branch (240:62): [True: 4, False: 4]
  ------------------
  241|      4|            ASSIMP_LOG_DEBUG("MDL subtype: 3D GameStudio A7, magic word is MDL7");
  242|      4|            iGSFileVersion = 7;
  243|      4|            InternReadFile_3DGS_MDL7();
  244|      4|        }
  245|       |        // IDST/IDSQ Format (CS:S/HL^2, etc ...)
  246|      4|        else if (AI_MDL_MAGIC_NUMBER_BE_HL2a == iMagicWord || AI_MDL_MAGIC_NUMBER_LE_HL2a == iMagicWord ||
  ------------------
  |  |   59|      4|#define AI_MDL_MAGIC_NUMBER_BE_HL2a AI_MAKE_MAGIC("IDST")
  ------------------
                      else if (AI_MDL_MAGIC_NUMBER_BE_HL2a == iMagicWord || AI_MDL_MAGIC_NUMBER_LE_HL2a == iMagicWord ||
  ------------------
  |  |   60|      4|#define AI_MDL_MAGIC_NUMBER_LE_HL2a AI_MAKE_MAGIC("TSDI")
  ------------------
  |  Branch (246:18): [True: 0, False: 4]
  |  Branch (246:63): [True: 4, False: 0]
  ------------------
  247|      4|                 AI_MDL_MAGIC_NUMBER_BE_HL2b == iMagicWord || AI_MDL_MAGIC_NUMBER_LE_HL2b == iMagicWord) {
  ------------------
  |  |   61|      0|#define AI_MDL_MAGIC_NUMBER_BE_HL2b AI_MAKE_MAGIC("IDSQ")
  ------------------
                               AI_MDL_MAGIC_NUMBER_BE_HL2b == iMagicWord || AI_MDL_MAGIC_NUMBER_LE_HL2b == iMagicWord) {
  ------------------
  |  |   62|      0|#define AI_MDL_MAGIC_NUMBER_LE_HL2b AI_MAKE_MAGIC("QSDI")
  ------------------
  |  Branch (247:18): [True: 0, False: 0]
  |  Branch (247:63): [True: 0, False: 0]
  ------------------
  248|      4|            iGSFileVersion = 0;
  249|      4|            is_half_life = true;
  250|       |
  251|      4|            HalfLife::HalfLifeMDLBaseHeader *pHeader = (HalfLife::HalfLifeMDLBaseHeader *)mBuffer;
  252|      4|            if (pHeader->version == AI_MDL_HL1_VERSION) {
  ------------------
  |  |  540|      4|#define AI_MDL_HL1_VERSION 10
  ------------------
  |  Branch (252:17): [True: 4, False: 0]
  ------------------
  253|      4|                ASSIMP_LOG_DEBUG("MDL subtype: Half-Life 1/Goldsrc Engine, magic word is IDST/IDSQ");
  254|      4|                InternReadFile_HL1(pFile, iMagicWord);
  255|      4|            } else {
  256|      0|                ASSIMP_LOG_DEBUG("MDL subtype: Source(tm) Engine, magic word is IDST/IDSQ");
  257|      0|                InternReadFile_HL2();
  258|      0|            }
  259|      4|        } else {
  260|       |            // print the magic word to the log file
  261|      0|            throw DeadlyImportError("Unknown MDL subformat ", pFile,
  262|      0|                                    ". Magic word (", ai_str_toprintable((const char *)&iMagicWord, sizeof(iMagicWord)), ") is not known");
  263|      0|        }
  264|       |
  265|     11|        if (is_half_life && mHL1ImportSettings.transform_coord_system) {
  ------------------
  |  Branch (265:13): [True: 3, False: 8]
  |  Branch (265:29): [True: 0, False: 3]
  ------------------
  266|       |            // Now rotate the whole scene 90 degrees around the z and x axes to convert to internal coordinate system
  267|      0|            transformCoordinateSystem(pScene);
  268|     11|        } else {
  269|       |            // Now rotate the whole scene 90 degrees around the x axis to convert to internal coordinate system
  270|     11|            pScene->mRootNode->mTransformation = aiMatrix4x4(
  271|     11|                1.f,  0.f, 0.f, 0.f,
  272|     11|                0.f,  0.f, 1.f, 0.f,
  273|     11|                0.f, -1.f, 0.f, 0.f,
  274|     11|                0.f,  0.f, 0.f, 1.f);
  275|     11|        }
  276|       |
  277|     11|        DeleteBufferAndCleanup();
  278|     11|    } catch (...) {
  279|      4|        DeleteBufferAndCleanup();
  280|      4|        throw;
  281|      4|    }
  282|     11|}
_ZNK6Assimp11MDLImporter10IsPosValidEPKv:
  286|     76|bool MDLImporter::IsPosValid(const void *szPos) const {
  287|     76|    return szPos && (const unsigned char *)szPos <= this->mBuffer + this->iFileSize && szPos >= this->mBuffer;
  ------------------
  |  Branch (287:12): [True: 76, False: 0]
  |  Branch (287:21): [True: 76, False: 0]
  |  Branch (287:88): [True: 76, False: 0]
  ------------------
  288|     76|}
_ZN6Assimp11MDLImporter9SizeCheckEPKvPKcj:
  301|     76|void MDLImporter::SizeCheck(const void *szPos, const char *szFile, unsigned int iLine) {
  302|     76|    ai_assert(nullptr != szFile);
  303|     76|    if (!IsPosValid(szPos)) {
  ------------------
  |  Branch (303:9): [True: 0, False: 76]
  ------------------
  304|       |        // remove a directory if there is one
  305|      0|        const char *szFilePtr = ::strrchr(szFile, '\\');
  306|      0|        if (!szFilePtr) {
  ------------------
  |  Branch (306:13): [True: 0, False: 0]
  ------------------
  307|      0|            szFilePtr = ::strrchr(szFile, '/');
  308|      0|            if (nullptr == szFilePtr) {
  ------------------
  |  Branch (308:17): [True: 0, False: 0]
  ------------------
  309|      0|                szFilePtr = szFile;
  310|      0|            }
  311|      0|        }
  312|      0|        if (szFilePtr) {
  ------------------
  |  Branch (312:13): [True: 0, False: 0]
  ------------------
  313|      0|            ++szFilePtr;
  314|      0|        }
  315|       |
  316|      0|        char szBuffer[1024];
  317|      0|        ::snprintf(szBuffer, sizeof(szBuffer), "Invalid MDL file. The file is too small "
  318|      0|                            "or contains invalid data (File: %s Line: %u)",
  319|      0|                szFilePtr, iLine);
  320|       |
  321|      0|        throw DeadlyImportError(szBuffer);
  322|      0|    }
  323|     76|}
_ZN6Assimp11MDLImporter21ValidateHeader_Quake1EPKNS_3MDL6HeaderE:
  327|      3|void MDLImporter::ValidateHeader_Quake1(const MDL::Header *pcHeader) {
  328|       |    // some values may not be nullptr
  329|      3|    if (pcHeader->num_frames <= 0)
  ------------------
  |  Branch (329:9): [True: 0, False: 3]
  ------------------
  330|      0|        throw DeadlyImportError("[Quake 1 MDL] There are no frames in the file");
  331|       |
  332|      3|    if (pcHeader->num_verts <= 0)
  ------------------
  |  Branch (332:9): [True: 0, False: 3]
  ------------------
  333|      0|        throw DeadlyImportError("[Quake 1 MDL] There are no vertices in the file");
  334|       |
  335|      3|    if (pcHeader->num_tris <= 0)
  ------------------
  |  Branch (335:9): [True: 0, False: 3]
  ------------------
  336|      0|        throw DeadlyImportError("[Quake 1 MDL] There are no triangles in the file");
  337|       |
  338|       |    // check whether the maxima are exceeded ...however, this applies for Quake 1 MDLs only
  339|      3|    if (!this->iGSFileVersion) {
  ------------------
  |  Branch (339:9): [True: 0, False: 3]
  ------------------
  340|      0|        if (pcHeader->num_verts > AI_MDL_MAX_VERTS)
  ------------------
  |  |  105|      0|#   define AI_MDL_MAX_VERTS             1024
  ------------------
  |  Branch (340:13): [True: 0, False: 0]
  ------------------
  341|      0|            ASSIMP_LOG_WARN("Quake 1 MDL model has more than AI_MDL_MAX_VERTS vertices");
  342|       |
  343|      0|        if (pcHeader->num_tris > AI_MDL_MAX_TRIANGLES)
  ------------------
  |  |  108|      0|#   define AI_MDL_MAX_TRIANGLES         2048
  ------------------
  |  Branch (343:13): [True: 0, False: 0]
  ------------------
  344|      0|            ASSIMP_LOG_WARN("Quake 1 MDL model has more than AI_MDL_MAX_TRIANGLES triangles");
  345|       |
  346|      0|        if (pcHeader->num_frames > AI_MDL_MAX_FRAMES)
  ------------------
  |  |   99|      0|#   define AI_MDL_MAX_FRAMES            256
  ------------------
  |  Branch (346:13): [True: 0, False: 0]
  ------------------
  347|      0|            ASSIMP_LOG_WARN("Quake 1 MDL model has more than AI_MDL_MAX_FRAMES frames");
  348|       |
  349|       |        // (this does not apply for 3DGS MDLs)
  350|      0|        if (!this->iGSFileVersion && pcHeader->version != AI_MDL_VERSION)
  ------------------
  |  |   96|      0|#   define AI_MDL_VERSION               6
  ------------------
  |  Branch (350:13): [True: 0, False: 0]
  |  Branch (350:38): [True: 0, False: 0]
  ------------------
  351|      0|            ASSIMP_LOG_WARN("Quake 1 MDL model has an unknown version: AI_MDL_VERSION (=6) is "
  352|      0|                            "the expected file format version");
  353|      0|        if (pcHeader->num_skins && (!pcHeader->skinwidth || !pcHeader->skinheight))
  ------------------
  |  Branch (353:13): [True: 0, False: 0]
  |  Branch (353:37): [True: 0, False: 0]
  |  Branch (353:61): [True: 0, False: 0]
  ------------------
  354|       |            ASSIMP_LOG_WARN("Skin width or height are 0");
  355|      0|    }
  356|      3|}
_ZN6Assimp11MDLImporter40SetupMaterialProperties_3DGS_MDL5_Quake1Ev:
  561|      3|void MDLImporter::SetupMaterialProperties_3DGS_MDL5_Quake1() {
  562|      3|    const MDL::Header *const pcHeader = (const MDL::Header *)this->mBuffer;
  563|       |
  564|       |    // allocate ONE material
  565|      3|    pScene->mMaterials = new aiMaterial *[1];
  566|      3|    pScene->mMaterials[0] = new aiMaterial();
  567|      3|    pScene->mNumMaterials = 1;
  568|       |
  569|       |    // setup the material's properties
  570|      3|    const int iMode = (int)aiShadingMode_Gouraud;
  571|      3|    aiMaterial *const pcHelper = (aiMaterial *)pScene->mMaterials[0];
  572|      3|    pcHelper->AddProperty<int>(&iMode, 1, AI_MATKEY_SHADING_MODEL);
  573|       |
  574|      3|    aiColor4D clr;
  575|      3|    if (0 != pcHeader->num_skins && pScene->mNumTextures) {
  ------------------
  |  Branch (575:9): [True: 0, False: 3]
  |  Branch (575:37): [True: 0, False: 0]
  ------------------
  576|       |        // can we replace the texture with a single color?
  577|      0|        clr = this->ReplaceTextureWithColor(pScene->mTextures[0]);
  578|      0|        if (is_not_qnan(clr.r)) {
  ------------------
  |  Branch (578:13): [True: 0, False: 0]
  ------------------
  579|      0|            delete pScene->mTextures[0];
  580|      0|            delete[] pScene->mTextures;
  581|       |
  582|      0|            pScene->mTextures = nullptr;
  583|      0|            pScene->mNumTextures = 0;
  584|      0|        } else {
  585|      0|            clr.b = clr.a = clr.g = clr.r = 1.0f;
  586|      0|            aiString szString;
  587|      0|            ::memcpy(szString.data, AI_MAKE_EMBEDDED_TEXNAME(0), 3);
  588|      0|            szString.length = 2;
  589|      0|            pcHelper->AddProperty(&szString, AI_MATKEY_TEXTURE_DIFFUSE(0));
  590|      0|        }
  591|      0|    }
  592|       |
  593|      3|    pcHelper->AddProperty<aiColor4D>(&clr, 1, AI_MATKEY_COLOR_DIFFUSE);
  594|      3|    pcHelper->AddProperty<aiColor4D>(&clr, 1, AI_MATKEY_COLOR_SPECULAR);
  595|       |
  596|      3|    clr.r *= 0.05f;
  597|      3|    clr.g *= 0.05f;
  598|      3|    clr.b *= 0.05f;
  599|      3|    clr.a = 1.0f;
  600|       |    pcHelper->AddProperty<aiColor4D>(&clr, 1, AI_MATKEY_COLOR_AMBIENT);
  601|      3|}
_ZN6Assimp11MDLImporter26InternReadFile_3DGS_MDL345Ev:
  605|      3|void MDLImporter::InternReadFile_3DGS_MDL345() {
  606|      3|    ai_assert(nullptr != pScene);
  607|      3|    if (pScene == nullptr) {
  ------------------
  |  Branch (607:9): [True: 0, False: 3]
  ------------------
  608|      0|        throw DeadlyImportError("INvalid scene pointer detected.");
  609|      0|    }
  610|       |
  611|       |    // the header of MDL 3/4/5 is nearly identical to the original Quake1 header
  612|      3|    BE_NCONST MDL::Header *pcHeader = (BE_NCONST MDL::Header *)this->mBuffer;
  613|       |#ifdef AI_BUILD_BIG_ENDIAN
  614|       |    FlipQuakeHeader(pcHeader);
  615|       |#endif
  616|      3|    ValidateHeader_Quake1(pcHeader);
  617|       |
  618|      3|    if (pcHeader->synctype < 0) {
  ------------------
  |  Branch (618:9): [True: 0, False: 3]
  ------------------
  619|      0|        throw DeadlyImportError("Invalid synctype value in MDL header; possible corrupt file.");
  620|      0|    }
  621|       |
  622|       |    // current cursor position in the file
  623|      3|    const unsigned char *szCurrent = (const unsigned char *)(pcHeader + 1);
  624|      3|    const unsigned char *szEnd = mBuffer + iFileSize;
  625|       |
  626|       |    // need to read all textures
  627|      3|    for (unsigned int i = 0; i < (unsigned int)pcHeader->num_skins; ++i) {
  ------------------
  |  Branch (627:30): [True: 0, False: 3]
  ------------------
  628|      0|        if (szCurrent + sizeof(uint32_t) > szEnd) {
  ------------------
  |  Branch (628:13): [True: 0, False: 0]
  ------------------
  629|      0|            throw DeadlyImportError("Texture data past end of file.");
  630|      0|        }
  631|      0|        BE_NCONST MDL::Skin *pcSkin = (BE_NCONST MDL::Skin *)szCurrent;
  632|      0|        AI_SWAP4(pcSkin->group);
  633|       |        // create one output image
  634|      0|        unsigned int iSkip = i ? UINT_MAX : 0;
  ------------------
  |  Branch (634:30): [True: 0, False: 0]
  ------------------
  635|      0|        if (5 <= iGSFileVersion) {
  ------------------
  |  Branch (635:13): [True: 0, False: 0]
  ------------------
  636|       |            // MDL5 format could contain MIPmaps
  637|      0|            CreateTexture_3DGS_MDL5((unsigned char *)pcSkin + sizeof(uint32_t),
  638|      0|                    pcSkin->group, &iSkip);
  639|      0|        } else {
  640|      0|            CreateTexture_3DGS_MDL4((unsigned char *)pcSkin + sizeof(uint32_t),
  641|      0|                    pcSkin->group, &iSkip);
  642|      0|        }
  643|       |        // need to skip one image
  644|      0|        szCurrent += iSkip + sizeof(uint32_t);
  645|      0|    }
  646|       |    // get a pointer to the texture coordinates
  647|      3|    BE_NCONST MDL::TexCoord_MDL3 *pcTexCoords = (BE_NCONST MDL::TexCoord_MDL3 *)szCurrent;
  648|      3|    szCurrent += sizeof(MDL::TexCoord_MDL3) * pcHeader->synctype;
  649|       |
  650|       |    // NOTE: for MDLn formats "synctype" corresponds to the number of UV coords
  651|       |
  652|       |    // get a pointer to the triangles
  653|      3|    BE_NCONST MDL::Triangle_MDL3 *pcTriangles = (BE_NCONST MDL::Triangle_MDL3 *)szCurrent;
  654|      3|    szCurrent += sizeof(MDL::Triangle_MDL3) * pcHeader->num_tris;
  655|       |
  656|       |#ifdef AI_BUILD_BIG_ENDIAN
  657|       |
  658|       |    for (int i = 0; i < pcHeader->synctype; ++i) {
  659|       |        AI_SWAP2(pcTexCoords[i].u);
  660|       |        AI_SWAP2(pcTexCoords[i].v);
  661|       |    }
  662|       |
  663|       |    for (int i = 0; i < pcHeader->num_tris; ++i) {
  664|       |        AI_SWAP2(pcTriangles[i].index_xyz[0]);
  665|       |        AI_SWAP2(pcTriangles[i].index_xyz[1]);
  666|       |        AI_SWAP2(pcTriangles[i].index_xyz[2]);
  667|       |        AI_SWAP2(pcTriangles[i].index_uv[0]);
  668|       |        AI_SWAP2(pcTriangles[i].index_uv[1]);
  669|       |        AI_SWAP2(pcTriangles[i].index_uv[2]);
  670|       |    }
  671|       |
  672|       |#endif
  673|       |
  674|      3|    VALIDATE_FILE_SIZE(szCurrent);
  ------------------
  |  |   63|      3|#   define VALIDATE_FILE_SIZE(msg) SizeCheck(msg,__FILE__,__LINE__)
  ------------------
  675|       |
  676|       |    // setup materials
  677|      3|    SetupMaterialProperties_3DGS_MDL5_Quake1();
  678|       |
  679|       |    // allocate enough storage to hold all vertices and triangles
  680|      3|    aiMesh *pcMesh = new aiMesh();
  681|      3|    pcMesh->mPrimitiveTypes = aiPrimitiveType_TRIANGLE;
  682|       |
  683|      3|    pcMesh->mNumVertices = pcHeader->num_tris * 3;
  684|      3|    pcMesh->mNumFaces = pcHeader->num_tris;
  685|      3|    pcMesh->mFaces = new aiFace[pcMesh->mNumFaces];
  686|       |
  687|       |    // there won't be more than one mesh inside the file
  688|      3|    pScene->mRootNode = new aiNode();
  689|      3|    pScene->mRootNode->mNumMeshes = 1;
  690|      3|    pScene->mRootNode->mMeshes = new unsigned int[1];
  691|      3|    pScene->mRootNode->mMeshes[0] = 0;
  692|      3|    pScene->mNumMeshes = 1;
  693|      3|    pScene->mMeshes = new aiMesh *[1];
  694|      3|    pScene->mMeshes[0] = pcMesh;
  695|       |
  696|       |    // allocate output storage
  697|      3|    pcMesh->mNumVertices = (unsigned int)pcHeader->num_tris * 3;
  698|      3|    pcMesh->mVertices = new aiVector3D[pcMesh->mNumVertices];
  699|      3|    pcMesh->mNormals = new aiVector3D[pcMesh->mNumVertices];
  700|       |
  701|      3|    if (pcHeader->synctype) {
  ------------------
  |  Branch (701:9): [True: 3, False: 0]
  ------------------
  702|      3|        pcMesh->mTextureCoords[0] = new aiVector3D[pcMesh->mNumVertices];
  703|      3|        pcMesh->mNumUVComponents[0] = 2;
  704|      3|    }
  705|       |
  706|       |    // now get a pointer to the first frame in the file
  707|      3|    BE_NCONST MDL::Frame *pcFrames = (BE_NCONST MDL::Frame *)szCurrent;
  708|      3|    VALIDATE_FILE_SIZE((const unsigned char *)(pcFrames + 1));
  ------------------
  |  |   63|      3|#   define VALIDATE_FILE_SIZE(msg) SizeCheck(msg,__FILE__,__LINE__)
  ------------------
  709|      3|    AI_SWAP4(pcFrames->type);
  710|       |
  711|       |    // byte packed vertices
  712|       |    // FIXME: these two snippets below are almost identical ... join them?
  713|       |    /////////////////////////////////////////////////////////////////////////////////////
  714|      3|    if (0 == pcFrames->type || 3 >= this->iGSFileVersion) {
  ------------------
  |  Branch (714:9): [True: 0, False: 3]
  |  Branch (714:32): [True: 0, False: 3]
  ------------------
  715|       |
  716|      0|        const MDL::SimpleFrame *pcFirstFrame = (const MDL::SimpleFrame *)(szCurrent + sizeof(uint32_t));
  717|      0|        const MDL::Vertex *pcVertices = (const MDL::Vertex *)((pcFirstFrame->name) + sizeof(pcFirstFrame->name));
  718|       |
  719|      0|        VALIDATE_FILE_SIZE(pcVertices + pcHeader->num_verts);
  ------------------
  |  |   63|      0|#   define VALIDATE_FILE_SIZE(msg) SizeCheck(msg,__FILE__,__LINE__)
  ------------------
  720|       |
  721|       |        // now iterate through all triangles
  722|      0|        unsigned int iCurrent = 0;
  723|      0|        for (unsigned int i = 0; i < (unsigned int)pcHeader->num_tris; ++i) {
  ------------------
  |  Branch (723:34): [True: 0, False: 0]
  ------------------
  724|      0|            pcMesh->mFaces[i].mIndices = new unsigned int[3];
  725|      0|            pcMesh->mFaces[i].mNumIndices = 3;
  726|       |
  727|      0|            unsigned int iTemp = iCurrent;
  728|      0|            for (unsigned int c = 0; c < 3; ++c, ++iCurrent) {
  ------------------
  |  Branch (728:38): [True: 0, False: 0]
  ------------------
  729|       |                // read vertices
  730|      0|                unsigned int iIndex = pcTriangles->index_xyz[c];
  731|      0|                if (iIndex >= (unsigned int)pcHeader->num_verts) {
  ------------------
  |  Branch (731:21): [True: 0, False: 0]
  ------------------
  732|      0|                    iIndex = pcHeader->num_verts - 1;
  733|      0|                    ASSIMP_LOG_WARN("Index overflow in MDLn vertex list");
  734|      0|                }
  735|       |
  736|      0|                aiVector3D &vec = pcMesh->mVertices[iCurrent];
  737|      0|                vec.x = (float)pcVertices[iIndex].v[0] * pcHeader->scale[0];
  738|      0|                vec.x += pcHeader->translate[0];
  739|       |
  740|      0|                vec.y = (float)pcVertices[iIndex].v[1] * pcHeader->scale[1];
  741|      0|                vec.y += pcHeader->translate[1];
  742|       |                // vec.y *= -1.0f;
  743|       |
  744|      0|                vec.z = (float)pcVertices[iIndex].v[2] * pcHeader->scale[2];
  745|      0|                vec.z += pcHeader->translate[2];
  746|       |
  747|       |                // read the normal vector from the precalculated normal table
  748|      0|                MD2::LookupNormalIndex(pcVertices[iIndex].normalIndex, pcMesh->mNormals[iCurrent]);
  749|       |                // pcMesh->mNormals[iCurrent].y *= -1.0f;
  750|       |
  751|       |                // read texture coordinates
  752|      0|                if (pcHeader->synctype) {
  ------------------
  |  Branch (752:21): [True: 0, False: 0]
  ------------------
  753|      0|                    ImportUVCoordinate_3DGS_MDL345(pcMesh->mTextureCoords[0][iCurrent],
  754|      0|                            pcTexCoords, pcTriangles->index_uv[c]);
  755|      0|                }
  756|      0|            }
  757|      0|            pcMesh->mFaces[i].mIndices[0] = iTemp + 2;
  758|      0|            pcMesh->mFaces[i].mIndices[1] = iTemp + 1;
  759|      0|            pcMesh->mFaces[i].mIndices[2] = iTemp + 0;
  760|      0|            pcTriangles++;
  761|      0|        }
  762|       |
  763|      0|    }
  764|       |    // short packed vertices
  765|       |    /////////////////////////////////////////////////////////////////////////////////////
  766|      3|    else {
  767|       |        // now get a pointer to the first frame in the file
  768|      3|        const MDL::SimpleFrame_MDLn_SP *pcFirstFrame = (const MDL::SimpleFrame_MDLn_SP *)(szCurrent + sizeof(uint32_t));
  769|       |
  770|       |        // get a pointer to the vertices
  771|      3|        const MDL::Vertex_MDL4 *pcVertices = (const MDL::Vertex_MDL4 *)((pcFirstFrame->name) +
  772|      3|                                                                        sizeof(pcFirstFrame->name));
  773|       |
  774|      3|        VALIDATE_FILE_SIZE(pcVertices + pcHeader->num_verts);
  ------------------
  |  |   63|      3|#   define VALIDATE_FILE_SIZE(msg) SizeCheck(msg,__FILE__,__LINE__)
  ------------------
  775|       |
  776|       |        // now iterate through all triangles
  777|      3|        unsigned int iCurrent = 0;
  778|  2.88k|        for (unsigned int i = 0; i < (unsigned int)pcHeader->num_tris; ++i) {
  ------------------
  |  Branch (778:34): [True: 2.88k, False: 3]
  ------------------
  779|  2.88k|            pcMesh->mFaces[i].mIndices = new unsigned int[3];
  780|  2.88k|            pcMesh->mFaces[i].mNumIndices = 3;
  781|       |
  782|  2.88k|            unsigned int iTemp = iCurrent;
  783|  11.5k|            for (unsigned int c = 0; c < 3; ++c, ++iCurrent) {
  ------------------
  |  Branch (783:38): [True: 8.64k, False: 2.88k]
  ------------------
  784|       |                // read vertices
  785|  8.64k|                unsigned int iIndex = pcTriangles->index_xyz[c];
  786|  8.64k|                if (iIndex >= (unsigned int)pcHeader->num_verts) {
  ------------------
  |  Branch (786:21): [True: 3, False: 8.63k]
  ------------------
  787|      3|                    iIndex = pcHeader->num_verts - 1;
  788|      3|                    ASSIMP_LOG_WARN("Index overflow in MDLn vertex list");
  789|      3|                }
  790|       |
  791|  8.64k|                aiVector3D &vec = pcMesh->mVertices[iCurrent];
  792|  8.64k|                vec.x = (float)pcVertices[iIndex].v[0] * pcHeader->scale[0];
  793|  8.64k|                vec.x += pcHeader->translate[0];
  794|       |
  795|  8.64k|                vec.y = (float)pcVertices[iIndex].v[1] * pcHeader->scale[1];
  796|  8.64k|                vec.y += pcHeader->translate[1];
  797|       |                // vec.y *= -1.0f;
  798|       |
  799|  8.64k|                vec.z = (float)pcVertices[iIndex].v[2] * pcHeader->scale[2];
  800|  8.64k|                vec.z += pcHeader->translate[2];
  801|       |
  802|       |                // read the normal vector from the precalculated normal table
  803|  8.64k|                MD2::LookupNormalIndex(pcVertices[iIndex].normalIndex, pcMesh->mNormals[iCurrent]);
  804|       |                // pcMesh->mNormals[iCurrent].y *= -1.0f;
  805|       |
  806|       |                // read texture coordinates
  807|  8.64k|                if (pcHeader->synctype) {
  ------------------
  |  Branch (807:21): [True: 8.64k, False: 0]
  ------------------
  808|  8.64k|                    ImportUVCoordinate_3DGS_MDL345(pcMesh->mTextureCoords[0][iCurrent],
  809|  8.64k|                            pcTexCoords, pcTriangles->index_uv[c]);
  810|  8.64k|                }
  811|  8.64k|            }
  812|  2.88k|            pcMesh->mFaces[i].mIndices[0] = iTemp + 2;
  813|  2.88k|            pcMesh->mFaces[i].mIndices[1] = iTemp + 1;
  814|  2.88k|            pcMesh->mFaces[i].mIndices[2] = iTemp + 0;
  815|  2.88k|            pcTriangles++;
  816|  2.88k|        }
  817|      3|    }
  818|       |
  819|       |    // For MDL5 we will need to build valid texture coordinates
  820|       |    // basing upon the file loaded (only support one file as skin)
  821|      3|    if (0x5 == iGSFileVersion)
  ------------------
  |  Branch (821:9): [True: 3, False: 0]
  ------------------
  822|      3|        CalculateUVCoordinates_MDL5();
  823|      3|    return;
  824|      3|}
_ZN6Assimp11MDLImporter30ImportUVCoordinate_3DGS_MDL345ER10aiVector3tIfEPKNS_3MDL13TexCoord_MDL3Ej:
  831|  8.64k|        unsigned int iIndex) {
  832|  8.64k|    ai_assert(nullptr != pcSrc);
  833|  8.64k|    const MDL::Header *const pcHeader = (const MDL::Header *)this->mBuffer;
  834|       |
  835|       |    // validate UV indices
  836|  8.64k|    if (iIndex >= (unsigned int)pcHeader->synctype) {
  ------------------
  |  Branch (836:9): [True: 718, False: 7.92k]
  ------------------
  837|    718|        iIndex = pcHeader->synctype - 1;
  838|    718|        ASSIMP_LOG_WARN("Index overflow in MDLn UV coord list");
  839|    718|    }
  840|       |
  841|  8.64k|    float s = (float)pcSrc[iIndex].u;
  842|  8.64k|    float t = (float)pcSrc[iIndex].v;
  843|       |
  844|       |    // Scale s and t to range from 0.0 to 1.0
  845|  8.64k|    if (0x5 != iGSFileVersion) {
  ------------------
  |  Branch (845:9): [True: 0, False: 8.64k]
  ------------------
  846|      0|        s = (s + 0.5f) / pcHeader->skinwidth;
  847|      0|        t = 1.0f - (t + 0.5f) / pcHeader->skinheight;
  848|      0|    }
  849|       |
  850|  8.64k|    vOut.x = s;
  851|  8.64k|    vOut.y = t;
  852|  8.64k|    vOut.z = 0.0f;
  853|  8.64k|}
_ZN6Assimp11MDLImporter27CalculateUVCoordinates_MDL5Ev:
  857|      3|void MDLImporter::CalculateUVCoordinates_MDL5() {
  858|      3|    const MDL::Header *const pcHeader = (const MDL::Header *)this->mBuffer;
  859|      3|    if (pcHeader->num_skins && this->pScene->mNumTextures) {
  ------------------
  |  Branch (859:9): [True: 0, False: 3]
  |  Branch (859:32): [True: 0, False: 0]
  ------------------
  860|      0|        const aiTexture *pcTex = this->pScene->mTextures[0];
  861|       |
  862|       |        // if the file is loaded in DDS format: get the size of the
  863|       |        // texture from the header of the DDS file
  864|       |        // skip three DWORDs and read first height, then the width
  865|      0|        unsigned int iWidth, iHeight;
  866|      0|        if (!pcTex->mHeight) {
  ------------------
  |  Branch (866:13): [True: 0, False: 0]
  ------------------
  867|      0|            const uint32_t *piPtr = (uint32_t *)pcTex->pcData;
  868|       |
  869|      0|            piPtr += 3;
  870|      0|            iHeight = (unsigned int)*piPtr++;
  871|      0|            iWidth = (unsigned int)*piPtr;
  872|      0|            if (!iHeight || !iWidth) {
  ------------------
  |  Branch (872:17): [True: 0, False: 0]
  |  Branch (872:29): [True: 0, False: 0]
  ------------------
  873|      0|                ASSIMP_LOG_WARN("Either the width or the height of the "
  874|      0|                                "embedded DDS texture is zero. Unable to compute final texture "
  875|      0|                                "coordinates. The texture coordinates remain in their original "
  876|      0|                                "0-x/0-y (x,y = texture size) range.");
  877|      0|                iWidth = 1;
  878|      0|                iHeight = 1;
  879|      0|            }
  880|      0|        } else {
  881|      0|            iWidth = pcTex->mWidth;
  882|      0|            iHeight = pcTex->mHeight;
  883|      0|        }
  884|       |
  885|      0|        if (1 != iWidth || 1 != iHeight) {
  ------------------
  |  Branch (885:13): [True: 0, False: 0]
  |  Branch (885:28): [True: 0, False: 0]
  ------------------
  886|      0|            const float fWidth = (float)iWidth;
  887|      0|            const float fHeight = (float)iHeight;
  888|      0|            aiMesh *pcMesh = this->pScene->mMeshes[0];
  889|      0|            for (unsigned int i = 0; i < pcMesh->mNumVertices; ++i) {
  ------------------
  |  Branch (889:38): [True: 0, False: 0]
  ------------------
  890|      0|                if (!pcMesh->HasTextureCoords(0)) {
  ------------------
  |  Branch (890:21): [True: 0, False: 0]
  ------------------
  891|      0|                    continue;
  892|      0|                }
  893|      0|                pcMesh->mTextureCoords[0][i].x /= fWidth;
  894|      0|                pcMesh->mTextureCoords[0][i].y /= fHeight;
  895|      0|                pcMesh->mTextureCoords[0][i].y = 1.0f - pcMesh->mTextureCoords[0][i].y; // DX to OGL
  896|      0|            }
  897|      0|        }
  898|      0|    }
  899|      3|}
_ZN6Assimp11MDLImporter24ValidateHeader_3DGS_MDL7EPKNS_3MDL11Header_MDL7E:
  903|      4|void MDLImporter::ValidateHeader_3DGS_MDL7(const MDL::Header_MDL7 *pcHeader) {
  904|      4|    ai_assert(nullptr != pcHeader);
  905|       |
  906|       |    // There are some fixed sizes ...
  907|      4|    if (sizeof(MDL::ColorValue_MDL7) != pcHeader->colorvalue_stc_size) {
  ------------------
  |  Branch (907:9): [True: 0, False: 4]
  ------------------
  908|      0|        throw DeadlyImportError(
  909|      0|                "[3DGS MDL7] sizeof(MDL::ColorValue_MDL7) != pcHeader->colorvalue_stc_size");
  910|      0|    }
  911|      4|    if (sizeof(MDL::TexCoord_MDL7) != pcHeader->skinpoint_stc_size) {
  ------------------
  |  Branch (911:9): [True: 0, False: 4]
  ------------------
  912|      0|        throw DeadlyImportError(
  913|      0|                "[3DGS MDL7] sizeof(MDL::TexCoord_MDL7) != pcHeader->skinpoint_stc_size");
  914|      0|    }
  915|      4|    if (sizeof(MDL::Skin_MDL7) != pcHeader->skin_stc_size) {
  ------------------
  |  Branch (915:9): [True: 0, False: 4]
  ------------------
  916|      0|        throw DeadlyImportError(
  917|      0|                "sizeof(MDL::Skin_MDL7) != pcHeader->skin_stc_size");
  918|      0|    }
  919|       |
  920|       |    // if there are no groups ... how should we load such a file?
  921|      4|    if (!pcHeader->groups_num) {
  ------------------
  |  Branch (921:9): [True: 0, False: 4]
  ------------------
  922|      0|        throw DeadlyImportError("[3DGS MDL7] No frames found");
  923|      0|    }
  924|      4|}
_ZN6Assimp11MDLImporter19LoadBones_3DGS_MDL7Ev:
 1015|      4|MDL::IntBone_MDL7 **MDLImporter::LoadBones_3DGS_MDL7() {
 1016|      4|    const MDL::Header_MDL7 *pcHeader = (const MDL::Header_MDL7 *)this->mBuffer;
 1017|      4|    if (pcHeader->bones_num) {
  ------------------
  |  Branch (1017:9): [True: 0, False: 4]
  ------------------
 1018|       |        // validate the size of the bone data structure in the file
 1019|      0|        if (AI_MDL7_BONE_STRUCT_SIZE__NAME_IS_20_CHARS != pcHeader->bone_stc_size &&
  ------------------
  |  |  248|      0|#   define AI_MDL7_BONE_STRUCT_SIZE__NAME_IS_20_CHARS (16 + 20)
  ------------------
  |  Branch (1019:13): [True: 0, False: 0]
  ------------------
 1020|      0|                AI_MDL7_BONE_STRUCT_SIZE__NAME_IS_32_CHARS != pcHeader->bone_stc_size &&
  ------------------
  |  |  252|      0|#   define AI_MDL7_BONE_STRUCT_SIZE__NAME_IS_32_CHARS (16 + 32)
  ------------------
  |  Branch (1020:17): [True: 0, False: 0]
  ------------------
 1021|      0|                AI_MDL7_BONE_STRUCT_SIZE__NAME_IS_NOT_THERE != pcHeader->bone_stc_size) {
  ------------------
  |  |  256|      0|#   define AI_MDL7_BONE_STRUCT_SIZE__NAME_IS_NOT_THERE (16)
  ------------------
  |  Branch (1021:17): [True: 0, False: 0]
  ------------------
 1022|      0|            ASSIMP_LOG_WARN("Unknown size of bone data structure");
 1023|      0|            return nullptr;
 1024|      0|        }
 1025|       |
 1026|      0|        MDL::IntBone_MDL7 **apcBonesOut = new MDL::IntBone_MDL7 *[pcHeader->bones_num];
 1027|      0|        for (uint32_t crank = 0; crank < pcHeader->bones_num; ++crank)
  ------------------
  |  Branch (1027:34): [True: 0, False: 0]
  ------------------
 1028|      0|            apcBonesOut[crank] = new MDL::IntBone_MDL7();
 1029|       |
 1030|       |        // and calculate absolute bone offset matrices ...
 1031|      0|        CalcAbsBoneMatrices_3DGS_MDL7(apcBonesOut);
 1032|      0|        return apcBonesOut;
 1033|      0|    }
 1034|      4|    return nullptr;
 1035|      4|}
_ZN6Assimp11MDLImporter19ReadFaces_3DGS_MDL7ERKNS_3MDL17IntGroupInfo_MDL7ERNS1_17IntGroupData_MDL7E:
 1040|     20|        MDL::IntGroupData_MDL7 &groupData) {
 1041|     20|    const MDL::Header_MDL7 *pcHeader = (const MDL::Header_MDL7 *)this->mBuffer;
 1042|     20|    MDL::Triangle_MDL7 *pcGroupTris = groupInfo.pcGroupTris;
 1043|       |
 1044|       |    // iterate through all triangles and build valid display lists
 1045|     20|    unsigned int iOutIndex = 0;
 1046|  2.42k|    for (unsigned int iTriangle = 0; iTriangle < (unsigned int)groupInfo.pcGroup->numtris; ++iTriangle) {
  ------------------
  |  Branch (1046:38): [True: 2.40k, False: 20]
  ------------------
 1047|  2.40k|        AI_SWAP2(pcGroupTris->v_index[0]);
 1048|  2.40k|        AI_SWAP2(pcGroupTris->v_index[1]);
 1049|  2.40k|        AI_SWAP2(pcGroupTris->v_index[2]);
 1050|       |
 1051|       |        // iterate through all indices of the current triangle
 1052|  9.60k|        for (unsigned int c = 0; c < 3; ++c, ++iOutIndex) {
  ------------------
  |  Branch (1052:34): [True: 7.20k, False: 2.40k]
  ------------------
 1053|       |
 1054|       |            // validate the vertex index
 1055|  7.20k|            unsigned int iIndex = pcGroupTris->v_index[c];
 1056|  7.20k|            if (iIndex > (unsigned int)groupInfo.pcGroup->numverts) {
  ------------------
  |  Branch (1056:17): [True: 0, False: 7.20k]
  ------------------
 1057|       |                // (we might need to read this section a second time - to process frame vertices correctly)
 1058|      0|                pcGroupTris->v_index[c] = (uint16_t)(iIndex = groupInfo.pcGroup->numverts - 1);
 1059|      0|                ASSIMP_LOG_WARN("Index overflow in MDL7 vertex list");
 1060|      0|            }
 1061|       |
 1062|       |            // write the output face index
 1063|  7.20k|            groupData.pcFaces[iTriangle].mIndices[2 - c] = iOutIndex;
 1064|       |
 1065|  7.20k|            aiVector3D &vPosition = groupData.vPositions[iOutIndex];
 1066|  7.20k|            vPosition.x = _AI_MDL7_ACCESS_VERT(groupInfo.pcGroupVerts, iIndex, pcHeader->mainvertex_stc_size).x;
  ------------------
  |  |   91|  7.20k|    _AI_MDL7_ACCESS(_data, _index, _limit, MDL::Vertex_MDL7)
  |  |  ------------------
  |  |  |  |   85|  7.20k|    (*((const _type *)(((const char *)_data) + _index * _limit)))
  |  |  ------------------
  ------------------
 1067|  7.20k|            vPosition.y = _AI_MDL7_ACCESS_VERT(groupInfo.pcGroupVerts, iIndex, pcHeader->mainvertex_stc_size).y;
  ------------------
  |  |   91|  7.20k|    _AI_MDL7_ACCESS(_data, _index, _limit, MDL::Vertex_MDL7)
  |  |  ------------------
  |  |  |  |   85|  7.20k|    (*((const _type *)(((const char *)_data) + _index * _limit)))
  |  |  ------------------
  ------------------
 1068|  7.20k|            vPosition.z = _AI_MDL7_ACCESS_VERT(groupInfo.pcGroupVerts, iIndex, pcHeader->mainvertex_stc_size).z;
  ------------------
  |  |   91|  7.20k|    _AI_MDL7_ACCESS(_data, _index, _limit, MDL::Vertex_MDL7)
  |  |  ------------------
  |  |  |  |   85|  7.20k|    (*((const _type *)(((const char *)_data) + _index * _limit)))
  |  |  ------------------
  ------------------
 1069|       |
 1070|       |            // if we have bones, save the index
 1071|  7.20k|            if (!groupData.aiBones.empty()) {
  ------------------
  |  Branch (1071:17): [True: 0, False: 7.20k]
  ------------------
 1072|      0|                groupData.aiBones[iOutIndex] = _AI_MDL7_ACCESS_VERT(groupInfo.pcGroupVerts,
  ------------------
  |  |   91|      0|    _AI_MDL7_ACCESS(_data, _index, _limit, MDL::Vertex_MDL7)
  |  |  ------------------
  |  |  |  |   85|      0|    (*((const _type *)(((const char *)_data) + _index * _limit)))
  |  |  ------------------
  ------------------
 1073|      0|                        iIndex, pcHeader->mainvertex_stc_size)
 1074|      0|                                                       .vertindex;
 1075|      0|            }
 1076|       |
 1077|       |            // now read the normal vector
 1078|  7.20k|            if (AI_MDL7_FRAMEVERTEX030305_STCSIZE <= pcHeader->mainvertex_stc_size) {
  ------------------
  |  |  592|  7.20k|#define AI_MDL7_FRAMEVERTEX030305_STCSIZE       26
  ------------------
  |  Branch (1078:17): [True: 7.20k, False: 0]
  ------------------
 1079|       |                // read the full normal vector
 1080|  7.20k|                aiVector3D &vNormal = groupData.vNormals[iOutIndex];
 1081|  7.20k|                vNormal.x = _AI_MDL7_ACCESS_VERT(groupInfo.pcGroupVerts, iIndex, pcHeader->mainvertex_stc_size).norm[0];
  ------------------
  |  |   91|  7.20k|    _AI_MDL7_ACCESS(_data, _index, _limit, MDL::Vertex_MDL7)
  |  |  ------------------
  |  |  |  |   85|  7.20k|    (*((const _type *)(((const char *)_data) + _index * _limit)))
  |  |  ------------------
  ------------------
 1082|  7.20k|                AI_SWAP4(vNormal.x);
 1083|  7.20k|                vNormal.y = _AI_MDL7_ACCESS_VERT(groupInfo.pcGroupVerts, iIndex, pcHeader->mainvertex_stc_size).norm[1];
  ------------------
  |  |   91|  7.20k|    _AI_MDL7_ACCESS(_data, _index, _limit, MDL::Vertex_MDL7)
  |  |  ------------------
  |  |  |  |   85|  7.20k|    (*((const _type *)(((const char *)_data) + _index * _limit)))
  |  |  ------------------
  ------------------
 1084|  7.20k|                AI_SWAP4(vNormal.y);
 1085|  7.20k|                vNormal.z = _AI_MDL7_ACCESS_VERT(groupInfo.pcGroupVerts, iIndex, pcHeader->mainvertex_stc_size).norm[2];
  ------------------
  |  |   91|  7.20k|    _AI_MDL7_ACCESS(_data, _index, _limit, MDL::Vertex_MDL7)
  |  |  ------------------
  |  |  |  |   85|  7.20k|    (*((const _type *)(((const char *)_data) + _index * _limit)))
  |  |  ------------------
  ------------------
 1086|  7.20k|                AI_SWAP4(vNormal.z);
 1087|  7.20k|            } else if (AI_MDL7_FRAMEVERTEX120503_STCSIZE <= pcHeader->mainvertex_stc_size) {
  ------------------
  |  |  591|      0|#define AI_MDL7_FRAMEVERTEX120503_STCSIZE       16
  ------------------
  |  Branch (1087:24): [True: 0, False: 0]
  ------------------
 1088|       |                // read the normal vector from Quake2's smart table
 1089|      0|                aiVector3D &vNormal = groupData.vNormals[iOutIndex];
 1090|      0|                MD2::LookupNormalIndex(_AI_MDL7_ACCESS_VERT(groupInfo.pcGroupVerts, iIndex,
  ------------------
  |  |   91|      0|    _AI_MDL7_ACCESS(_data, _index, _limit, MDL::Vertex_MDL7)
  |  |  ------------------
  |  |  |  |   85|      0|    (*((const _type *)(((const char *)_data) + _index * _limit)))
  |  |  ------------------
  ------------------
 1091|      0|                                               pcHeader->mainvertex_stc_size)
 1092|      0|                                               .norm162index,
 1093|      0|                        vNormal);
 1094|      0|            }
 1095|       |            // validate and process the first uv coordinate set
 1096|  7.20k|            if (pcHeader->triangle_stc_size >= AI_MDL7_TRIANGLE_STD_SIZE_ONE_UV) {
  ------------------
  |  |  555|  7.20k|#   define AI_MDL7_TRIANGLE_STD_SIZE_ONE_UV (6+sizeof(SkinSet_MDL7)-sizeof(uint32_t))
  ------------------
  |  Branch (1096:17): [True: 7.20k, False: 0]
  ------------------
 1097|       |
 1098|  7.20k|                if (groupInfo.pcGroup->num_stpts) {
  ------------------
  |  Branch (1098:21): [True: 0, False: 7.20k]
  ------------------
 1099|      0|                    AI_SWAP2(pcGroupTris->skinsets[0].st_index[0]);
 1100|      0|                    AI_SWAP2(pcGroupTris->skinsets[0].st_index[1]);
 1101|      0|                    AI_SWAP2(pcGroupTris->skinsets[0].st_index[2]);
 1102|       |
 1103|      0|                    iIndex = pcGroupTris->skinsets[0].st_index[c];
 1104|      0|                    if (iIndex > (unsigned int)groupInfo.pcGroup->num_stpts) {
  ------------------
  |  Branch (1104:25): [True: 0, False: 0]
  ------------------
 1105|      0|                        iIndex = groupInfo.pcGroup->num_stpts - 1;
 1106|      0|                        ASSIMP_LOG_WARN("Index overflow in MDL7 UV coordinate list (#1)");
 1107|      0|                    }
 1108|       |
 1109|      0|                    float u = groupInfo.pcGroupUVs[iIndex].u;
 1110|      0|                    float v = 1.0f - groupInfo.pcGroupUVs[iIndex].v; // DX to OGL
 1111|       |
 1112|      0|                    groupData.vTextureCoords1[iOutIndex].x = u;
 1113|      0|                    groupData.vTextureCoords1[iOutIndex].y = v;
 1114|      0|                }
 1115|       |                // assign the material index, but only if it is existing
 1116|  7.20k|                if (pcHeader->triangle_stc_size >= AI_MDL7_TRIANGLE_STD_SIZE_ONE_UV_WITH_MATINDEX) {
  ------------------
  |  |  558|  7.20k|#   define AI_MDL7_TRIANGLE_STD_SIZE_ONE_UV_WITH_MATINDEX (6+sizeof(SkinSet_MDL7))
  ------------------
  |  Branch (1116:21): [True: 7.20k, False: 0]
  ------------------
 1117|  7.20k|                    AI_SWAP4(pcGroupTris->skinsets[0].material);
 1118|  7.20k|                    groupData.pcFaces[iTriangle].iMatIndex[0] = pcGroupTris->skinsets[0].material;
 1119|  7.20k|                }
 1120|  7.20k|            }
 1121|       |            // validate and process the second uv coordinate set
 1122|  7.20k|            if (pcHeader->triangle_stc_size >= AI_MDL7_TRIANGLE_STD_SIZE_TWO_UV) {
  ------------------
  |  |  561|  7.20k|#   define AI_MDL7_TRIANGLE_STD_SIZE_TWO_UV (6+2*sizeof(SkinSet_MDL7))
  ------------------
  |  Branch (1122:17): [True: 0, False: 7.20k]
  ------------------
 1123|       |
 1124|      0|                if (groupInfo.pcGroup->num_stpts) {
  ------------------
  |  Branch (1124:21): [True: 0, False: 0]
  ------------------
 1125|      0|                    AI_SWAP2(pcGroupTris->skinsets[1].st_index[0]);
 1126|      0|                    AI_SWAP2(pcGroupTris->skinsets[1].st_index[1]);
 1127|      0|                    AI_SWAP2(pcGroupTris->skinsets[1].st_index[2]);
 1128|      0|                    AI_SWAP4(pcGroupTris->skinsets[1].material);
 1129|       |
 1130|      0|                    iIndex = pcGroupTris->skinsets[1].st_index[c];
 1131|      0|                    if (iIndex > (unsigned int)groupInfo.pcGroup->num_stpts) {
  ------------------
  |  Branch (1131:25): [True: 0, False: 0]
  ------------------
 1132|      0|                        iIndex = groupInfo.pcGroup->num_stpts - 1;
 1133|      0|                        ASSIMP_LOG_WARN("Index overflow in MDL7 UV coordinate list (#2)");
 1134|      0|                    }
 1135|       |
 1136|      0|                    float u = groupInfo.pcGroupUVs[iIndex].u;
 1137|      0|                    float v = 1.0f - groupInfo.pcGroupUVs[iIndex].v;
 1138|       |
 1139|      0|                    groupData.vTextureCoords2[iOutIndex].x = u;
 1140|      0|                    groupData.vTextureCoords2[iOutIndex].y = v; // DX to OGL
 1141|       |
 1142|       |                    // check whether we do really need the second texture
 1143|       |                    // coordinate set ... wastes memory and loading time
 1144|      0|                    if (0 != iIndex && (u != groupData.vTextureCoords1[iOutIndex].x ||
  ------------------
  |  Branch (1144:25): [True: 0, False: 0]
  |  Branch (1144:41): [True: 0, False: 0]
  ------------------
 1145|      0|                                               v != groupData.vTextureCoords1[iOutIndex].y))
  ------------------
  |  Branch (1145:48): [True: 0, False: 0]
  ------------------
 1146|      0|                        groupData.bNeed2UV = true;
 1147|       |
 1148|       |                    // if the material differs, we need a second skin, too
 1149|      0|                    if (pcGroupTris->skinsets[1].material != pcGroupTris->skinsets[0].material)
  ------------------
  |  Branch (1149:25): [True: 0, False: 0]
  ------------------
 1150|      0|                        groupData.bNeed2UV = true;
 1151|      0|                }
 1152|       |                // assign the material index
 1153|      0|                groupData.pcFaces[iTriangle].iMatIndex[1] = pcGroupTris->skinsets[1].material;
 1154|      0|            }
 1155|  7.20k|        }
 1156|       |        // get the next triangle in the list
 1157|  2.40k|        pcGroupTris = (MDL::Triangle_MDL7 *)((const char *)pcGroupTris + pcHeader->triangle_stc_size);
 1158|  2.40k|    }
 1159|     20|}
_ZN6Assimp11MDLImporter23ProcessFrames_3DGS_MDL7ERKNS_3MDL17IntGroupInfo_MDL7ERNS1_17IntGroupData_MDL7ERNS1_18IntSharedData_MDL7EPKhPSA_:
 1167|     20|        const unsigned char **szCurrentOut) {
 1168|     20|    ai_assert(nullptr != szCurrent);
 1169|     20|    ai_assert(nullptr != szCurrentOut);
 1170|       |
 1171|     20|    const MDL::Header_MDL7 *pcHeader = (const MDL::Header_MDL7 *)mBuffer;
 1172|       |
 1173|       |    // if we have no bones we can simply skip all frames,
 1174|       |    // otherwise we'll need to process them.
 1175|       |    // FIX: If we need another frame than the first we must apply frame vertex replacements ...
 1176|     20|    for (unsigned int iFrame = 0; iFrame < (unsigned int)groupInfo.pcGroup->numframes; ++iFrame) {
  ------------------
  |  Branch (1176:35): [True: 0, False: 20]
  ------------------
 1177|      0|        MDL::IntFrameInfo_MDL7 frame((BE_NCONST MDL::Frame_MDL7 *)szCurrent, iFrame);
 1178|       |
 1179|      0|        VALIDATE_FILE_SIZE((const unsigned char *)(frame.pcFrame + 1));
  ------------------
  |  |   63|      0|#   define VALIDATE_FILE_SIZE(msg) SizeCheck(msg,__FILE__,__LINE__)
  ------------------
 1180|      0|        AI_SWAP4(frame.pcFrame->vertices_count);
 1181|      0|        AI_SWAP4(frame.pcFrame->transmatrix_count);
 1182|       |
 1183|      0|        const unsigned int iAdd = pcHeader->frame_stc_size +
 1184|      0|                                  frame.pcFrame->vertices_count * pcHeader->framevertex_stc_size +
 1185|      0|                                  frame.pcFrame->transmatrix_count * pcHeader->bonetrans_stc_size;
 1186|       |
 1187|      0|        if (((const char *)szCurrent - (const char *)pcHeader) + iAdd > (unsigned int)pcHeader->data_size) {
  ------------------
  |  Branch (1187:13): [True: 0, False: 0]
  ------------------
 1188|      0|            ASSIMP_LOG_WARN("Index overflow in frame area. "
 1189|      0|                            "Ignoring all frames and all further mesh groups, too.");
 1190|       |
 1191|       |            // don't parse more groups if we can't even read one
 1192|       |            // FIXME: sometimes this seems to occur even for valid files ...
 1193|      0|            *szCurrentOut = szCurrent;
 1194|      0|            return false;
 1195|      0|        }
 1196|       |        // our output frame?
 1197|      0|        if (configFrameID == iFrame) {
  ------------------
  |  Branch (1197:13): [True: 0, False: 0]
  ------------------
 1198|      0|            BE_NCONST MDL::Vertex_MDL7 *pcFrameVertices = (BE_NCONST MDL::Vertex_MDL7 *)(szCurrent + pcHeader->frame_stc_size);
 1199|       |
 1200|      0|            for (unsigned int qq = 0; qq < frame.pcFrame->vertices_count; ++qq) {
  ------------------
  |  Branch (1200:39): [True: 0, False: 0]
  ------------------
 1201|       |                // I assume this are simple replacements for normal vertices, the bone index serving
 1202|       |                // as the index of the vertex to be replaced.
 1203|      0|                uint16_t iIndex = _AI_MDL7_ACCESS(pcFrameVertices, qq, pcHeader->framevertex_stc_size, MDL::Vertex_MDL7).vertindex;
  ------------------
  |  |   85|      0|    (*((const _type *)(((const char *)_data) + _index * _limit)))
  ------------------
 1204|      0|                AI_SWAP2(iIndex);
 1205|      0|                if (iIndex >= groupInfo.pcGroup->numverts) {
  ------------------
  |  Branch (1205:21): [True: 0, False: 0]
  ------------------
 1206|      0|                    ASSIMP_LOG_WARN("Invalid vertex index in frame vertex section");
 1207|      0|                    continue;
 1208|      0|                }
 1209|       |
 1210|      0|                aiVector3D vPosition, vNormal;
 1211|       |
 1212|      0|                vPosition.x = _AI_MDL7_ACCESS_VERT(pcFrameVertices, qq, pcHeader->framevertex_stc_size).x;
  ------------------
  |  |   91|      0|    _AI_MDL7_ACCESS(_data, _index, _limit, MDL::Vertex_MDL7)
  |  |  ------------------
  |  |  |  |   85|      0|    (*((const _type *)(((const char *)_data) + _index * _limit)))
  |  |  ------------------
  ------------------
 1213|      0|                AI_SWAP4(vPosition.x);
 1214|      0|                vPosition.y = _AI_MDL7_ACCESS_VERT(pcFrameVertices, qq, pcHeader->framevertex_stc_size).y;
  ------------------
  |  |   91|      0|    _AI_MDL7_ACCESS(_data, _index, _limit, MDL::Vertex_MDL7)
  |  |  ------------------
  |  |  |  |   85|      0|    (*((const _type *)(((const char *)_data) + _index * _limit)))
  |  |  ------------------
  ------------------
 1215|      0|                AI_SWAP4(vPosition.y);
 1216|      0|                vPosition.z = _AI_MDL7_ACCESS_VERT(pcFrameVertices, qq, pcHeader->framevertex_stc_size).z;
  ------------------
  |  |   91|      0|    _AI_MDL7_ACCESS(_data, _index, _limit, MDL::Vertex_MDL7)
  |  |  ------------------
  |  |  |  |   85|      0|    (*((const _type *)(((const char *)_data) + _index * _limit)))
  |  |  ------------------
  ------------------
 1217|      0|                AI_SWAP4(vPosition.z);
 1218|       |
 1219|       |                // now read the normal vector
 1220|      0|                if (AI_MDL7_FRAMEVERTEX030305_STCSIZE <= pcHeader->mainvertex_stc_size) {
  ------------------
  |  |  592|      0|#define AI_MDL7_FRAMEVERTEX030305_STCSIZE       26
  ------------------
  |  Branch (1220:21): [True: 0, False: 0]
  ------------------
 1221|       |                    // read the full normal vector
 1222|      0|                    vNormal.x = _AI_MDL7_ACCESS_VERT(pcFrameVertices, qq, pcHeader->framevertex_stc_size).norm[0];
  ------------------
  |  |   91|      0|    _AI_MDL7_ACCESS(_data, _index, _limit, MDL::Vertex_MDL7)
  |  |  ------------------
  |  |  |  |   85|      0|    (*((const _type *)(((const char *)_data) + _index * _limit)))
  |  |  ------------------
  ------------------
 1223|      0|                    AI_SWAP4(vNormal.x);
 1224|      0|                    vNormal.y = _AI_MDL7_ACCESS_VERT(pcFrameVertices, qq, pcHeader->framevertex_stc_size).norm[1];
  ------------------
  |  |   91|      0|    _AI_MDL7_ACCESS(_data, _index, _limit, MDL::Vertex_MDL7)
  |  |  ------------------
  |  |  |  |   85|      0|    (*((const _type *)(((const char *)_data) + _index * _limit)))
  |  |  ------------------
  ------------------
 1225|      0|                    AI_SWAP4(vNormal.y);
 1226|      0|                    vNormal.z = _AI_MDL7_ACCESS_VERT(pcFrameVertices, qq, pcHeader->framevertex_stc_size).norm[2];
  ------------------
  |  |   91|      0|    _AI_MDL7_ACCESS(_data, _index, _limit, MDL::Vertex_MDL7)
  |  |  ------------------
  |  |  |  |   85|      0|    (*((const _type *)(((const char *)_data) + _index * _limit)))
  |  |  ------------------
  ------------------
 1227|      0|                    AI_SWAP4(vNormal.z);
 1228|      0|                } else if (AI_MDL7_FRAMEVERTEX120503_STCSIZE <= pcHeader->mainvertex_stc_size) {
  ------------------
  |  |  591|      0|#define AI_MDL7_FRAMEVERTEX120503_STCSIZE       16
  ------------------
  |  Branch (1228:28): [True: 0, False: 0]
  ------------------
 1229|       |                    // read the normal vector from Quake2's smart table
 1230|      0|                    MD2::LookupNormalIndex(_AI_MDL7_ACCESS_VERT(pcFrameVertices, qq,
  ------------------
  |  |   91|      0|    _AI_MDL7_ACCESS(_data, _index, _limit, MDL::Vertex_MDL7)
  |  |  ------------------
  |  |  |  |   85|      0|    (*((const _type *)(((const char *)_data) + _index * _limit)))
  |  |  ------------------
  ------------------
 1231|      0|                                                   pcHeader->framevertex_stc_size)
 1232|      0|                                                   .norm162index,
 1233|      0|                            vNormal);
 1234|      0|                }
 1235|       |
 1236|       |                // FIXME: O(n^2) at the moment ...
 1237|      0|                BE_NCONST MDL::Triangle_MDL7 *pcGroupTris = groupInfo.pcGroupTris;
 1238|      0|                unsigned int iOutIndex = 0;
 1239|      0|                for (unsigned int iTriangle = 0; iTriangle < (unsigned int)groupInfo.pcGroup->numtris; ++iTriangle) {
  ------------------
  |  Branch (1239:50): [True: 0, False: 0]
  ------------------
 1240|       |                    // iterate through all indices of the current triangle
 1241|      0|                    for (unsigned int c = 0; c < 3; ++c, ++iOutIndex) {
  ------------------
  |  Branch (1241:46): [True: 0, False: 0]
  ------------------
 1242|       |                        // replace the vertex with the new data
 1243|      0|                        const unsigned int iCurIndex = pcGroupTris->v_index[c];
 1244|      0|                        if (iCurIndex == iIndex) {
  ------------------
  |  Branch (1244:29): [True: 0, False: 0]
  ------------------
 1245|      0|                            groupData.vPositions[iOutIndex] = vPosition;
 1246|      0|                            groupData.vNormals[iOutIndex] = vNormal;
 1247|      0|                        }
 1248|      0|                    }
 1249|       |                    // get the next triangle in the list
 1250|      0|                    pcGroupTris = (BE_NCONST MDL::Triangle_MDL7 *)((const char *)
 1251|      0|                                                                           pcGroupTris +
 1252|      0|                                                                   pcHeader->triangle_stc_size);
 1253|      0|                }
 1254|      0|            }
 1255|      0|        }
 1256|       |        // parse bone trafo matrix keys (only if there are bones ...)
 1257|      0|        if (shared.apcOutBones) {
  ------------------
  |  Branch (1257:13): [True: 0, False: 0]
  ------------------
 1258|      0|            ParseBoneTrafoKeys_3DGS_MDL7(groupInfo, frame, shared);
 1259|      0|        }
 1260|      0|        szCurrent += iAdd;
 1261|      0|    }
 1262|     20|    *szCurrentOut = szCurrent;
 1263|     20|    return true;
 1264|     20|}
_ZN6Assimp11MDLImporter25SortByMaterials_3DGS_MDL7ERKNS_3MDL17IntGroupInfo_MDL7ERNS1_17IntGroupData_MDL7ERNS1_22IntSplitGroupData_MDL7E:
 1271|     20|        MDL::IntSplitGroupData_MDL7 &splitGroupData) {
 1272|     20|    const unsigned int iNumMaterials = (unsigned int)splitGroupData.shared.pcMats.size();
 1273|     20|    if (!groupData.bNeed2UV) {
  ------------------
  |  Branch (1273:9): [True: 20, False: 0]
  ------------------
 1274|       |        // if we don't need a second set of texture coordinates there is no reason to keep it in memory ...
 1275|     20|        groupData.vTextureCoords2.clear();
 1276|       |
 1277|       |        // allocate the array
 1278|     20|        splitGroupData.aiSplit = new std::vector<unsigned int> *[iNumMaterials];
 1279|       |
 1280|     80|        for (unsigned int m = 0; m < iNumMaterials; ++m)
  ------------------
  |  Branch (1280:34): [True: 60, False: 20]
  ------------------
 1281|     60|            splitGroupData.aiSplit[m] = new std::vector<unsigned int>();
 1282|       |
 1283|       |        // iterate through all faces and sort by material
 1284|  2.42k|        for (unsigned int iFace = 0; iFace < (unsigned int)groupInfo.pcGroup->numtris; ++iFace) {
  ------------------
  |  Branch (1284:38): [True: 2.40k, False: 20]
  ------------------
 1285|       |            // check range
 1286|  2.40k|            if (groupData.pcFaces[iFace].iMatIndex[0] >= iNumMaterials) {
  ------------------
  |  Branch (1286:17): [True: 3, False: 2.39k]
  ------------------
 1287|       |                // use the last material instead
 1288|      3|                splitGroupData.aiSplit[iNumMaterials - 1]->push_back(iFace);
 1289|       |
 1290|       |                // sometimes MED writes -1, but normally only if there is only
 1291|       |                // one skin assigned. No warning in this case
 1292|      3|                if (0xFFFFFFFF != groupData.pcFaces[iFace].iMatIndex[0])
  ------------------
  |  Branch (1292:21): [True: 3, False: 0]
  ------------------
 1293|      3|                    ASSIMP_LOG_WARN("Index overflow in MDL7 material list [#0]");
 1294|      3|            } else
 1295|  2.39k|                splitGroupData.aiSplit[groupData.pcFaces[iFace].iMatIndex[0]]->push_back(iFace);
 1296|  2.40k|        }
 1297|     20|    } else {
 1298|       |        // we need to build combined materials for each combination of
 1299|      0|        std::vector<MDL::IntMaterial_MDL7> avMats;
 1300|      0|        avMats.reserve(iNumMaterials * 2);
 1301|       |
 1302|       |        // fixme: why on the heap?
 1303|      0|        std::vector<std::vector<unsigned int> *> aiTempSplit(iNumMaterials * 2);
 1304|      0|        for (unsigned int m = 0; m < iNumMaterials; ++m)
  ------------------
  |  Branch (1304:34): [True: 0, False: 0]
  ------------------
 1305|      0|            aiTempSplit[m] = new std::vector<unsigned int>();
 1306|       |
 1307|       |        // iterate through all faces and sort by material
 1308|      0|        for (unsigned int iFace = 0; iFace < (unsigned int)groupInfo.pcGroup->numtris; ++iFace) {
  ------------------
  |  Branch (1308:38): [True: 0, False: 0]
  ------------------
 1309|       |            // check range
 1310|      0|            unsigned int iMatIndex = groupData.pcFaces[iFace].iMatIndex[0];
 1311|      0|            if (iMatIndex >= iNumMaterials) {
  ------------------
  |  Branch (1311:17): [True: 0, False: 0]
  ------------------
 1312|       |                // sometimes MED writes -1, but normally only if there is only
 1313|       |                // one skin assigned. No warning in this case
 1314|      0|                if (UINT_MAX != iMatIndex)
  ------------------
  |  Branch (1314:21): [True: 0, False: 0]
  ------------------
 1315|      0|                    ASSIMP_LOG_WARN("Index overflow in MDL7 material list [#1]");
 1316|      0|                iMatIndex = iNumMaterials - 1;
 1317|      0|            }
 1318|      0|            unsigned int iMatIndex2 = groupData.pcFaces[iFace].iMatIndex[1];
 1319|       |
 1320|      0|            unsigned int iNum = iMatIndex;
 1321|      0|            if (UINT_MAX != iMatIndex2 && iMatIndex != iMatIndex2) {
  ------------------
  |  Branch (1321:17): [True: 0, False: 0]
  |  Branch (1321:43): [True: 0, False: 0]
  ------------------
 1322|      0|                if (iMatIndex2 >= iNumMaterials) {
  ------------------
  |  Branch (1322:21): [True: 0, False: 0]
  ------------------
 1323|       |                    // sometimes MED writes -1, but normally only if there is only
 1324|       |                    // one skin assigned. No warning in this case
 1325|      0|                    ASSIMP_LOG_WARN("Index overflow in MDL7 material list [#2]");
 1326|      0|                    iMatIndex2 = iNumMaterials - 1;
 1327|      0|                }
 1328|       |
 1329|       |                // do a slow search in the list ...
 1330|      0|                iNum = 0;
 1331|      0|                bool bFound = false;
 1332|      0|                for (std::vector<MDL::IntMaterial_MDL7>::iterator i = avMats.begin(); i != avMats.end(); ++i, ++iNum) {
  ------------------
  |  Branch (1332:87): [True: 0, False: 0]
  ------------------
 1333|      0|                    if ((*i).iOldMatIndices[0] == iMatIndex && (*i).iOldMatIndices[1] == iMatIndex2) {
  ------------------
  |  Branch (1333:25): [True: 0, False: 0]
  |  Branch (1333:64): [True: 0, False: 0]
  ------------------
 1334|       |                        // reuse this material
 1335|      0|                        bFound = true;
 1336|      0|                        break;
 1337|      0|                    }
 1338|      0|                }
 1339|      0|                if (!bFound) {
  ------------------
  |  Branch (1339:21): [True: 0, False: 0]
  ------------------
 1340|       |                    //  build a new material ...
 1341|      0|                    MDL::IntMaterial_MDL7 sHelper;
 1342|      0|                    sHelper.pcMat = new aiMaterial();
 1343|      0|                    sHelper.iOldMatIndices[0] = iMatIndex;
 1344|      0|                    sHelper.iOldMatIndices[1] = iMatIndex2;
 1345|      0|                    JoinSkins_3DGS_MDL7(splitGroupData.shared.pcMats[iMatIndex],
 1346|      0|                            splitGroupData.shared.pcMats[iMatIndex2], sHelper.pcMat);
 1347|       |
 1348|       |                    // and add it to the list
 1349|      0|                    avMats.push_back(sHelper);
 1350|      0|                    iNum = (unsigned int)avMats.size() - 1;
 1351|      0|                }
 1352|       |                // adjust the size of the file array
 1353|      0|                if (iNum == aiTempSplit.size()) {
  ------------------
  |  Branch (1353:21): [True: 0, False: 0]
  ------------------
 1354|      0|                    aiTempSplit.push_back(new std::vector<unsigned int>());
 1355|      0|                }
 1356|      0|            }
 1357|      0|            aiTempSplit[iNum]->push_back(iFace);
 1358|      0|        }
 1359|       |
 1360|       |        // now add the newly created materials to the old list
 1361|      0|        if (0 == groupInfo.iIndex) {
  ------------------
  |  Branch (1361:13): [True: 0, False: 0]
  ------------------
 1362|      0|            splitGroupData.shared.pcMats.resize(avMats.size());
 1363|      0|            for (unsigned int o = 0; o < avMats.size(); ++o)
  ------------------
  |  Branch (1363:38): [True: 0, False: 0]
  ------------------
 1364|      0|                splitGroupData.shared.pcMats[o] = avMats[o].pcMat;
 1365|      0|        } else {
 1366|       |            // This might result in redundant materials ...
 1367|      0|            splitGroupData.shared.pcMats.resize(iNumMaterials + avMats.size());
 1368|      0|            for (unsigned int o = iNumMaterials; o < avMats.size(); ++o)
  ------------------
  |  Branch (1368:50): [True: 0, False: 0]
  ------------------
 1369|      0|                splitGroupData.shared.pcMats[o] = avMats[o].pcMat;
 1370|      0|        }
 1371|       |
 1372|       |        // and build the final face-to-material array
 1373|      0|        splitGroupData.aiSplit = new std::vector<unsigned int> *[aiTempSplit.size()];
 1374|      0|        for (unsigned int m = 0; m < iNumMaterials; ++m)
  ------------------
  |  Branch (1374:34): [True: 0, False: 0]
  ------------------
 1375|      0|            splitGroupData.aiSplit[m] = aiTempSplit[m];
 1376|      0|    }
 1377|     20|}
_ZN6Assimp11MDLImporter24InternReadFile_3DGS_MDL7Ev:
 1381|      4|void MDLImporter::InternReadFile_3DGS_MDL7() {
 1382|      4|    ai_assert(nullptr != pScene);
 1383|       |
 1384|      4|    MDL::IntSharedData_MDL7 sharedData;
 1385|       |
 1386|       |    // current cursor position in the file
 1387|      4|    BE_NCONST MDL::Header_MDL7 *pcHeader = (BE_NCONST MDL::Header_MDL7 *)this->mBuffer;
 1388|      4|    const unsigned char *szCurrent = (const unsigned char *)(pcHeader + 1);
 1389|       |
 1390|      4|    AI_SWAP4(pcHeader->version);
 1391|      4|    AI_SWAP4(pcHeader->bones_num);
 1392|      4|    AI_SWAP4(pcHeader->groups_num);
 1393|      4|    AI_SWAP4(pcHeader->data_size);
 1394|      4|    AI_SWAP4(pcHeader->entlump_size);
 1395|      4|    AI_SWAP4(pcHeader->medlump_size);
 1396|      4|    AI_SWAP2(pcHeader->bone_stc_size);
 1397|      4|    AI_SWAP2(pcHeader->skin_stc_size);
 1398|      4|    AI_SWAP2(pcHeader->colorvalue_stc_size);
 1399|      4|    AI_SWAP2(pcHeader->material_stc_size);
 1400|      4|    AI_SWAP2(pcHeader->skinpoint_stc_size);
 1401|      4|    AI_SWAP2(pcHeader->triangle_stc_size);
 1402|      4|    AI_SWAP2(pcHeader->mainvertex_stc_size);
 1403|      4|    AI_SWAP2(pcHeader->framevertex_stc_size);
 1404|      4|    AI_SWAP2(pcHeader->bonetrans_stc_size);
 1405|      4|    AI_SWAP2(pcHeader->frame_stc_size);
 1406|       |
 1407|       |    // validate the header of the file. There are some structure
 1408|       |    // sizes that are expected by the loader to be constant
 1409|      4|    this->ValidateHeader_3DGS_MDL7(pcHeader);
 1410|       |
 1411|       |    // load all bones (they are shared by all groups, so
 1412|       |    // we'll need to add them to all groups/meshes later)
 1413|       |    // apcBonesOut is a list of all bones or nullptr if they could not been loaded
 1414|      4|    szCurrent += pcHeader->bones_num * pcHeader->bone_stc_size;
 1415|      4|    sharedData.apcOutBones = this->LoadBones_3DGS_MDL7();
 1416|       |
 1417|       |    // vector to held all created meshes
 1418|      4|    std::vector<aiMesh *> *avOutList;
 1419|       |
 1420|       |    // 3 meshes per group - that should be OK for most models
 1421|      4|    avOutList = new std::vector<aiMesh *>[pcHeader->groups_num];
 1422|     36|    for (uint32_t i = 0; i < pcHeader->groups_num; ++i)
  ------------------
  |  Branch (1422:26): [True: 32, False: 4]
  ------------------
 1423|     32|        avOutList[i].reserve(3);
 1424|       |
 1425|       |    // buffer to held the names of all groups in the file
 1426|      4|    const size_t buffersize(AI_MDL7_MAX_GROUPNAMESIZE * pcHeader->groups_num);
  ------------------
  |  |  260|      4|#   define AI_MDL7_MAX_GROUPNAMESIZE    16
  ------------------
 1427|      4|    char *aszGroupNameBuffer = new char[buffersize];
 1428|       |
 1429|       |    // read all groups
 1430|     27|    for (unsigned int iGroup = 0; iGroup < (unsigned int)pcHeader->groups_num; ++iGroup) {
  ------------------
  |  Branch (1430:35): [True: 23, False: 4]
  ------------------
 1431|     23|        MDL::IntGroupInfo_MDL7 groupInfo((BE_NCONST MDL::Group_MDL7 *)szCurrent, iGroup);
 1432|     23|        szCurrent = (const unsigned char *)(groupInfo.pcGroup + 1);
 1433|       |
 1434|     23|        VALIDATE_FILE_SIZE(szCurrent);
  ------------------
  |  |   63|     23|#   define VALIDATE_FILE_SIZE(msg) SizeCheck(msg,__FILE__,__LINE__)
  ------------------
 1435|       |
 1436|     23|        AI_SWAP4(groupInfo.pcGroup->groupdata_size);
 1437|     23|        AI_SWAP4(groupInfo.pcGroup->numskins);
 1438|     23|        AI_SWAP4(groupInfo.pcGroup->num_stpts);
 1439|     23|        AI_SWAP4(groupInfo.pcGroup->numtris);
 1440|     23|        AI_SWAP4(groupInfo.pcGroup->numverts);
 1441|     23|        AI_SWAP4(groupInfo.pcGroup->numframes);
 1442|       |
 1443|     23|        if (1 != groupInfo.pcGroup->typ) {
  ------------------
  |  Branch (1443:13): [True: 4, False: 19]
  ------------------
 1444|       |            // Not a triangle-based mesh
 1445|      4|            ASSIMP_LOG_WARN("[3DGS MDL7] Not a triangle mesh group. Continuing happily");
 1446|      4|        }
 1447|       |
 1448|       |        // store the name of the group
 1449|     23|        const unsigned int ofs = iGroup * AI_MDL7_MAX_GROUPNAMESIZE;
  ------------------
  |  |  260|     23|#   define AI_MDL7_MAX_GROUPNAMESIZE    16
  ------------------
 1450|     23|        ::memcpy(&aszGroupNameBuffer[ofs],
 1451|     23|                groupInfo.pcGroup->name, AI_MDL7_MAX_GROUPNAMESIZE);
  ------------------
  |  |  260|     23|#   define AI_MDL7_MAX_GROUPNAMESIZE    16
  ------------------
 1452|       |
 1453|       |        // make sure '\0' is at the end
 1454|     23|        aszGroupNameBuffer[ofs + AI_MDL7_MAX_GROUPNAMESIZE - 1] = '\0';
  ------------------
  |  |  260|     23|#   define AI_MDL7_MAX_GROUPNAMESIZE    16
  ------------------
 1455|       |
 1456|       |        // read all skins
 1457|     23|        sharedData.pcMats.reserve(sharedData.pcMats.size() + groupInfo.pcGroup->numskins);
 1458|     23|        sharedData.abNeedMaterials.resize(sharedData.abNeedMaterials.size() +
 1459|     23|                                                  groupInfo.pcGroup->numskins,
 1460|     23|                false);
 1461|       |
 1462|     37|        for (unsigned int iSkin = 0; iSkin < (unsigned int)groupInfo.pcGroup->numskins; ++iSkin) {
  ------------------
  |  Branch (1462:38): [True: 14, False: 23]
  ------------------
 1463|     14|            ParseSkinLump_3DGS_MDL7(szCurrent, &szCurrent, sharedData.pcMats);
 1464|     14|        }
 1465|       |        // if we have absolutely no skin loaded we need to generate a default material
 1466|     23|        if (sharedData.pcMats.empty()) {
  ------------------
  |  Branch (1466:13): [True: 0, False: 23]
  ------------------
 1467|      0|            const int iMode = (int)aiShadingMode_Gouraud;
 1468|      0|            sharedData.pcMats.push_back(new aiMaterial());
 1469|      0|            aiMaterial *pcHelper = (aiMaterial *)sharedData.pcMats[0];
 1470|      0|            pcHelper->AddProperty<int>(&iMode, 1, AI_MATKEY_SHADING_MODEL);
 1471|       |
 1472|      0|            aiColor3D clr;
 1473|      0|            clr.b = clr.g = clr.r = 0.6f;
 1474|      0|            pcHelper->AddProperty<aiColor3D>(&clr, 1, AI_MATKEY_COLOR_DIFFUSE);
 1475|      0|            pcHelper->AddProperty<aiColor3D>(&clr, 1, AI_MATKEY_COLOR_SPECULAR);
 1476|       |
 1477|      0|            clr.b = clr.g = clr.r = 0.05f;
 1478|      0|            pcHelper->AddProperty<aiColor3D>(&clr, 1, AI_MATKEY_COLOR_AMBIENT);
 1479|       |
 1480|      0|            aiString szName;
 1481|      0|            szName.Set(AI_DEFAULT_MATERIAL_NAME);
 1482|      0|            pcHelper->AddProperty(&szName, AI_MATKEY_NAME);
 1483|       |
 1484|      0|            sharedData.abNeedMaterials.resize(1, false);
 1485|      0|        }
 1486|       |
 1487|       |        // now get a pointer to all texture coords in the group
 1488|     23|        groupInfo.pcGroupUVs = (BE_NCONST MDL::TexCoord_MDL7 *)szCurrent;
 1489|     23|        for (int i = 0; i < groupInfo.pcGroup->num_stpts; ++i) {
  ------------------
  |  Branch (1489:25): [True: 0, False: 23]
  ------------------
 1490|      0|            AI_SWAP4(groupInfo.pcGroupUVs[i].u);
 1491|      0|            AI_SWAP4(groupInfo.pcGroupUVs[i].v);
 1492|      0|        }
 1493|     23|        szCurrent += pcHeader->skinpoint_stc_size * groupInfo.pcGroup->num_stpts;
 1494|       |
 1495|       |        // now get a pointer to all triangle in the group
 1496|     23|        groupInfo.pcGroupTris = (Triangle_MDL7 *)szCurrent;
 1497|     23|        szCurrent += pcHeader->triangle_stc_size * groupInfo.pcGroup->numtris;
 1498|       |
 1499|       |        // now get a pointer to all vertices in the group
 1500|     23|        groupInfo.pcGroupVerts = (BE_NCONST MDL::Vertex_MDL7 *)szCurrent;
 1501|  1.26k|        for (int i = 0; i < groupInfo.pcGroup->numverts; ++i) {
  ------------------
  |  Branch (1501:25): [True: 1.24k, False: 23]
  ------------------
 1502|  1.24k|            AI_SWAP4(groupInfo.pcGroupVerts[i].x);
 1503|  1.24k|            AI_SWAP4(groupInfo.pcGroupVerts[i].y);
 1504|  1.24k|            AI_SWAP4(groupInfo.pcGroupVerts[i].z);
 1505|       |
 1506|  1.24k|            AI_SWAP2(groupInfo.pcGroupVerts[i].vertindex);
 1507|       |            //We can not swap the normal information now as we don't know which of the two kinds it is
 1508|  1.24k|        }
 1509|     23|        szCurrent += pcHeader->mainvertex_stc_size * groupInfo.pcGroup->numverts;
 1510|     23|        VALIDATE_FILE_SIZE(szCurrent);
  ------------------
  |  |   63|     23|#   define VALIDATE_FILE_SIZE(msg) SizeCheck(msg,__FILE__,__LINE__)
  ------------------
 1511|       |
 1512|     23|        MDL::IntSplitGroupData_MDL7 splitGroupData(sharedData, avOutList[iGroup]);
 1513|     23|        MDL::IntGroupData_MDL7 groupData;
 1514|     23|        if (groupInfo.pcGroup->numtris && groupInfo.pcGroup->numverts) {
  ------------------
  |  Branch (1514:13): [True: 20, False: 3]
  |  Branch (1514:43): [True: 20, False: 0]
  ------------------
 1515|       |            // build output vectors
 1516|     20|            const unsigned int iNumVertices = groupInfo.pcGroup->numtris * 3;
 1517|     20|            groupData.vPositions.resize(iNumVertices);
 1518|     20|            groupData.vNormals.resize(iNumVertices);
 1519|       |
 1520|     20|            if (sharedData.apcOutBones) groupData.aiBones.resize(iNumVertices, UINT_MAX);
  ------------------
  |  Branch (1520:17): [True: 0, False: 20]
  ------------------
 1521|       |
 1522|       |            // it is also possible that there are 0 UV coordinate sets
 1523|     20|            if (groupInfo.pcGroup->num_stpts) {
  ------------------
  |  Branch (1523:17): [True: 0, False: 20]
  ------------------
 1524|      0|                groupData.vTextureCoords1.resize(iNumVertices, aiVector3D());
 1525|       |
 1526|       |                // check whether the triangle data structure is large enough
 1527|       |                // to contain a second UV coordinate set
 1528|      0|                if (pcHeader->triangle_stc_size >= AI_MDL7_TRIANGLE_STD_SIZE_TWO_UV) {
  ------------------
  |  |  561|      0|#   define AI_MDL7_TRIANGLE_STD_SIZE_TWO_UV (6+2*sizeof(SkinSet_MDL7))
  ------------------
  |  Branch (1528:21): [True: 0, False: 0]
  ------------------
 1529|      0|                    groupData.vTextureCoords2.resize(iNumVertices, aiVector3D());
 1530|      0|                    groupData.bNeed2UV = true;
 1531|      0|                }
 1532|      0|            }
 1533|     20|            groupData.pcFaces.resize(groupInfo.pcGroup->numtris);
 1534|       |
 1535|       |            // read all faces into the preallocated arrays
 1536|     20|            ReadFaces_3DGS_MDL7(groupInfo, groupData);
 1537|       |
 1538|       |            // sort by materials
 1539|     20|            SortByMaterials_3DGS_MDL7(groupInfo, groupData,
 1540|     20|                    splitGroupData);
 1541|       |
 1542|     80|            for (unsigned int qq = 0; qq < sharedData.pcMats.size(); ++qq) {
  ------------------
  |  Branch (1542:39): [True: 60, False: 20]
  ------------------
 1543|     60|                if (!splitGroupData.aiSplit[qq]->empty())
  ------------------
  |  Branch (1543:21): [True: 20, False: 40]
  ------------------
 1544|     20|                    sharedData.abNeedMaterials[qq] = true;
 1545|     60|            }
 1546|     20|        } else
 1547|     23|            ASSIMP_LOG_WARN("[3DGS MDL7] Mesh group consists of 0 "
 1548|     23|                            "vertices or faces. It will be skipped.");
 1549|       |
 1550|       |        // process all frames and generate output meshes
 1551|     23|        ProcessFrames_3DGS_MDL7(groupInfo, groupData, sharedData, szCurrent, &szCurrent);
 1552|     23|        GenerateOutputMeshes_3DGS_MDL7(groupData, splitGroupData);
 1553|     23|    }
 1554|       |
 1555|       |    // generate a nodegraph and subnodes for each group
 1556|      4|    pScene->mRootNode = new aiNode();
 1557|       |
 1558|       |    // now we need to build a final mesh list
 1559|     12|    for (uint32_t i = 0; i < pcHeader->groups_num; ++i)
  ------------------
  |  Branch (1559:26): [True: 8, False: 4]
  ------------------
 1560|      8|        pScene->mNumMeshes += (unsigned int)avOutList[i].size();
 1561|       |
 1562|      4|    pScene->mMeshes = new aiMesh *[pScene->mNumMeshes];
 1563|      4|    {
 1564|      4|        unsigned int p = 0, q = 0;
 1565|     12|        for (uint32_t i = 0; i < pcHeader->groups_num; ++i) {
  ------------------
  |  Branch (1565:30): [True: 8, False: 4]
  ------------------
 1566|     16|            for (unsigned int a = 0; a < avOutList[i].size(); ++a) {
  ------------------
  |  Branch (1566:38): [True: 8, False: 8]
  ------------------
 1567|      8|                pScene->mMeshes[p++] = avOutList[i][a];
 1568|      8|            }
 1569|      8|            if (!avOutList[i].empty()) ++pScene->mRootNode->mNumChildren;
  ------------------
  |  Branch (1569:17): [True: 8, False: 0]
  ------------------
 1570|      8|        }
 1571|       |        // we will later need an extra node to serve as parent for all bones
 1572|      4|        if (sharedData.apcOutBones) ++pScene->mRootNode->mNumChildren;
  ------------------
  |  Branch (1572:13): [True: 0, False: 4]
  ------------------
 1573|      4|        this->pScene->mRootNode->mChildren = new aiNode *[pScene->mRootNode->mNumChildren];
 1574|      4|        p = 0;
 1575|     12|        for (uint32_t i = 0; i < pcHeader->groups_num; ++i) {
  ------------------
  |  Branch (1575:30): [True: 8, False: 4]
  ------------------
 1576|      8|            if (avOutList[i].empty()) continue;
  ------------------
  |  Branch (1576:17): [True: 0, False: 8]
  ------------------
 1577|       |
 1578|      8|            aiNode *const pcNode = pScene->mRootNode->mChildren[p] = new aiNode();
 1579|      8|            pcNode->mNumMeshes = (unsigned int)avOutList[i].size();
 1580|      8|            pcNode->mMeshes = new unsigned int[pcNode->mNumMeshes];
 1581|      8|            pcNode->mParent = this->pScene->mRootNode;
 1582|     16|            for (unsigned int a = 0; a < pcNode->mNumMeshes; ++a)
  ------------------
  |  Branch (1582:38): [True: 8, False: 8]
  ------------------
 1583|      8|                pcNode->mMeshes[a] = q + a;
 1584|      8|            q += (unsigned int)avOutList[i].size();
 1585|       |
 1586|       |            // setup the name of the node
 1587|      8|            char *const szBuffer = &aszGroupNameBuffer[i * AI_MDL7_MAX_GROUPNAMESIZE];
  ------------------
  |  |  260|      8|#   define AI_MDL7_MAX_GROUPNAMESIZE    16
  ------------------
 1588|      8|            if ('\0' == *szBuffer) {
  ------------------
  |  Branch (1588:17): [True: 8, False: 0]
  ------------------
 1589|      8|                const size_t maxSize(buffersize - (i * AI_MDL7_MAX_GROUPNAMESIZE));
  ------------------
  |  |  260|      8|#   define AI_MDL7_MAX_GROUPNAMESIZE    16
  ------------------
 1590|      8|                pcNode->mName.length = ai_snprintf(szBuffer, maxSize, "Group_%u", p);
 1591|      8|            } else {
 1592|      0|                pcNode->mName.length = (ai_uint32)::strlen(szBuffer);
 1593|      0|            }
 1594|      8|            ::strncpy(pcNode->mName.data, szBuffer, AI_MAXLEN - 1);
 1595|      8|            ++p;
 1596|      8|        }
 1597|      4|    }
 1598|       |
 1599|       |    // if there is only one root node with a single child we can optimize it a bit ...
 1600|      4|    if (1 == pScene->mRootNode->mNumChildren && !sharedData.apcOutBones) {
  ------------------
  |  Branch (1600:9): [True: 0, False: 4]
  |  Branch (1600:49): [True: 0, False: 0]
  ------------------
 1601|      0|        aiNode *pcOldRoot = this->pScene->mRootNode;
 1602|      0|        pScene->mRootNode = pcOldRoot->mChildren[0];
 1603|      0|        pcOldRoot->mChildren[0] = nullptr;
 1604|      0|        delete pcOldRoot;
 1605|      0|        pScene->mRootNode->mParent = nullptr;
 1606|      0|    } else
 1607|      4|        pScene->mRootNode->mName.Set("<mesh_root>");
 1608|       |
 1609|      4|    delete[] avOutList;
 1610|      4|    delete[] aszGroupNameBuffer;
 1611|      4|    AI_DEBUG_INVALIDATE_PTR(avOutList);
 1612|      4|    AI_DEBUG_INVALIDATE_PTR(aszGroupNameBuffer);
 1613|       |
 1614|       |    // build a final material list.
 1615|      4|    CopyMaterials_3DGS_MDL7(sharedData);
 1616|      4|    HandleMaterialReferences_3DGS_MDL7();
 1617|       |
 1618|       |    // generate output bone animations and add all bones to the scenegraph
 1619|      4|    if (sharedData.apcOutBones) {
  ------------------
  |  Branch (1619:9): [True: 0, False: 4]
  ------------------
 1620|       |        // this step adds empty dummy bones to the nodegraph
 1621|       |        // insert another dummy node to avoid name conflicts
 1622|      0|        aiNode *const pc = pScene->mRootNode->mChildren[pScene->mRootNode->mNumChildren - 1] = new aiNode();
 1623|       |
 1624|      0|        pc->mName.Set("<skeleton_root>");
 1625|       |
 1626|       |        // add bones to the nodegraph
 1627|      0|        AddBonesToNodeGraph_3DGS_MDL7((const Assimp::MDL::IntBone_MDL7 **)
 1628|      0|                                              sharedData.apcOutBones,
 1629|      0|                pc, 0xffff);
 1630|       |
 1631|       |        // this steps build a valid output animation
 1632|      0|        BuildOutputAnims_3DGS_MDL7((const Assimp::MDL::IntBone_MDL7 **)
 1633|      0|                                           sharedData.apcOutBones);
 1634|      0|    }
 1635|      4|}
_ZN6Assimp11MDLImporter23CopyMaterials_3DGS_MDL7ERNS_3MDL18IntSharedData_MDL7E:
 1639|      1|void MDLImporter::CopyMaterials_3DGS_MDL7(MDL::IntSharedData_MDL7 &shared) {
 1640|      1|    pScene->mNumMaterials = (unsigned int)shared.pcMats.size();
 1641|      1|    pScene->mMaterials = new aiMaterial *[pScene->mNumMaterials];
 1642|      4|    for (unsigned int i = 0; i < pScene->mNumMaterials; ++i)
  ------------------
  |  Branch (1642:30): [True: 3, False: 1]
  ------------------
 1643|      3|        pScene->mMaterials[i] = shared.pcMats[i];
 1644|      1|}
_ZN6Assimp11MDLImporter34HandleMaterialReferences_3DGS_MDL7Ev:
 1648|      1|void MDLImporter::HandleMaterialReferences_3DGS_MDL7() {
 1649|       |    // search for referrer materials
 1650|      4|    for (unsigned int i = 0; i < pScene->mNumMaterials; ++i) {
  ------------------
  |  Branch (1650:30): [True: 3, False: 1]
  ------------------
 1651|      3|        int iIndex = 0;
 1652|      3|        if (AI_SUCCESS == aiGetMaterialInteger(pScene->mMaterials[i], AI_MDL7_REFERRER_MATERIAL, &iIndex)) {
  ------------------
  |  |  114|      3|#   define AI_MDL7_REFERRER_MATERIAL "&&&referrer&&&",0,0
  ------------------
  |  Branch (1652:13): [True: 0, False: 3]
  ------------------
 1653|      0|            for (unsigned int a = 0; a < pScene->mNumMeshes; ++a) {
  ------------------
  |  Branch (1653:38): [True: 0, False: 0]
  ------------------
 1654|      0|                aiMesh *const pcMesh = pScene->mMeshes[a];
 1655|      0|                if (i == pcMesh->mMaterialIndex) {
  ------------------
  |  Branch (1655:21): [True: 0, False: 0]
  ------------------
 1656|      0|                    pcMesh->mMaterialIndex = iIndex;
 1657|      0|                }
 1658|      0|            }
 1659|       |            // collapse the rest of the array
 1660|      0|            delete pScene->mMaterials[i];
 1661|      0|            for (unsigned int pp = i; pp < pScene->mNumMaterials - 1; ++pp) {
  ------------------
  |  Branch (1661:39): [True: 0, False: 0]
  ------------------
 1662|       |
 1663|      0|                pScene->mMaterials[pp] = pScene->mMaterials[pp + 1];
 1664|      0|                for (unsigned int a = 0; a < pScene->mNumMeshes; ++a) {
  ------------------
  |  Branch (1664:42): [True: 0, False: 0]
  ------------------
 1665|      0|                    aiMesh *const pcMesh = pScene->mMeshes[a];
 1666|      0|                    if (pcMesh->mMaterialIndex > i) --pcMesh->mMaterialIndex;
  ------------------
  |  Branch (1666:25): [True: 0, False: 0]
  ------------------
 1667|      0|                }
 1668|      0|            }
 1669|      0|            --pScene->mNumMaterials;
 1670|      0|        }
 1671|      3|    }
 1672|      1|}
_ZN6Assimp11MDLImporter30GenerateOutputMeshes_3DGS_MDL7ERNS_3MDL17IntGroupData_MDL7ERNS1_22IntSplitGroupData_MDL7E:
 1843|     20|        MDL::IntSplitGroupData_MDL7 &splitGroupData) {
 1844|     20|    const MDL::IntSharedData_MDL7 &shared = splitGroupData.shared;
 1845|       |
 1846|       |    // get a pointer to the header ...
 1847|     20|    const MDL::Header_MDL7 *const pcHeader = (const MDL::Header_MDL7 *)this->mBuffer;
 1848|     20|    const unsigned int iNumOutBones = pcHeader->bones_num;
 1849|       |
 1850|     80|    for (std::vector<aiMaterial *>::size_type i = 0; i < shared.pcMats.size(); ++i) {
  ------------------
  |  Branch (1850:54): [True: 60, False: 20]
  ------------------
 1851|     60|        if (splitGroupData.aiSplit == nullptr) {
  ------------------
  |  Branch (1851:13): [True: 0, False: 60]
  ------------------
 1852|      0|            continue;
 1853|      0|        }
 1854|       |
 1855|     60|        if (!splitGroupData.aiSplit[i]->empty()) {
  ------------------
  |  Branch (1855:13): [True: 20, False: 40]
  ------------------
 1856|       |
 1857|       |            // allocate the output mesh
 1858|     20|            aiMesh *pcMesh = new aiMesh();
 1859|       |
 1860|     20|            pcMesh->mPrimitiveTypes = aiPrimitiveType_TRIANGLE;
 1861|     20|            pcMesh->mMaterialIndex = (unsigned int)i;
 1862|       |
 1863|       |            // allocate output storage
 1864|     20|            pcMesh->mNumFaces = (unsigned int)splitGroupData.aiSplit[i]->size();
 1865|     20|            pcMesh->mFaces = new aiFace[pcMesh->mNumFaces];
 1866|       |
 1867|     20|            pcMesh->mNumVertices = pcMesh->mNumFaces * 3;
 1868|     20|            pcMesh->mVertices = new aiVector3D[pcMesh->mNumVertices];
 1869|     20|            pcMesh->mNormals = new aiVector3D[pcMesh->mNumVertices];
 1870|       |
 1871|     20|            if (!groupData.vTextureCoords1.empty()) {
  ------------------
  |  Branch (1871:17): [True: 0, False: 20]
  ------------------
 1872|      0|                pcMesh->mNumUVComponents[0] = 2;
 1873|      0|                pcMesh->mTextureCoords[0] = new aiVector3D[pcMesh->mNumVertices];
 1874|      0|                if (!groupData.vTextureCoords2.empty()) {
  ------------------
  |  Branch (1874:21): [True: 0, False: 0]
  ------------------
 1875|      0|                    pcMesh->mNumUVComponents[1] = 2;
 1876|      0|                    pcMesh->mTextureCoords[1] = new aiVector3D[pcMesh->mNumVertices];
 1877|      0|                }
 1878|      0|            }
 1879|       |
 1880|       |            // iterate through all faces and build an unique set of vertices
 1881|     20|            unsigned int iCurrent = 0;
 1882|  2.42k|            for (unsigned int iFace = 0; iFace < pcMesh->mNumFaces; ++iFace) {
  ------------------
  |  Branch (1882:42): [True: 2.40k, False: 20]
  ------------------
 1883|  2.40k|                pcMesh->mFaces[iFace].mNumIndices = 3;
 1884|  2.40k|                pcMesh->mFaces[iFace].mIndices = new unsigned int[3];
 1885|       |
 1886|  2.40k|                unsigned int iSrcFace = splitGroupData.aiSplit[i]->operator[](iFace);
 1887|  2.40k|                const MDL::IntFace_MDL7 &oldFace = groupData.pcFaces[iSrcFace];
 1888|       |
 1889|       |                // iterate through all face indices
 1890|  9.60k|                for (unsigned int c = 0; c < 3; ++c) {
  ------------------
  |  Branch (1890:42): [True: 7.20k, False: 2.40k]
  ------------------
 1891|  7.20k|                    const uint32_t iIndex = oldFace.mIndices[c];
 1892|  7.20k|                    pcMesh->mVertices[iCurrent] = groupData.vPositions[iIndex];
 1893|  7.20k|                    pcMesh->mNormals[iCurrent] = groupData.vNormals[iIndex];
 1894|       |
 1895|  7.20k|                    if (!groupData.vTextureCoords1.empty()) {
  ------------------
  |  Branch (1895:25): [True: 0, False: 7.20k]
  ------------------
 1896|       |
 1897|      0|                        pcMesh->mTextureCoords[0][iCurrent] = groupData.vTextureCoords1[iIndex];
 1898|      0|                        if (!groupData.vTextureCoords2.empty()) {
  ------------------
  |  Branch (1898:29): [True: 0, False: 0]
  ------------------
 1899|      0|                            pcMesh->mTextureCoords[1][iCurrent] = groupData.vTextureCoords2[iIndex];
 1900|      0|                        }
 1901|      0|                    }
 1902|  7.20k|                    pcMesh->mFaces[iFace].mIndices[c] = iCurrent++;
 1903|  7.20k|                }
 1904|  2.40k|            }
 1905|       |
 1906|       |            // if we have bones in the mesh we'll need to generate
 1907|       |            // proper vertex weights for them
 1908|     20|            if (!groupData.aiBones.empty()) {
  ------------------
  |  Branch (1908:17): [True: 0, False: 20]
  ------------------
 1909|      0|                std::vector<std::vector<unsigned int>> aaiVWeightList;
 1910|      0|                aaiVWeightList.resize(iNumOutBones);
 1911|       |
 1912|      0|                int iCurrentWeight = 0;
 1913|      0|                for (unsigned int iFace = 0; iFace < pcMesh->mNumFaces; ++iFace) {
  ------------------
  |  Branch (1913:46): [True: 0, False: 0]
  ------------------
 1914|      0|                    unsigned int iSrcFace = splitGroupData.aiSplit[i]->operator[](iFace);
 1915|      0|                    const MDL::IntFace_MDL7 &oldFace = groupData.pcFaces[iSrcFace];
 1916|       |
 1917|       |                    // iterate through all face indices
 1918|      0|                    for (unsigned int c = 0; c < 3; ++c) {
  ------------------
  |  Branch (1918:46): [True: 0, False: 0]
  ------------------
 1919|      0|                        unsigned int iBone = groupData.aiBones[oldFace.mIndices[c]];
 1920|      0|                        if (UINT_MAX != iBone) {
  ------------------
  |  Branch (1920:29): [True: 0, False: 0]
  ------------------
 1921|      0|                            if (iBone >= iNumOutBones) {
  ------------------
  |  Branch (1921:33): [True: 0, False: 0]
  ------------------
 1922|      0|                                ASSIMP_LOG_ERROR("Bone index overflow. "
 1923|      0|                                                 "The bone index of a vertex exceeds the allowed range. ");
 1924|      0|                                iBone = iNumOutBones - 1;
 1925|      0|                            }
 1926|      0|                            aaiVWeightList[iBone].push_back(iCurrentWeight);
 1927|      0|                        }
 1928|      0|                        ++iCurrentWeight;
 1929|      0|                    }
 1930|      0|                }
 1931|       |                // now check which bones are required ...
 1932|      0|                for (std::vector<std::vector<unsigned int>>::const_iterator k = aaiVWeightList.begin(); k != aaiVWeightList.end(); ++k) {
  ------------------
  |  Branch (1932:105): [True: 0, False: 0]
  ------------------
 1933|      0|                    if (!(*k).empty()) {
  ------------------
  |  Branch (1933:25): [True: 0, False: 0]
  ------------------
 1934|      0|                        ++pcMesh->mNumBones;
 1935|      0|                    }
 1936|      0|                }
 1937|      0|                pcMesh->mBones = new aiBone *[pcMesh->mNumBones];
 1938|      0|                iCurrent = 0;
 1939|      0|                for (std::vector<std::vector<unsigned int>>::const_iterator k = aaiVWeightList.begin(); k != aaiVWeightList.end(); ++k, ++iCurrent) {
  ------------------
  |  Branch (1939:105): [True: 0, False: 0]
  ------------------
 1940|      0|                    if ((*k).empty())
  ------------------
  |  Branch (1940:25): [True: 0, False: 0]
  ------------------
 1941|      0|                        continue;
 1942|       |
 1943|       |                    // seems we'll need this node
 1944|      0|                    aiBone *pcBone = pcMesh->mBones[iCurrent] = new aiBone();
 1945|      0|                    pcBone->mName = aiString(shared.apcOutBones[iCurrent]->mName);
 1946|      0|                    pcBone->mOffsetMatrix = shared.apcOutBones[iCurrent]->mOffsetMatrix;
 1947|       |
 1948|       |                    // setup vertex weights
 1949|      0|                    pcBone->mNumWeights = (unsigned int)(*k).size();
 1950|      0|                    pcBone->mWeights = new aiVertexWeight[pcBone->mNumWeights];
 1951|       |
 1952|      0|                    for (unsigned int weight = 0; weight < pcBone->mNumWeights; ++weight) {
  ------------------
  |  Branch (1952:51): [True: 0, False: 0]
  ------------------
 1953|      0|                        pcBone->mWeights[weight].mVertexId = (*k)[weight];
 1954|      0|                        pcBone->mWeights[weight].mWeight = 1.0f;
 1955|      0|                    }
 1956|      0|                }
 1957|      0|            }
 1958|       |            // add the mesh to the list of output meshes
 1959|     20|            splitGroupData.avOutList.push_back(pcMesh);
 1960|     20|        }
 1961|     60|    }
 1962|     20|}
_ZN6Assimp11MDLImporter18InternReadFile_HL1ERKNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEj:
 1993|      4|void MDLImporter::InternReadFile_HL1(const std::string &pFile, const uint32_t iMagicWord) {
 1994|       |    // We can't correctly load an MDL from a MDL "sequence" file.
 1995|      4|    if (iMagicWord == AI_MDL_MAGIC_NUMBER_BE_HL2b || iMagicWord == AI_MDL_MAGIC_NUMBER_LE_HL2b)
  ------------------
  |  |   61|      4|#define AI_MDL_MAGIC_NUMBER_BE_HL2b AI_MAKE_MAGIC("IDSQ")
  ------------------
                  if (iMagicWord == AI_MDL_MAGIC_NUMBER_BE_HL2b || iMagicWord == AI_MDL_MAGIC_NUMBER_LE_HL2b)
  ------------------
  |  |   62|      4|#define AI_MDL_MAGIC_NUMBER_LE_HL2b AI_MAKE_MAGIC("QSDI")
  ------------------
  |  Branch (1995:9): [True: 0, False: 4]
  |  Branch (1995:54): [True: 0, False: 4]
  ------------------
 1996|      0|        throw DeadlyImportError("Impossible to properly load a model from an MDL sequence file.");
 1997|       |
 1998|       |    // Check if the buffer is large enough to hold the header
 1999|      4|    if (iFileSize < sizeof(HalfLife::Header_HL1)) {
  ------------------
  |  Branch (1999:9): [True: 0, False: 4]
  ------------------
 2000|      0|        throw DeadlyImportError("HL1 MDL file is too small to contain header.");
 2001|      0|    }
 2002|       |
 2003|       |    // Read the MDL file.
 2004|      4|    HalfLife::HL1MDLLoader loader(
 2005|      4|            pScene,
 2006|      4|            mIOHandler,
 2007|      4|            mBuffer,
 2008|      4|            iFileSize,
 2009|      4|            pFile,
 2010|      4|            mHL1ImportSettings);
 2011|      4|}
MDLLoader.cpp:_ZZN6Assimp11MDLImporter14InternReadFileERKNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEP7aiScenePNS_8IOSystemEENK3$_0clEv:
  186|     11|    auto DeleteBufferAndCleanup = [&]() {
  187|     11|        if (mBuffer) {
  ------------------
  |  Branch (187:13): [True: 11, False: 0]
  ------------------
  188|     11|            delete[] mBuffer;
  189|     11|            mBuffer = nullptr;
  190|     11|        }
  191|     11|        AI_DEBUG_INVALIDATE_PTR(mIOHandler);
  192|       |        AI_DEBUG_INVALIDATE_PTR(pScene);
  193|     11|    };

_ZN6Assimp11MDLImporterD2Ev:
   87|  1.24k|    ~MDLImporter() override = default;

_ZN6Assimp11MDLImporter21ParseTextureColorDataEPKhjPjP9aiTexture:
  219|      2|        aiTexture *pcNew) {
  220|      2|    const bool do_read = bad_texel != pcNew->pcData;
  221|       |
  222|       |    // allocate storage for the texture image
  223|      2|    if (do_read) {
  ------------------
  |  Branch (223:9): [True: 2, False: 0]
  ------------------
  224|       |        // check for max texture sizes
  225|      2|        if (pcNew->mWidth > MaxTextureSize || pcNew->mHeight > MaxTextureSize) {
  ------------------
  |  Branch (225:13): [True: 2, False: 0]
  |  Branch (225:47): [True: 0, False: 0]
  ------------------
  226|      2|            throw DeadlyImportError("Invalid MDL file. A texture is too big.");
  227|      2|        }
  228|       |
  229|      0|        if(pcNew->mWidth != 0 && pcNew->mHeight > UINT_MAX/pcNew->mWidth) {
  ------------------
  |  Branch (229:12): [True: 0, False: 0]
  |  Branch (229:34): [True: 0, False: 0]
  ------------------
  230|      0|            throw DeadlyImportError("Invalid MDL file. A texture is too big.");
  231|      0|        }
  232|      0|        pcNew->pcData = new aiTexel[pcNew->mWidth * pcNew->mHeight];
  233|      0|    }
  234|       |
  235|       |    // R5G6B5 format (with or without MIPs)
  236|       |    // ****************************************************************
  237|      0|    if (2 == iType || 10 == iType) {
  ------------------
  |  Branch (237:9): [True: 0, False: 0]
  |  Branch (237:23): [True: 0, False: 0]
  ------------------
  238|      0|        VALIDATE_FILE_SIZE(szData + pcNew->mWidth * pcNew->mHeight * 2);
  ------------------
  |  |   63|      0|#   define VALIDATE_FILE_SIZE(msg) SizeCheck(msg,__FILE__,__LINE__)
  ------------------
  239|       |
  240|       |        // copy texture data
  241|      0|        unsigned int i;
  242|      0|        if (do_read) {
  ------------------
  |  Branch (242:13): [True: 0, False: 0]
  ------------------
  243|      0|            for (i = 0; i < pcNew->mWidth * pcNew->mHeight; ++i) {
  ------------------
  |  Branch (243:25): [True: 0, False: 0]
  ------------------
  244|      0|                MDL::RGB565 val = ((MDL::RGB565 *)szData)[i];
  245|      0|                AI_SWAP2(val);
  246|       |
  247|      0|                pcNew->pcData[i].a = 0xFF;
  248|      0|                pcNew->pcData[i].r = (unsigned char)val.b << 3;
  249|      0|                pcNew->pcData[i].g = (unsigned char)val.g << 2;
  250|      0|                pcNew->pcData[i].b = (unsigned char)val.r << 3;
  251|      0|            }
  252|      0|        } else {
  253|      0|            i = pcNew->mWidth * pcNew->mHeight;
  254|      0|        }
  255|      0|        *piSkip = i * 2;
  256|       |
  257|       |        // apply MIP maps
  258|      0|        if (10 == iType) {
  ------------------
  |  Branch (258:13): [True: 0, False: 0]
  ------------------
  259|      0|            *piSkip += ((i >> 2) + (i >> 4) + (i >> 6)) << 1;
  260|      0|            VALIDATE_FILE_SIZE(szData + *piSkip);
  ------------------
  |  |   63|      0|#   define VALIDATE_FILE_SIZE(msg) SizeCheck(msg,__FILE__,__LINE__)
  ------------------
  261|      0|        }
  262|      0|    }
  263|       |    // ARGB4 format (with or without MIPs)
  264|       |    // ****************************************************************
  265|      0|    else if (3 == iType || 11 == iType) {
  ------------------
  |  Branch (265:14): [True: 0, False: 0]
  |  Branch (265:28): [True: 0, False: 0]
  ------------------
  266|      0|        VALIDATE_FILE_SIZE(szData + pcNew->mWidth * pcNew->mHeight * 4);
  ------------------
  |  |   63|      0|#   define VALIDATE_FILE_SIZE(msg) SizeCheck(msg,__FILE__,__LINE__)
  ------------------
  267|       |
  268|       |        // copy texture data
  269|      0|        unsigned int i;
  270|      0|        if (do_read) {
  ------------------
  |  Branch (270:13): [True: 0, False: 0]
  ------------------
  271|      0|            for (i = 0; i < pcNew->mWidth * pcNew->mHeight; ++i) {
  ------------------
  |  Branch (271:25): [True: 0, False: 0]
  ------------------
  272|      0|                MDL::ARGB4 val = ((MDL::ARGB4 *)szData)[i];
  273|      0|                AI_SWAP2(val);
  274|       |
  275|      0|                pcNew->pcData[i].a = (unsigned char)val.a << 4;
  276|      0|                pcNew->pcData[i].r = (unsigned char)val.r << 4;
  277|      0|                pcNew->pcData[i].g = (unsigned char)val.g << 4;
  278|      0|                pcNew->pcData[i].b = (unsigned char)val.b << 4;
  279|      0|            }
  280|      0|        } else
  281|      0|            i = pcNew->mWidth * pcNew->mHeight;
  282|      0|        *piSkip = i * 2;
  283|       |
  284|       |        // apply MIP maps
  285|      0|        if (11 == iType) {
  ------------------
  |  Branch (285:13): [True: 0, False: 0]
  ------------------
  286|      0|            *piSkip += ((i >> 2) + (i >> 4) + (i >> 6)) << 1;
  287|      0|            VALIDATE_FILE_SIZE(szData + *piSkip);
  ------------------
  |  |   63|      0|#   define VALIDATE_FILE_SIZE(msg) SizeCheck(msg,__FILE__,__LINE__)
  ------------------
  288|      0|        }
  289|      0|    }
  290|       |    // RGB8 format (with or without MIPs)
  291|       |    // ****************************************************************
  292|      0|    else if (4 == iType || 12 == iType) {
  ------------------
  |  Branch (292:14): [True: 0, False: 0]
  |  Branch (292:28): [True: 0, False: 0]
  ------------------
  293|      0|        VALIDATE_FILE_SIZE(szData + pcNew->mWidth * pcNew->mHeight * 3);
  ------------------
  |  |   63|      0|#   define VALIDATE_FILE_SIZE(msg) SizeCheck(msg,__FILE__,__LINE__)
  ------------------
  294|       |
  295|       |        // copy texture data
  296|      0|        unsigned int i;
  297|      0|        if (do_read) {
  ------------------
  |  Branch (297:13): [True: 0, False: 0]
  ------------------
  298|      0|            for (i = 0; i < pcNew->mWidth * pcNew->mHeight; ++i) {
  ------------------
  |  Branch (298:25): [True: 0, False: 0]
  ------------------
  299|      0|                const unsigned char *_szData = &szData[i * 3];
  300|       |
  301|      0|                pcNew->pcData[i].a = 0xFF;
  302|      0|                pcNew->pcData[i].b = *_szData++;
  303|      0|                pcNew->pcData[i].g = *_szData++;
  304|      0|                pcNew->pcData[i].r = *_szData;
  305|      0|            }
  306|      0|        } else
  307|      0|            i = pcNew->mWidth * pcNew->mHeight;
  308|       |
  309|       |        // apply MIP maps
  310|      0|        *piSkip = i * 3;
  311|      0|        if (12 == iType) {
  ------------------
  |  Branch (311:13): [True: 0, False: 0]
  ------------------
  312|      0|            *piSkip += ((i >> 2) + (i >> 4) + (i >> 6)) * 3;
  313|      0|            VALIDATE_FILE_SIZE(szData + *piSkip);
  ------------------
  |  |   63|      0|#   define VALIDATE_FILE_SIZE(msg) SizeCheck(msg,__FILE__,__LINE__)
  ------------------
  314|      0|        }
  315|      0|    }
  316|       |    // ARGB8 format (with ir without MIPs)
  317|       |    // ****************************************************************
  318|      0|    else if (5 == iType || 13 == iType) {
  ------------------
  |  Branch (318:14): [True: 0, False: 0]
  |  Branch (318:28): [True: 0, False: 0]
  ------------------
  319|      0|        VALIDATE_FILE_SIZE(szData + pcNew->mWidth * pcNew->mHeight * 4);
  ------------------
  |  |   63|      0|#   define VALIDATE_FILE_SIZE(msg) SizeCheck(msg,__FILE__,__LINE__)
  ------------------
  320|       |
  321|       |        // copy texture data
  322|      0|        unsigned int i;
  323|      0|        if (do_read) {
  ------------------
  |  Branch (323:13): [True: 0, False: 0]
  ------------------
  324|      0|            for (i = 0; i < pcNew->mWidth * pcNew->mHeight; ++i) {
  ------------------
  |  Branch (324:25): [True: 0, False: 0]
  ------------------
  325|      0|                const unsigned char *_szData = &szData[i * 4];
  326|       |
  327|      0|                pcNew->pcData[i].b = *_szData++;
  328|      0|                pcNew->pcData[i].g = *_szData++;
  329|      0|                pcNew->pcData[i].r = *_szData++;
  330|      0|                pcNew->pcData[i].a = *_szData;
  331|      0|            }
  332|      0|        } else {
  333|      0|            i = pcNew->mWidth * pcNew->mHeight;
  334|      0|        }
  335|       |
  336|       |        // apply MIP maps
  337|      0|        *piSkip = i << 2;
  338|      0|        if (13 == iType) {
  ------------------
  |  Branch (338:13): [True: 0, False: 0]
  ------------------
  339|      0|            *piSkip += ((i >> 2) + (i >> 4) + (i >> 6)) << 2;
  340|      0|        }
  341|      0|    }
  342|       |    // palletized 8 bit texture. As for Quake 1
  343|       |    // ****************************************************************
  344|      0|    else if (0 == iType) {
  ------------------
  |  Branch (344:14): [True: 0, False: 0]
  ------------------
  345|      0|        VALIDATE_FILE_SIZE(szData + pcNew->mWidth * pcNew->mHeight);
  ------------------
  |  |   63|      0|#   define VALIDATE_FILE_SIZE(msg) SizeCheck(msg,__FILE__,__LINE__)
  ------------------
  346|       |
  347|       |        // copy texture data
  348|      0|        unsigned int i;
  349|      0|        if (do_read) {
  ------------------
  |  Branch (349:13): [True: 0, False: 0]
  ------------------
  350|       |
  351|      0|            const unsigned char *szColorMap;
  352|      0|            SearchPalette(&szColorMap);
  353|       |
  354|      0|            for (i = 0; i < pcNew->mWidth * pcNew->mHeight; ++i) {
  ------------------
  |  Branch (354:25): [True: 0, False: 0]
  ------------------
  355|      0|                const unsigned char val = szData[i];
  356|      0|                const unsigned char *sz = &szColorMap[val * 3];
  357|       |
  358|      0|                pcNew->pcData[i].a = 0xFF;
  359|      0|                pcNew->pcData[i].r = *sz++;
  360|      0|                pcNew->pcData[i].g = *sz++;
  361|      0|                pcNew->pcData[i].b = *sz;
  362|      0|            }
  363|      0|            this->FreePalette(szColorMap);
  364|       |
  365|      0|        } else
  366|      0|            i = pcNew->mWidth * pcNew->mHeight;
  367|      0|        *piSkip = i;
  368|       |
  369|       |        // FIXME: Also support for MIP maps?
  370|      0|    }
  371|      0|}
_ZN6Assimp11MDLImporter23ParseSkinLump_3DGS_MDL7EPKhPS2_P10aiMaterialjjj:
  456|     14|        unsigned int iHeight) {
  457|     14|    std::unique_ptr<aiTexture> pcNew;
  458|     14|    if (szCurrent == nullptr) {
  ------------------
  |  Branch (458:9): [True: 0, False: 14]
  ------------------
  459|      0|        return;
  460|      0|    }
  461|       |
  462|       |    // get the type of the skin
  463|     14|    unsigned int iMasked = (unsigned int)(iType & 0xF);
  464|       |
  465|     14|    if (0x1 == iMasked) {
  ------------------
  |  Branch (465:9): [True: 0, False: 14]
  ------------------
  466|       |        // ***** REFERENCE TO ANOTHER SKIN INDEX *****
  467|      0|        int referrer = (int)iWidth;
  468|      0|        pcMatOut->AddProperty<int>(&referrer, 1, AI_MDL7_REFERRER_MATERIAL);
  ------------------
  |  |  114|      0|#   define AI_MDL7_REFERRER_MATERIAL "&&&referrer&&&",0,0
  ------------------
  469|     14|    } else if (0x6 == iMasked) {
  ------------------
  |  Branch (469:16): [True: 0, False: 14]
  ------------------
  470|       |        // ***** EMBEDDED DDS FILE *****
  471|      0|        if (1 != iHeight) {
  ------------------
  |  Branch (471:13): [True: 0, False: 0]
  ------------------
  472|      0|            ASSIMP_LOG_WARN("Found a reference to an embedded DDS texture, "
  473|      0|                            "but texture height is not equal to 1, which is not supported by MED");
  474|      0|        }
  475|      0|        if (iWidth == 0) {
  ------------------
  |  Branch (475:13): [True: 0, False: 0]
  ------------------
  476|      0|            ASSIMP_LOG_ERROR("Found a reference to an embedded DDS texture, but texture width is zero, aborting import.");
  477|      0|            return;
  478|      0|        }
  479|       |
  480|      0|        pcNew.reset(new aiTexture);
  481|      0|        pcNew->mHeight = 0;
  482|      0|        pcNew->mWidth = iWidth;
  483|       |
  484|       |        // place a proper format hint
  485|      0|        pcNew->achFormatHint[0] = 'd';
  486|      0|        pcNew->achFormatHint[1] = 'd';
  487|      0|        pcNew->achFormatHint[2] = 's';
  488|      0|        pcNew->achFormatHint[3] = '\0';
  489|       |
  490|      0|        SizeCheck(szCurrent + pcNew->mWidth);
  491|       |
  492|      0|        pcNew->pcData = (aiTexel *)new unsigned char[pcNew->mWidth];
  493|      0|        memcpy(pcNew->pcData, szCurrent, pcNew->mWidth);
  494|      0|        szCurrent += iWidth;
  495|     14|    } else if (0x7 == iMasked) {
  ------------------
  |  Branch (495:16): [True: 0, False: 14]
  ------------------
  496|       |        // ***** REFERENCE TO EXTERNAL FILE *****
  497|      0|        if (1 != iHeight) {
  ------------------
  |  Branch (497:13): [True: 0, False: 0]
  ------------------
  498|      0|            ASSIMP_LOG_WARN("Found a reference to an external texture, "
  499|      0|                            "but texture height is not equal to 1, which is not supported by MED");
  500|      0|        }
  501|       |
  502|      0|        aiString szFile;
  503|      0|        const size_t iLen = strlen((const char *)szCurrent);
  504|      0|        size_t iLen2 = iLen > (AI_MAXLEN - 1) ? (AI_MAXLEN - 1) : iLen;
  ------------------
  |  Branch (504:24): [True: 0, False: 0]
  ------------------
  505|      0|        memcpy(szFile.data, (const char *)szCurrent, iLen2);
  506|      0|        szFile.data[iLen2] = '\0';
  507|      0|        szFile.length = static_cast<ai_uint32>(iLen2);
  508|       |
  509|      0|        szCurrent += iLen2 + 1;
  510|       |
  511|       |        // place this as diffuse texture
  512|      0|        pcMatOut->AddProperty(&szFile, AI_MATKEY_TEXTURE_DIFFUSE(0));
  513|     14|    } else if (iMasked || !iType || (iType && iWidth && iHeight)) {
  ------------------
  |  Branch (513:16): [True: 1, False: 13]
  |  Branch (513:27): [True: 1, False: 12]
  |  Branch (513:38): [True: 12, False: 0]
  |  Branch (513:47): [True: 0, False: 12]
  |  Branch (513:57): [True: 0, False: 0]
  ------------------
  514|      2|        pcNew.reset(new aiTexture());
  515|      2|        if (!iHeight || !iWidth) {
  ------------------
  |  Branch (515:13): [True: 0, False: 2]
  |  Branch (515:25): [True: 0, False: 2]
  ------------------
  516|      0|            ASSIMP_LOG_WARN("Found embedded texture, but its width "
  517|      0|                            "an height are both 0. Is this a joke?");
  518|       |
  519|       |            // generate an empty chess pattern
  520|      0|            pcNew->mWidth = pcNew->mHeight = 8;
  521|      0|            pcNew->pcData = new aiTexel[64];
  522|      0|            for (unsigned int x = 0; x < 8; ++x) {
  ------------------
  |  Branch (522:38): [True: 0, False: 0]
  ------------------
  523|      0|                for (unsigned int y = 0; y < 8; ++y) {
  ------------------
  |  Branch (523:42): [True: 0, False: 0]
  ------------------
  524|      0|                    const bool bSet = ((0 == x % 2 && 0 != y % 2) ||
  ------------------
  |  Branch (524:41): [True: 0, False: 0]
  |  Branch (524:55): [True: 0, False: 0]
  ------------------
  525|      0|                                       (0 != x % 2 && 0 == y % 2));
  ------------------
  |  Branch (525:41): [True: 0, False: 0]
  |  Branch (525:55): [True: 0, False: 0]
  ------------------
  526|       |
  527|      0|                    aiTexel *pc = &pcNew->pcData[y * 8 + x];
  528|      0|                    pc->r = pc->b = pc->g = (bSet ? 0xFF : 0);
  ------------------
  |  Branch (528:46): [True: 0, False: 0]
  ------------------
  529|      0|                    pc->a = 0xFF;
  530|      0|                }
  531|      0|            }
  532|      2|        } else {
  533|       |            // it is a standard color texture. Fill in width and height
  534|       |            // and call the same function we used for loading MDL5 files
  535|       |
  536|      2|            pcNew->mWidth = iWidth;
  537|      2|            pcNew->mHeight = iHeight;
  538|       |
  539|      2|            unsigned int iSkip = 0;
  540|      2|            ParseTextureColorData(szCurrent, iMasked, &iSkip, pcNew.get());
  541|       |
  542|       |            // skip length of texture data
  543|      2|            szCurrent += iSkip;
  544|      2|        }
  545|      2|    }
  546|       |
  547|       |    // sometimes there are MDL7 files which have a monochrome
  548|       |    // texture instead of material colors ... possible they have
  549|       |    // been converted to MDL7 from other formats, such as MDL5
  550|     14|    aiColor4D clrTexture;
  551|     14|    if (pcNew)
  ------------------
  |  Branch (551:9): [True: 0, False: 14]
  ------------------
  552|      0|        clrTexture = ReplaceTextureWithColor(pcNew.get());
  553|     14|    else
  554|     14|        clrTexture.r = get_qnan();
  555|       |
  556|       |    // check whether a material definition is contained in the skin
  557|     14|    if (iType & AI_MDL7_SKINTYPE_MATERIAL) {
  ------------------
  |  |  296|     14|#define AI_MDL7_SKINTYPE_MATERIAL               0x10
  ------------------
  |  Branch (557:9): [True: 12, False: 2]
  ------------------
  558|     12|        BE_NCONST MDL::Material_MDL7 *pcMatIn = (BE_NCONST MDL::Material_MDL7 *)szCurrent;
  559|     12|        szCurrent = (unsigned char *)(pcMatIn + 1);
  560|     12|        VALIDATE_FILE_SIZE(szCurrent);
  ------------------
  |  |   63|     12|#   define VALIDATE_FILE_SIZE(msg) SizeCheck(msg,__FILE__,__LINE__)
  ------------------
  561|       |
  562|     12|        aiColor3D clrTemp;
  563|       |
  564|     12|#define COLOR_MULTIPLY_RGB()         \
  565|     12|    if (is_not_qnan(clrTexture.r)) { \
  566|     12|        clrTemp.r *= clrTexture.r;   \
  567|     12|        clrTemp.g *= clrTexture.g;   \
  568|     12|        clrTemp.b *= clrTexture.b;   \
  569|     12|    }
  570|       |
  571|       |        // read diffuse color
  572|     12|        clrTemp.r = pcMatIn->Diffuse.r;
  573|     12|        AI_SWAP4(clrTemp.r);
  574|     12|        clrTemp.g = pcMatIn->Diffuse.g;
  575|     12|        AI_SWAP4(clrTemp.g);
  576|     12|        clrTemp.b = pcMatIn->Diffuse.b;
  577|     12|        AI_SWAP4(clrTemp.b);
  578|     12|        COLOR_MULTIPLY_RGB();
  ------------------
  |  |  565|     12|    if (is_not_qnan(clrTexture.r)) { \
  |  |  ------------------
  |  |  |  Branch (565:9): [True: 0, False: 12]
  |  |  ------------------
  |  |  566|      0|        clrTemp.r *= clrTexture.r;   \
  |  |  567|      0|        clrTemp.g *= clrTexture.g;   \
  |  |  568|      0|        clrTemp.b *= clrTexture.b;   \
  |  |  569|      0|    }
  ------------------
  579|     12|        pcMatOut->AddProperty<aiColor3D>(&clrTemp, 1, AI_MATKEY_COLOR_DIFFUSE);
  580|       |
  581|       |        // read specular color
  582|     12|        clrTemp.r = pcMatIn->Specular.r;
  583|     12|        AI_SWAP4(clrTemp.r);
  584|     12|        clrTemp.g = pcMatIn->Specular.g;
  585|     12|        AI_SWAP4(clrTemp.g);
  586|     12|        clrTemp.b = pcMatIn->Specular.b;
  587|     12|        AI_SWAP4(clrTemp.b);
  588|     12|        COLOR_MULTIPLY_RGB();
  ------------------
  |  |  565|     12|    if (is_not_qnan(clrTexture.r)) { \
  |  |  ------------------
  |  |  |  Branch (565:9): [True: 0, False: 12]
  |  |  ------------------
  |  |  566|      0|        clrTemp.r *= clrTexture.r;   \
  |  |  567|      0|        clrTemp.g *= clrTexture.g;   \
  |  |  568|      0|        clrTemp.b *= clrTexture.b;   \
  |  |  569|      0|    }
  ------------------
  589|     12|        pcMatOut->AddProperty<aiColor3D>(&clrTemp, 1, AI_MATKEY_COLOR_SPECULAR);
  590|       |
  591|       |        // read ambient color
  592|     12|        clrTemp.r = pcMatIn->Ambient.r;
  593|     12|        AI_SWAP4(clrTemp.r);
  594|     12|        clrTemp.g = pcMatIn->Ambient.g;
  595|     12|        AI_SWAP4(clrTemp.g);
  596|     12|        clrTemp.b = pcMatIn->Ambient.b;
  597|     12|        AI_SWAP4(clrTemp.b);
  598|     12|        COLOR_MULTIPLY_RGB();
  ------------------
  |  |  565|     12|    if (is_not_qnan(clrTexture.r)) { \
  |  |  ------------------
  |  |  |  Branch (565:9): [True: 0, False: 12]
  |  |  ------------------
  |  |  566|      0|        clrTemp.r *= clrTexture.r;   \
  |  |  567|      0|        clrTemp.g *= clrTexture.g;   \
  |  |  568|      0|        clrTemp.b *= clrTexture.b;   \
  |  |  569|      0|    }
  ------------------
  599|     12|        pcMatOut->AddProperty<aiColor3D>(&clrTemp, 1, AI_MATKEY_COLOR_AMBIENT);
  600|       |
  601|       |        // read emissive color
  602|     12|        clrTemp.r = pcMatIn->Emissive.r;
  603|     12|        AI_SWAP4(clrTemp.r);
  604|     12|        clrTemp.g = pcMatIn->Emissive.g;
  605|     12|        AI_SWAP4(clrTemp.g);
  606|     12|        clrTemp.b = pcMatIn->Emissive.b;
  607|     12|        AI_SWAP4(clrTemp.b);
  608|     12|        pcMatOut->AddProperty<aiColor3D>(&clrTemp, 1, AI_MATKEY_COLOR_EMISSIVE);
  609|       |
  610|     12|#undef COLOR_MULITPLY_RGB
  611|       |
  612|       |        // FIX: Take the opacity from the ambient color.
  613|       |        // The doc say something else, but it is fact that MED exports the
  614|       |        // opacity like this .... oh well.
  615|     12|        clrTemp.r = pcMatIn->Ambient.a;
  616|     12|        AI_SWAP4(clrTemp.r);
  617|     12|        if (is_not_qnan(clrTexture.r)) {
  ------------------
  |  Branch (617:13): [True: 0, False: 12]
  ------------------
  618|      0|            clrTemp.r *= clrTexture.a;
  619|      0|        }
  620|     12|        pcMatOut->AddProperty<float>(&clrTemp.r, 1, AI_MATKEY_OPACITY);
  621|       |
  622|       |        // read phong power
  623|     12|        int iShadingMode = (int)aiShadingMode_Gouraud;
  624|     12|        AI_SWAP4(pcMatIn->Power);
  625|     12|        if (0.0f != pcMatIn->Power) {
  ------------------
  |  Branch (625:13): [True: 12, False: 0]
  ------------------
  626|     12|            iShadingMode = (int)aiShadingMode_Phong;
  627|       |            // pcMatIn is packed, we can't form pointers to its members
  628|     12|            float power = pcMatIn->Power;
  629|     12|            pcMatOut->AddProperty<float>(&power, 1, AI_MATKEY_SHININESS);
  630|     12|        }
  631|     12|        pcMatOut->AddProperty<int>(&iShadingMode, 1, AI_MATKEY_SHADING_MODEL);
  632|     12|    } else if (is_not_qnan(clrTexture.r)) {
  ------------------
  |  Branch (632:16): [True: 0, False: 2]
  ------------------
  633|      0|        pcMatOut->AddProperty<aiColor4D>(&clrTexture, 1, AI_MATKEY_COLOR_DIFFUSE);
  634|      0|        pcMatOut->AddProperty<aiColor4D>(&clrTexture, 1, AI_MATKEY_COLOR_SPECULAR);
  635|      0|    }
  636|       |    // if the texture could be replaced by a single material color
  637|       |    // we don't need the texture anymore
  638|     14|    if (is_not_qnan(clrTexture.r)) {
  ------------------
  |  Branch (638:9): [True: 0, False: 14]
  ------------------
  639|      0|        pcNew.reset();
  640|      0|    }
  641|       |
  642|       |    // If an ASCII effect description (HLSL?) is contained in the file,
  643|       |    // we can simply ignore it ...
  644|     14|    if (iType & AI_MDL7_SKINTYPE_MATERIAL_ASCDEF) {
  ------------------
  |  |  297|     14|#define AI_MDL7_SKINTYPE_MATERIAL_ASCDEF        0x20
  ------------------
  |  Branch (644:9): [True: 0, False: 14]
  ------------------
  645|      0|        VALIDATE_FILE_SIZE(szCurrent);
  ------------------
  |  |   63|      0|#   define VALIDATE_FILE_SIZE(msg) SizeCheck(msg,__FILE__,__LINE__)
  ------------------
  646|      0|        int32_t iMe = *((int32_t *)szCurrent);
  647|      0|        AI_SWAP4(iMe);
  648|      0|        szCurrent += sizeof(char) * iMe + sizeof(int32_t);
  649|      0|        VALIDATE_FILE_SIZE(szCurrent);
  ------------------
  |  |   63|      0|#   define VALIDATE_FILE_SIZE(msg) SizeCheck(msg,__FILE__,__LINE__)
  ------------------
  650|      0|    }
  651|       |
  652|       |    // If an embedded texture has been loaded setup the corresponding
  653|       |    // data structures in the aiScene instance
  654|     14|    if (pcNew && pScene->mNumTextures <= 999) {
  ------------------
  |  Branch (654:9): [True: 0, False: 14]
  |  Branch (654:18): [True: 0, False: 0]
  ------------------
  655|       |        // place this as diffuse texture
  656|      0|        char current[5];
  657|      0|        ai_snprintf(current, 5, "*%i", this->pScene->mNumTextures);
  658|       |
  659|      0|        aiString szFile;
  660|      0|        const size_t iLen = strlen((const char *)current);
  661|      0|        ::memcpy(szFile.data, (const char *)current, iLen + 1);
  662|      0|        szFile.length = (ai_uint32)iLen;
  663|       |
  664|      0|        pcMatOut->AddProperty(&szFile, AI_MATKEY_TEXTURE_DIFFUSE(0));
  665|       |
  666|       |        // store the texture
  667|      0|        if (!pScene->mNumTextures) {
  ------------------
  |  Branch (667:13): [True: 0, False: 0]
  ------------------
  668|      0|            pScene->mNumTextures = 1;
  669|      0|            pScene->mTextures = new aiTexture *[1];
  670|      0|            pScene->mTextures[0] = pcNew.release();
  671|      0|        } else {
  672|      0|            aiTexture **pc = pScene->mTextures;
  673|      0|            pScene->mTextures = new aiTexture *[pScene->mNumTextures + 1];
  674|      0|            for (unsigned int i = 0; i < pScene->mNumTextures; ++i) {
  ------------------
  |  Branch (674:38): [True: 0, False: 0]
  ------------------
  675|      0|                pScene->mTextures[i] = pc[i];
  676|      0|            }
  677|       |
  678|      0|            pScene->mTextures[pScene->mNumTextures] = pcNew.release();
  679|      0|            pScene->mNumTextures++;
  680|      0|            delete[] pc;
  681|      0|        }
  682|      0|    }
  683|     14|    VALIDATE_FILE_SIZE(szCurrent);
  ------------------
  |  |   63|     14|#   define VALIDATE_FILE_SIZE(msg) SizeCheck(msg,__FILE__,__LINE__)
  ------------------
  684|     14|    *szCurrentOut = szCurrent;
  685|     14|}
_ZN6Assimp11MDLImporter23ParseSkinLump_3DGS_MDL7EPKhPS2_RNSt3__16vectorIP10aiMaterialNS4_9allocatorIS7_EEEE:
  754|     14|        std::vector<aiMaterial *> &pcMats) {
  755|     14|    ai_assert(nullptr != szCurrent);
  756|     14|    ai_assert(nullptr != szCurrentOut);
  757|       |
  758|     14|    *szCurrentOut = szCurrent;
  759|     14|    BE_NCONST MDL::Skin_MDL7 *pcSkin = (BE_NCONST MDL::Skin_MDL7 *)szCurrent;
  760|     14|    AI_SWAP4(pcSkin->width);
  761|     14|    AI_SWAP4(pcSkin->height);
  762|     14|    szCurrent += 12;
  763|       |
  764|       |    // allocate an output material
  765|     14|    aiMaterial *pcMatOut = new aiMaterial();
  766|     14|    pcMats.push_back(pcMatOut);
  767|       |
  768|       |    // skip length of file name
  769|     14|    szCurrent += AI_MDL7_MAX_TEXNAMESIZE;
  ------------------
  |  |  406|     14|#   define AI_MDL7_MAX_TEXNAMESIZE      0x10
  ------------------
  770|       |
  771|     14|    ParseSkinLump_3DGS_MDL7(szCurrent, szCurrentOut, pcMatOut,
  772|     14|            pcSkin->typ, pcSkin->width, pcSkin->height);
  773|       |
  774|       |    // place the name of the skin in the material
  775|     14|    if (pcSkin->texture_name[0]) {
  ------------------
  |  Branch (775:9): [True: 12, False: 2]
  ------------------
  776|       |        // the 0 termination could be there or not - we can't know
  777|     12|        aiString szFile;
  778|     12|        ::memcpy(szFile.data, pcSkin->texture_name, sizeof(pcSkin->texture_name));
  779|     12|        szFile.data[sizeof(pcSkin->texture_name)] = '\0';
  780|     12|        szFile.length = (ai_uint32)::strlen(szFile.data);
  781|       |
  782|       |        pcMatOut->AddProperty(&szFile, AI_MATKEY_NAME);
  783|     12|    }
  784|     14|}

_ZN6Assimp11MMDImporterC2Ev:
   78|    624|        m_Buffer(),
   79|    624|        m_strAbsPath() {
   80|    624|    DefaultIOSystem io;
   81|    624|    m_strAbsPath = io.getOsSeparator();
   82|    624|}
_ZNK6Assimp11MMDImporter7CanReadERKNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEPNS_8IOSystemEb:
   87|     43|        bool /*checkSig*/) const {
   88|     43|    static const char *tokens[] = { "PMX " };
   89|       |    return SearchFileHeaderForToken(pIOHandler, pFile, tokens, AI_COUNT_OF(tokens));
   90|     43|}
_ZNK6Assimp11MMDImporter7GetInfoEv:
   93|    634|const aiImporterDesc *MMDImporter::GetInfo() const {
   94|    634|    return &desc;
   95|    634|}

_ZN6Assimp11MMDImporterD2Ev:
   62|    624|    ~MMDImporter() override = default;

_ZN6Assimp12MS3DImporterC2Ev:
   81|    624|{}
_ZNK6Assimp12MS3DImporter7CanReadERKNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEPNS_8IOSystemEb:
   86|    126|{
   87|    126|    static const char* tokens[] = { "MS3D000000" };
   88|       |    return SearchFileHeaderForToken(pIOHandler,pFile,tokens,AI_COUNT_OF(tokens));
   89|    126|}
_ZNK6Assimp12MS3DImporter7GetInfoEv:
   93|    661|{
   94|    661|    return &desc;
   95|    661|}
_Z9ReadColorRN6Assimp12StreamReaderILb0ELb0EEER9aiColor4tIfE:
   99|  1.13k|{
  100|       |    // aiColor4D is packed on gcc, implicit binding to float& fails therefore.
  101|  1.13k|    stream >> (float&)ambient.r >> (float&)ambient.g >> (float&)ambient.b >> (float&)ambient.a;
  102|  1.13k|}
_Z10ReadVectorRN6Assimp12StreamReaderILb0ELb0EEER10aiVector3tIfE:
  106|  41.7k|{
  107|       |    // See note in ReadColor()
  108|  41.7k|    stream >> (float&)pos.x >> (float&)pos.y >> (float&)pos.z;
  109|  41.7k|}
_ZN6Assimp12MS3DImporter14InternReadFileERKNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEP7aiScenePNS_8IOSystemE:
  195|     27|{
  196|       |
  197|     27|    auto file = pIOHandler->Open(pFile, "rb");
  198|     27|    if (!file)
  ------------------
  |  Branch (198:9): [True: 0, False: 27]
  ------------------
  199|      0|        throw DeadlyImportError("MS3D: Could not open ", pFile);
  200|       |
  201|     27|    StreamReaderLE stream(file);
  202|       |
  203|       |    // CanRead() should have done this already
  204|     27|    char head[10];
  205|     27|    int32_t version;
  206|       |
  207|     27|    mScene = pScene;
  208|       |
  209|       |
  210|       |    // 1 ------------ read into temporary data structures mirroring the original file
  211|       |
  212|     27|    stream.CopyAndAdvance(head,10);
  213|     27|    stream >> version;
  214|     27|    if (strncmp(head,"MS3D000000",10)) {
  ------------------
  |  Branch (214:9): [True: 0, False: 27]
  ------------------
  215|      0|        throw DeadlyImportError("Not a MS3D file, magic string MS3D000000 not found: ", pFile);
  216|      0|    }
  217|       |
  218|     27|    if (version != 4) {
  ------------------
  |  Branch (218:9): [True: 0, False: 27]
  ------------------
  219|      0|        throw DeadlyImportError("MS3D: Unsupported file format version, 4 was expected");
  220|      0|    }
  221|       |
  222|     27|    uint16_t verts;
  223|     27|    stream >> verts;
  224|       |
  225|     27|    std::vector<TempVertex> vertices(verts);
  226|  8.56k|    for (unsigned int i = 0; i < verts; ++i) {
  ------------------
  |  Branch (226:30): [True: 8.53k, False: 27]
  ------------------
  227|  8.53k|        TempVertex& v = vertices[i];
  228|       |
  229|  8.53k|        stream.IncPtr(1);
  230|  8.53k|        ReadVector(stream,v.pos);
  231|  8.53k|        v.bone_id[0] = stream.GetI1();
  232|  8.53k|        v.ref_cnt = stream.GetI1();
  233|       |
  234|  8.53k|        v.bone_id[1] = v.bone_id[2] = v.bone_id[3] = UINT_MAX;
  235|  8.53k|        v.weights[1] = v.weights[2] = v.weights[3] = 0.f;
  236|  8.53k|        v.weights[0] = 1.f;
  237|  8.53k|    }
  238|       |
  239|     27|    uint16_t tris;
  240|     27|    stream >> tris;
  241|       |
  242|     27|    std::vector<TempTriangle> triangles(tris);
  243|  10.9k|    for (unsigned int i = 0;i < tris; ++i) {
  ------------------
  |  Branch (243:29): [True: 10.9k, False: 27]
  ------------------
  244|  10.9k|        TempTriangle& t = triangles[i];
  245|       |
  246|  10.9k|        stream.IncPtr(2);
  247|  43.8k|        for (unsigned int j = 0; j < 3; ++j) {
  ------------------
  |  Branch (247:34): [True: 32.9k, False: 10.9k]
  ------------------
  248|  32.9k|            t.indices[j] = stream.GetI2();
  249|  32.9k|        }
  250|       |
  251|  43.8k|        for (unsigned int j = 0; j < 3; ++j) {
  ------------------
  |  Branch (251:34): [True: 32.9k, False: 10.9k]
  ------------------
  252|  32.9k|            ReadVector(stream,t.normals[j]);
  253|  32.9k|        }
  254|       |
  255|  43.8k|        for (unsigned int j = 0; j < 3; ++j) {
  ------------------
  |  Branch (255:34): [True: 32.9k, False: 10.9k]
  ------------------
  256|  32.9k|            stream >> (float&)(t.uv[j].x); // see note in ReadColor()
  257|  32.9k|        }
  258|  43.8k|        for (unsigned int j = 0; j < 3; ++j) {
  ------------------
  |  Branch (258:34): [True: 32.9k, False: 10.9k]
  ------------------
  259|  32.9k|            stream >> (float&)(t.uv[j].y);
  260|  32.9k|        }
  261|       |
  262|  10.9k|        t.sg    = stream.GetI1();
  263|  10.9k|        t.group = stream.GetI1();
  264|  10.9k|    }
  265|       |
  266|     27|    uint16_t grp;
  267|     27|    stream >> grp;
  268|       |
  269|     27|    bool need_default = false;
  270|     27|    std::vector<TempGroup> groups(grp);
  271|     74|    for (unsigned int i = 0;i < grp; ++i) {
  ------------------
  |  Branch (271:29): [True: 47, False: 27]
  ------------------
  272|     47|        TempGroup& t = groups[i];
  273|       |
  274|     47|        stream.IncPtr(1);
  275|     47|        stream.CopyAndAdvance(t.name,32);
  276|       |
  277|     47|        t.name[32] = '\0';
  278|     47|        uint16_t num;
  279|     47|        stream >> num;
  280|       |
  281|     47|        t.triangles.resize(num);
  282|  29.6k|        for (unsigned int j = 0; j < num; ++j) {
  ------------------
  |  Branch (282:34): [True: 29.5k, False: 47]
  ------------------
  283|  29.5k|            t.triangles[j] = stream.GetI2();
  284|  29.5k|        }
  285|     47|        t.mat = stream.GetI1();
  286|     47|        if (t.mat == UINT_MAX) {
  ------------------
  |  Branch (286:13): [True: 15, False: 32]
  ------------------
  287|     15|            need_default = true;
  288|     15|        }
  289|     47|    }
  290|       |
  291|     27|    uint16_t mat;
  292|     27|    stream >> mat;
  293|       |
  294|     27|    std::vector<TempMaterial> materials(mat);
  295|    311|    for (unsigned int j = 0;j < mat; ++j) {
  ------------------
  |  Branch (295:29): [True: 284, False: 27]
  ------------------
  296|    284|        TempMaterial& t = materials[j];
  297|       |
  298|    284|        stream.CopyAndAdvance(t.name,32);
  299|    284|        t.name[32] = '\0';
  300|       |
  301|    284|        ReadColor(stream,t.ambient);
  302|    284|        ReadColor(stream,t.diffuse);
  303|    284|        ReadColor(stream,t.specular);
  304|    284|        ReadColor(stream,t.emissive);
  305|    284|        stream >> t.shininess  >> t.transparency;
  306|       |
  307|    284|        stream.IncPtr(1);
  308|       |
  309|    284|        stream.CopyAndAdvance(t.texture,128);
  310|    284|        t.texture[128] = '\0';
  311|       |
  312|    284|        stream.CopyAndAdvance(t.alphamap,128);
  313|    284|        t.alphamap[128] = '\0';
  314|    284|    }
  315|       |
  316|     27|    float animfps, currenttime;
  317|     27|    uint32_t totalframes;
  318|     27|    stream >> animfps >> currenttime >> totalframes;
  319|       |
  320|     27|    uint16_t joint;
  321|     27|    stream >> joint;
  322|       |
  323|     27|    std::vector<TempJoint> joints(joint);
  324|     34|    for(unsigned int ii = 0; ii < joint; ++ii) {
  ------------------
  |  Branch (324:30): [True: 7, False: 27]
  ------------------
  325|      7|        TempJoint& j = joints[ii];
  326|       |
  327|      7|        stream.IncPtr(1);
  328|      7|        stream.CopyAndAdvance(j.name,32);
  329|      7|        j.name[32] = '\0';
  330|       |
  331|      7|        stream.CopyAndAdvance(j.parentName,32);
  332|      7|        j.parentName[32] = '\0';
  333|       |
  334|      7|        ReadVector(stream,j.rotation);
  335|      7|        ReadVector(stream,j.position);
  336|       |
  337|      7|        j.rotFrames.resize(stream.GetI2());
  338|      7|        j.posFrames.resize(stream.GetI2());
  339|       |
  340|    251|        for(unsigned int a = 0; a < j.rotFrames.size(); ++a) {
  ------------------
  |  Branch (340:33): [True: 244, False: 7]
  ------------------
  341|    244|            TempKeyFrame& kf = j.rotFrames[a];
  342|    244|            stream >> kf.time;
  343|    244|            ReadVector(stream,kf.value);
  344|    244|        }
  345|     76|        for(unsigned int a = 0; a < j.posFrames.size(); ++a) {
  ------------------
  |  Branch (345:33): [True: 69, False: 7]
  ------------------
  346|     69|            TempKeyFrame& kf = j.posFrames[a];
  347|     69|            stream >> kf.time;
  348|     69|            ReadVector(stream,kf.value);
  349|     69|        }
  350|      7|    }
  351|       |
  352|     27|    if(stream.GetRemainingSize() > 4) {
  ------------------
  |  Branch (352:8): [True: 7, False: 20]
  ------------------
  353|      7|        uint32_t subversion;
  354|      7|        stream >> subversion;
  355|      7|        if (subversion == 1) {
  ------------------
  |  Branch (355:13): [True: 7, False: 0]
  ------------------
  356|      7|            ReadComments<TempGroup>(stream,groups);
  357|      7|            ReadComments<TempMaterial>(stream,materials);
  358|      7|            ReadComments<TempJoint>(stream,joints);
  359|       |
  360|       |            // model comment - print it for we have such a nice log.
  361|      7|            if (stream.GetI4()) {
  ------------------
  |  Branch (361:17): [True: 1, False: 6]
  ------------------
  362|      1|                const size_t len = static_cast<size_t>(stream.GetI4());
  363|      1|                if (len > stream.GetRemainingSize()) {
  ------------------
  |  Branch (363:21): [True: 1, False: 0]
  ------------------
  364|      1|                    throw DeadlyImportError("MS3D: Model comment is too long");
  365|      1|                }
  366|       |
  367|      0|                const std::string& s = std::string(reinterpret_cast<char*>(stream.GetPtr()),len);
  368|      0|                ASSIMP_LOG_DEBUG("MS3D: Model comment: ", s);
  369|      0|            }
  370|       |
  371|      6|            if(stream.GetRemainingSize() > 4 && inrange((stream >> subversion,subversion),1u,3u)) {
  ------------------
  |  Branch (371:16): [True: 6, False: 0]
  |  Branch (371:16): [True: 0, False: 6]
  |  Branch (371:49): [True: 0, False: 6]
  ------------------
  372|      0|                for(unsigned int i = 0; i < verts; ++i) {
  ------------------
  |  Branch (372:41): [True: 0, False: 0]
  ------------------
  373|      0|                    TempVertex& v = vertices[i];
  374|      0|                    v.weights[3]=1.f;
  375|      0|                    for(unsigned int n = 0; n < 3; v.weights[3]-=v.weights[n++]) {
  ------------------
  |  Branch (375:45): [True: 0, False: 0]
  ------------------
  376|      0|                        v.bone_id[n+1] = stream.GetI1();
  377|      0|                        v.weights[n] = static_cast<float>(static_cast<unsigned int>(stream.GetI1()))/255.f;
  378|      0|                    }
  379|      0|                    stream.IncPtr((subversion-1)<<2u);
  380|      0|                }
  381|       |
  382|       |                // even further extra data is not of interest for us, at least now now.
  383|      0|            }
  384|      6|        }
  385|      7|    }
  386|       |
  387|       |    // 2 ------------ convert to proper aiXX data structures -----------------------------------
  388|       |
  389|     26|    if (need_default && materials.size()) {
  ------------------
  |  Branch (389:9): [True: 5, False: 21]
  |  Branch (389:25): [True: 0, False: 5]
  ------------------
  390|      0|        ASSIMP_LOG_WARN("MS3D: Found group with no material assigned, spawning default material");
  391|       |          // if one of the groups has no material assigned, but there are other
  392|       |        // groups with materials, a default material needs to be added (
  393|       |        // scenepreprocessor adds a default material only if nummat==0).
  394|      0|        materials.emplace_back();
  395|      0|        TempMaterial& m = materials.back();
  396|      0|        constexpr char DefaultMat[18] = "<MS3D_DefaultMat>";
  397|      0|        strncpy(m.name, DefaultMat, sizeof(m.name));
  398|      0|        m.name[18]='\0';
  399|      0|        m.diffuse = aiColor4D(0.6f,0.6f,0.6f,1.0);
  400|      0|        m.transparency = 1.f;
  401|      0|        m.shininess = 0.f;
  402|       |
  403|       |        // this is because these TempXXX struct's have no c'tors.
  404|      0|        m.texture[0] = m.alphamap[0] = '\0';
  405|       |
  406|      0|        for (unsigned int i = 0; i < groups.size(); ++i) {
  ------------------
  |  Branch (406:34): [True: 0, False: 0]
  ------------------
  407|      0|            TempGroup& g = groups[i];
  408|      0|            if (g.mat == UINT_MAX) {
  ------------------
  |  Branch (408:17): [True: 0, False: 0]
  ------------------
  409|      0|                g.mat = static_cast<unsigned int>(materials.size()-1);
  410|      0|            }
  411|      0|        }
  412|      0|    }
  413|       |
  414|       |    // convert materials to our generic key-value dict-alike
  415|     26|    if (materials.size()) {
  ------------------
  |  Branch (415:9): [True: 2, False: 24]
  ------------------
  416|      2|        pScene->mMaterials = new aiMaterial*[materials.size()];
  417|      5|        for (size_t i = 0; i < materials.size(); ++i) {
  ------------------
  |  Branch (417:28): [True: 3, False: 2]
  ------------------
  418|       |
  419|      3|            aiMaterial* mo = new aiMaterial();
  420|      3|            pScene->mMaterials[pScene->mNumMaterials++] = mo;
  421|       |
  422|      3|            const TempMaterial& mi = materials[i];
  423|       |
  424|      3|            aiString tmp;
  425|      3|            if (0[mi.alphamap]) {
  ------------------
  |  Branch (425:17): [True: 0, False: 3]
  ------------------
  426|      0|                tmp = aiString(mi.alphamap);
  427|      0|                mo->AddProperty(&tmp,AI_MATKEY_TEXTURE_OPACITY(0));
  428|      0|            }
  429|      3|            if (0[mi.texture]) {
  ------------------
  |  Branch (429:17): [True: 1, False: 2]
  ------------------
  430|      1|                tmp = aiString(mi.texture);
  431|      1|                mo->AddProperty(&tmp,AI_MATKEY_TEXTURE_DIFFUSE(0));
  432|      1|            }
  433|      3|            if (0[mi.name]) {
  ------------------
  |  Branch (433:17): [True: 3, False: 0]
  ------------------
  434|      3|                tmp = aiString(mi.name);
  435|      3|                mo->AddProperty(&tmp,AI_MATKEY_NAME);
  436|      3|            }
  437|       |
  438|      3|            mo->AddProperty(&mi.ambient,1,AI_MATKEY_COLOR_AMBIENT);
  439|      3|            mo->AddProperty(&mi.diffuse,1,AI_MATKEY_COLOR_DIFFUSE);
  440|      3|            mo->AddProperty(&mi.specular,1,AI_MATKEY_COLOR_SPECULAR);
  441|      3|            mo->AddProperty(&mi.emissive,1,AI_MATKEY_COLOR_EMISSIVE);
  442|       |
  443|      3|            mo->AddProperty(&mi.shininess,1,AI_MATKEY_SHININESS);
  444|      3|            mo->AddProperty(&mi.transparency,1,AI_MATKEY_OPACITY);
  445|       |
  446|      3|            const int sm = mi.shininess>0.f?aiShadingMode_Phong:aiShadingMode_Gouraud;
  ------------------
  |  Branch (446:28): [True: 2, False: 1]
  ------------------
  447|      3|            mo->AddProperty(&sm,1,AI_MATKEY_SHADING_MODEL);
  448|      3|        }
  449|      2|    }
  450|       |
  451|       |    // convert groups to meshes
  452|     26|    if (groups.empty()) {
  ------------------
  |  Branch (452:9): [True: 0, False: 26]
  ------------------
  453|      0|        throw DeadlyImportError("MS3D: Didn't get any group records, file is malformed");
  454|      0|    }
  455|       |
  456|     26|    pScene->mMeshes = new aiMesh*[pScene->mNumMeshes=static_cast<unsigned int>(groups.size())]();
  457|     39|    for (unsigned int i = 0; i < pScene->mNumMeshes; ++i) {
  ------------------
  |  Branch (457:30): [True: 16, False: 23]
  ------------------
  458|       |
  459|     16|        aiMesh* m = pScene->mMeshes[i] = new aiMesh();
  460|     16|        const TempGroup& g = groups[i];
  461|       |
  462|     16|        if (pScene->mNumMaterials && g.mat > pScene->mNumMaterials) {
  ------------------
  |  Branch (462:13): [True: 9, False: 7]
  |  Branch (462:38): [True: 0, False: 9]
  ------------------
  463|      0|            throw DeadlyImportError("MS3D: Encountered invalid material index, file is malformed");
  464|      0|        } // no error if no materials at all - scenepreprocessor adds one then
  465|       |
  466|     16|        m->mMaterialIndex  = g.mat;
  467|     16|        m->mPrimitiveTypes = aiPrimitiveType_TRIANGLE;
  468|       |
  469|     16|        m->mFaces = new aiFace[m->mNumFaces = static_cast<unsigned int>(g.triangles.size())];
  470|     16|        m->mNumVertices = m->mNumFaces*3;
  471|       |
  472|       |        // storage for vertices - verbose format, as requested by the postprocessing pipeline
  473|     16|        m->mVertices = new aiVector3D[m->mNumVertices];
  474|     16|        m->mNormals  = new aiVector3D[m->mNumVertices];
  475|     16|        m->mTextureCoords[0] = new aiVector3D[m->mNumVertices];
  476|     16|        m->mNumUVComponents[0] = 2;
  477|       |
  478|     16|        typedef std::map<unsigned int,unsigned int> BoneSet;
  479|     16|        BoneSet mybones;
  480|       |
  481|  6.46k|        for (unsigned int j = 0,n = 0; j < m->mNumFaces; ++j) {
  ------------------
  |  Branch (481:40): [True: 6.45k, False: 13]
  ------------------
  482|  6.45k|            aiFace& f = m->mFaces[j];
  483|  6.45k|            if (g.triangles[j] >= triangles.size()) {
  ------------------
  |  Branch (483:17): [True: 0, False: 6.45k]
  ------------------
  484|      0|                throw DeadlyImportError("MS3D: Encountered invalid triangle index, file is malformed");
  485|      0|            }
  486|       |
  487|  6.45k|            TempTriangle& t = triangles[g.triangles[j]];
  488|  6.45k|            f.mIndices = new unsigned int[f.mNumIndices=3];
  489|       |
  490|  25.8k|            for (unsigned int k = 0; k < 3; ++k,++n) {
  ------------------
  |  Branch (490:38): [True: 19.3k, False: 6.45k]
  ------------------
  491|  19.3k|                if (t.indices[k] >= vertices.size()) {
  ------------------
  |  Branch (491:21): [True: 0, False: 19.3k]
  ------------------
  492|      0|                    throw DeadlyImportError("MS3D: Encountered invalid vertex index, file is malformed");
  493|      0|                }
  494|       |
  495|  19.3k|                const TempVertex& v = vertices[t.indices[k]];
  496|  96.8k|                for(unsigned int a = 0; a < 4; ++a) {
  ------------------
  |  Branch (496:41): [True: 77.4k, False: 19.3k]
  ------------------
  497|  77.4k|                    if (v.bone_id[a] != UINT_MAX) {
  ------------------
  |  Branch (497:25): [True: 3, False: 77.4k]
  ------------------
  498|      3|                        if (v.bone_id[a] >= joints.size()) {
  ------------------
  |  Branch (498:29): [True: 3, False: 0]
  ------------------
  499|      3|                            throw DeadlyImportError("MS3D: Encountered invalid bone index, file is malformed");
  500|      3|                        }
  501|      0|                        if (mybones.find(v.bone_id[a]) == mybones.end()) {
  ------------------
  |  Branch (501:29): [True: 0, False: 0]
  ------------------
  502|      0|                             mybones[v.bone_id[a]] = 1;
  503|      0|                        }
  504|      0|                        else ++mybones[v.bone_id[a]];
  505|      0|                    }
  506|  77.4k|                }
  507|       |
  508|       |                // collect vertex components
  509|  19.3k|                m->mVertices[n] = v.pos;
  510|       |
  511|  19.3k|                m->mNormals[n] = t.normals[k];
  512|  19.3k|                m->mTextureCoords[0][n] = aiVector3D(t.uv[k].x,1.f-t.uv[k].y,0.0);
  513|  19.3k|                f.mIndices[k] = n;
  514|  19.3k|            }
  515|  6.45k|        }
  516|       |
  517|       |        // allocate storage for bones
  518|     13|        if(!mybones.empty()) {
  ------------------
  |  Branch (518:12): [True: 0, False: 13]
  ------------------
  519|      0|            std::vector<unsigned int> bmap(joints.size());
  520|      0|            m->mBones = new aiBone*[mybones.size()]();
  521|      0|            for(BoneSet::const_iterator it = mybones.begin(); it != mybones.end(); ++it) {
  ------------------
  |  Branch (521:63): [True: 0, False: 0]
  ------------------
  522|      0|                aiBone* const bn = m->mBones[m->mNumBones] = new aiBone();
  523|      0|                const TempJoint& jnt = joints[(*it).first];
  524|       |
  525|      0|                bn->mName.Set(jnt.name);
  526|      0|                bn->mWeights = new aiVertexWeight[(*it).second];
  527|       |
  528|      0|                bmap[(*it).first] = m->mNumBones++;
  529|      0|            }
  530|       |
  531|       |            // .. and collect bone weights
  532|      0|            for (unsigned int j = 0,n = 0; j < m->mNumFaces; ++j) {
  ------------------
  |  Branch (532:44): [True: 0, False: 0]
  ------------------
  533|      0|                TempTriangle& t = triangles[g.triangles[j]];
  534|       |
  535|      0|                for (unsigned int k = 0; k < 3; ++k,++n) {
  ------------------
  |  Branch (535:42): [True: 0, False: 0]
  ------------------
  536|      0|                    const TempVertex& v = vertices[t.indices[k]];
  537|      0|                    for(unsigned int a = 0; a < 4; ++a) {
  ------------------
  |  Branch (537:45): [True: 0, False: 0]
  ------------------
  538|      0|                        const unsigned int bone = v.bone_id[a];
  539|      0|                        if(bone==UINT_MAX){
  ------------------
  |  Branch (539:28): [True: 0, False: 0]
  ------------------
  540|      0|                            continue;
  541|      0|                        }
  542|       |
  543|      0|                        aiBone* const outbone = m->mBones[bmap[bone]];
  544|      0|                        aiVertexWeight& outwght = outbone->mWeights[outbone->mNumWeights++];
  545|       |
  546|      0|                        outwght.mVertexId = n;
  547|      0|                        outwght.mWeight = v.weights[a];
  548|      0|                    }
  549|      0|                }
  550|      0|            }
  551|      0|        }
  552|     13|    }
  553|       |
  554|       |    // ... add dummy nodes under a single root, each holding a reference to one
  555|       |    // mesh. If we didn't do this, we'd lose the group name.
  556|     23|    aiNode* rt = pScene->mRootNode = new aiNode("<MS3DRoot>");
  557|       |
  558|       |#ifdef ASSIMP_BUILD_MS3D_ONE_NODE_PER_MESH
  559|       |    rt->mChildren = new aiNode*[rt->mNumChildren=pScene->mNumMeshes+(joints.size()?1:0)]();
  560|       |
  561|       |    for (unsigned int i = 0; i < pScene->mNumMeshes; ++i) {
  562|       |        aiNode* nd = rt->mChildren[i] = new aiNode();
  563|       |
  564|       |        const TempGroup& g = groups[i];
  565|       |
  566|       |        // we need to generate an unique name for all mesh nodes.
  567|       |        // since we want to keep the group name, a prefix is
  568|       |        // prepended.
  569|       |        nd->mName = aiString("<MS3DMesh>_");
  570|       |        nd->mName.Append(g.name);
  571|       |        nd->mParent = rt;
  572|       |
  573|       |        nd->mMeshes = new unsigned int[nd->mNumMeshes = 1];
  574|       |        nd->mMeshes[0] = i;
  575|       |    }
  576|       |#else
  577|     23|    rt->mMeshes = new unsigned int[pScene->mNumMeshes];
  578|     35|    for (unsigned int i = 0; i < pScene->mNumMeshes; ++i) {
  ------------------
  |  Branch (578:30): [True: 12, False: 23]
  ------------------
  579|     12|        rt->mMeshes[rt->mNumMeshes++] = i;
  580|     12|    }
  581|     23|#endif
  582|       |
  583|       |    // convert animations as well
  584|     23|    if(joints.size()) {
  ------------------
  |  Branch (584:8): [True: 0, False: 23]
  ------------------
  585|      0|#ifndef ASSIMP_BUILD_MS3D_ONE_NODE_PER_MESH
  586|      0|        rt->mChildren = new aiNode*[1]();
  587|      0|        rt->mNumChildren = 1;
  588|       |
  589|      0|        aiNode* jt = rt->mChildren[0] = new aiNode();
  590|       |#else
  591|       |        aiNode* jt = rt->mChildren[pScene->mNumMeshes] = new aiNode();
  592|       |#endif
  593|      0|        jt->mParent = rt;
  594|      0|        CollectChildJoints(joints,jt);
  595|      0|        jt->mName.Set("<MS3DJointRoot>");
  596|       |
  597|      0|        pScene->mAnimations = new aiAnimation*[ pScene->mNumAnimations = 1 ];
  598|      0|        aiAnimation* const anim = pScene->mAnimations[0] = new aiAnimation();
  599|       |
  600|      0|        anim->mName.Set("<MS3DMasterAnim>");
  601|       |
  602|       |        // carry the fps info to the user by scaling all times with it
  603|      0|        anim->mTicksPerSecond = animfps;
  604|       |
  605|       |        // leave duration at its default, so ScenePreprocessor will fill an appropriate
  606|       |        // value (the values taken from some MS3D files seem to be too unreliable
  607|       |        // to pass the validation)
  608|       |        // anim->mDuration = totalframes/animfps;
  609|       |
  610|      0|        anim->mChannels = new aiNodeAnim*[joints.size()]();
  611|      0|        for(std::vector<TempJoint>::const_iterator it = joints.begin(); it != joints.end(); ++it) {
  ------------------
  |  Branch (611:73): [True: 0, False: 0]
  ------------------
  612|      0|            if ((*it).rotFrames.empty() && (*it).posFrames.empty()) {
  ------------------
  |  Branch (612:17): [True: 0, False: 0]
  |  Branch (612:44): [True: 0, False: 0]
  ------------------
  613|      0|                continue;
  614|      0|            }
  615|       |
  616|      0|            aiNodeAnim* nd = anim->mChannels[anim->mNumChannels++] = new aiNodeAnim();
  617|      0|            nd->mNodeName.Set((*it).name);
  618|       |
  619|      0|            if ((*it).rotFrames.size()) {
  ------------------
  |  Branch (619:17): [True: 0, False: 0]
  ------------------
  620|      0|                nd->mRotationKeys = new aiQuatKey[(*it).rotFrames.size()];
  621|      0|                for(std::vector<TempKeyFrame>::const_iterator rot = (*it).rotFrames.begin(); rot != (*it).rotFrames.end(); ++rot) {
  ------------------
  |  Branch (621:94): [True: 0, False: 0]
  ------------------
  622|      0|                    aiQuatKey& q = nd->mRotationKeys[nd->mNumRotationKeys++];
  623|       |
  624|      0|                    q.mTime = (*rot).time*animfps;
  625|      0|                    q.mValue = aiQuaternion(aiMatrix3x3(aiMatrix4x4().FromEulerAnglesXYZ((*it).rotation)*
  626|      0|                        aiMatrix4x4().FromEulerAnglesXYZ((*rot).value)));
  627|      0|                }
  628|      0|            }
  629|       |
  630|      0|            if ((*it).posFrames.size()) {
  ------------------
  |  Branch (630:17): [True: 0, False: 0]
  ------------------
  631|      0|                nd->mPositionKeys = new aiVectorKey[(*it).posFrames.size()];
  632|       |
  633|      0|                aiQuatKey* qu = nd->mRotationKeys;
  634|      0|                for(std::vector<TempKeyFrame>::const_iterator pos = (*it).posFrames.begin(); pos != (*it).posFrames.end(); ++pos,++qu) {
  ------------------
  |  Branch (634:94): [True: 0, False: 0]
  ------------------
  635|      0|                    aiVectorKey& v = nd->mPositionKeys[nd->mNumPositionKeys++];
  636|       |
  637|      0|                    v.mTime = (*pos).time*animfps;
  638|      0|                    v.mValue = (*it).position + (*pos).value;
  639|      0|                }
  640|      0|            }
  641|      0|        }
  642|       |        // fixup to pass the validation if not a single animation channel is non-trivial
  643|      0|        if (!anim->mNumChannels) {
  ------------------
  |  Branch (643:13): [True: 0, False: 0]
  ------------------
  644|      0|            anim->mChannels = nullptr;
  645|      0|        }
  646|      0|    }
  647|     23|}
_ZN6Assimp12MS3DImporter12ReadCommentsINS0_9TempGroupEEEvRNS_12StreamReaderILb0ELb0EEERNSt3__16vectorIT_NS6_9allocatorIS8_EEEE:
  114|      7|{
  115|      7|    uint16_t cnt;
  116|      7|    stream >> cnt;
  117|       |
  118|      8|    for(unsigned int i = 0; i < cnt; ++i) {
  ------------------
  |  Branch (118:29): [True: 1, False: 7]
  ------------------
  119|      1|        uint32_t index, clength;
  120|      1|        stream >> index >> clength;
  121|       |
  122|      1|        if(index >= outp.size()) {
  ------------------
  |  Branch (122:12): [True: 0, False: 1]
  ------------------
  123|      0|            ASSIMP_LOG_WARN("MS3D: Invalid index in comment section");
  124|      0|        }
  125|      1|        else if (clength > stream.GetRemainingSize()) {
  ------------------
  |  Branch (125:18): [True: 0, False: 1]
  ------------------
  126|      0|            throw DeadlyImportError("MS3D: Failure reading comment, length field is out of range");
  127|      0|        }
  128|      1|        else {
  129|      1|            outp[index].comment = std::string(reinterpret_cast<char*>(stream.GetPtr()),clength);
  130|      1|        }
  131|      1|        stream.IncPtr(clength);
  132|      1|    }
  133|      7|}
_ZN6Assimp12MS3DImporter12ReadCommentsINS0_12TempMaterialEEEvRNS_12StreamReaderILb0ELb0EEERNSt3__16vectorIT_NS6_9allocatorIS8_EEEE:
  114|      7|{
  115|      7|    uint16_t cnt;
  116|      7|    stream >> cnt;
  117|       |
  118|      9|    for(unsigned int i = 0; i < cnt; ++i) {
  ------------------
  |  Branch (118:29): [True: 2, False: 7]
  ------------------
  119|      2|        uint32_t index, clength;
  120|      2|        stream >> index >> clength;
  121|       |
  122|      2|        if(index >= outp.size()) {
  ------------------
  |  Branch (122:12): [True: 2, False: 0]
  ------------------
  123|      2|            ASSIMP_LOG_WARN("MS3D: Invalid index in comment section");
  124|      2|        }
  125|      0|        else if (clength > stream.GetRemainingSize()) {
  ------------------
  |  Branch (125:18): [True: 0, False: 0]
  ------------------
  126|      0|            throw DeadlyImportError("MS3D: Failure reading comment, length field is out of range");
  127|      0|        }
  128|      0|        else {
  129|      0|            outp[index].comment = std::string(reinterpret_cast<char*>(stream.GetPtr()),clength);
  130|      0|        }
  131|      2|        stream.IncPtr(clength);
  132|      2|    }
  133|      7|}
_ZN6Assimp12MS3DImporter12ReadCommentsINS0_9TempJointEEEvRNS_12StreamReaderILb0ELb0EEERNSt3__16vectorIT_NS6_9allocatorIS8_EEEE:
  114|      7|{
  115|      7|    uint16_t cnt;
  116|      7|    stream >> cnt;
  117|       |
  118|      7|    for(unsigned int i = 0; i < cnt; ++i) {
  ------------------
  |  Branch (118:29): [True: 0, False: 7]
  ------------------
  119|      0|        uint32_t index, clength;
  120|      0|        stream >> index >> clength;
  121|       |
  122|      0|        if(index >= outp.size()) {
  ------------------
  |  Branch (122:12): [True: 0, False: 0]
  ------------------
  123|      0|            ASSIMP_LOG_WARN("MS3D: Invalid index in comment section");
  124|      0|        }
  125|      0|        else if (clength > stream.GetRemainingSize()) {
  ------------------
  |  Branch (125:18): [True: 0, False: 0]
  ------------------
  126|      0|            throw DeadlyImportError("MS3D: Failure reading comment, length field is out of range");
  127|      0|        }
  128|      0|        else {
  129|      0|            outp[index].comment = std::string(reinterpret_cast<char*>(stream.GetPtr()),clength);
  130|      0|        }
  131|      0|        stream.IncPtr(clength);
  132|      0|    }
  133|      7|}
_Z7inrangeIjjjEbRKT_RKT0_RKT1_:
  137|      6|{
  138|      6|    return in > lower && in <= higher;
  ------------------
  |  Branch (138:12): [True: 0, False: 6]
  |  Branch (138:26): [True: 0, False: 0]
  ------------------
  139|      6|}

_ZNK6Assimp11NDOImporter7CanReadERKNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEPNS_8IOSystemEb:
   75|     57|{
   76|     57|    static const char* tokens[] = {"nendo"};
   77|       |    return SearchFileHeaderForToken(pIOHandler,pFile,tokens,AI_COUNT_OF(tokens),5);
   78|     57|}
_ZNK6Assimp11NDOImporter7GetInfoEv:
   83|    637|{
   84|    637|    return &desc;
   85|    637|}
_ZN6Assimp11NDOImporter15SetupPropertiesEPKNS_8ImporterE:
   90|      3|{
   91|       |    // nothing to be done for the moment
   92|      3|}
_Z27ProcessFaceEdgesAndVerticesRKN6Assimp11NDOImporter6ObjectEjjRNSt3__16vectorI10aiVector3tIfENS4_9allocatorIS7_EEEERNS5_IjNS8_IjEEEE:
   99|     46|{
  100|     46|    unsigned int cur_edge = start_edge;
  101|     46|    do {
  102|     46|        unsigned int next_edge, next_vert;
  103|     46|        if (key == obj.edges[cur_edge].edge[3]) {
  ------------------
  |  Branch (103:13): [True: 38, False: 8]
  ------------------
  104|     38|            next_edge = obj.edges[cur_edge].edge[5];
  105|     38|            next_vert = obj.edges[cur_edge].edge[1];
  106|     38|        }
  107|      8|        else {
  108|      8|            next_edge = obj.edges[cur_edge].edge[4];
  109|      8|            next_vert = obj.edges[cur_edge].edge[0];
  110|      8|        }
  111|     46|        indices.push_back( static_cast<unsigned int>(vertices.size()) );
  112|     46|        if (next_vert < obj.vertices.size()) {
  ------------------
  |  Branch (112:13): [True: 0, False: 46]
  ------------------
  113|      0|            vertices.push_back(obj.vertices[ next_vert ].val);
  114|      0|        }
  115|     46|        else {
  116|     46|            ASSIMP_LOG_WARN("NDOImporter: next_vert is out of bounds, skipping invalid access.");
  117|     46|            break;
  118|     46|        }
  119|       |
  120|      0|        cur_edge = next_edge;
  121|      0|    } while (cur_edge != start_edge);
  ------------------
  |  Branch (121:14): [True: 0, False: 0]
  ------------------
  122|     46|}
_ZN6Assimp11NDOImporter14InternReadFileERKNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEP7aiScenePNS_8IOSystemE:
  128|      3|{
  129|       |
  130|      3|    auto file = pIOHandler->Open( pFile, "rb");
  131|      3|    if (!file) {
  ------------------
  |  Branch (131:9): [True: 0, False: 3]
  ------------------
  132|      0|        throw DeadlyImportError("Nendo: Could not open ", pFile);
  133|      0|    }
  134|       |
  135|      3|    StreamReaderBE reader(file);
  136|       |
  137|       |    // first 9 bytes are nendo file format ("nendo 1.n")
  138|      3|    const char* head = (const char*)reader.GetPtr();
  139|      3|    reader.IncPtr(9);
  140|       |
  141|      3|    if (strncmp("nendo ",head,6)) {
  ------------------
  |  Branch (141:9): [True: 0, False: 3]
  ------------------
  142|      0|        throw DeadlyImportError("Not a Nendo file; magic signature missing");
  143|      0|    }
  144|       |    // check if this is a supported version. if not, continue, too -- users,
  145|       |    // please don't complain if it doesn't work then ...
  146|      3|    unsigned int file_format = 12;
  147|      3|    if (!strncmp("1.0",head+6,3)) {
  ------------------
  |  Branch (147:9): [True: 0, False: 3]
  ------------------
  148|      0|        file_format = 10;
  149|      0|        ASSIMP_LOG_INFO("NDO file format is 1.0");
  150|      0|    }
  151|      3|    else if (!strncmp("1.1",head+6,3)) {
  ------------------
  |  Branch (151:14): [True: 2, False: 1]
  ------------------
  152|      2|        file_format = 11;
  153|      2|        ASSIMP_LOG_INFO("NDO file format is 1.1");
  154|      2|    }
  155|      1|    else if (!strncmp("1.2",head+6,3)) {
  ------------------
  |  Branch (155:14): [True: 0, False: 1]
  ------------------
  156|      0|        file_format = 12;
  157|      0|        ASSIMP_LOG_INFO("NDO file format is 1.2");
  158|      0|    }
  159|      1|    else {
  160|      1|        char buff[4] = {0};
  161|      1|        memcpy(buff, head+6, 3);
  162|      1|        ASSIMP_LOG_WARN( "Unrecognized nendo file format version, continuing happily ... :", buff);
  163|      1|    }
  164|       |
  165|      3|    reader.IncPtr(2); /* skip flags */
  166|      3|    if (file_format >= 12) {
  ------------------
  |  Branch (166:9): [True: 1, False: 2]
  ------------------
  167|      1|        reader.IncPtr(2);
  168|      1|    }
  169|      3|    unsigned int temp = reader.GetU1();
  170|       |
  171|      3|    std::vector<Object> objects(temp); /* buffer to store all the loaded objects in */
  172|       |
  173|       |    // read all objects
  174|     44|    for (unsigned int o = 0; o < objects.size(); ++o) {
  ------------------
  |  Branch (174:30): [True: 41, False: 3]
  ------------------
  175|       |
  176|       |//      if (file_format < 12) {
  177|     41|            if (!reader.GetI1()) {
  ------------------
  |  Branch (177:17): [True: 36, False: 5]
  ------------------
  178|     36|                continue; /* skip over empty object */
  179|     36|            }
  180|       |        //  reader.GetI2();
  181|       |//      }
  182|      5|        Object& obj = objects[o];
  183|       |
  184|      5|        temp = file_format >= 12 ? reader.GetU4() : reader.GetU2();
  ------------------
  |  Branch (184:16): [True: 1, False: 4]
  ------------------
  185|      5|        head = (const char*)reader.GetPtr();
  186|      5|        if (std::numeric_limits<unsigned int>::max() - 76 < temp) {
  ------------------
  |  Branch (186:13): [True: 0, False: 5]
  ------------------
  187|      0|            throw DeadlyImportError("Invalid name length");
  188|      0|        }
  189|      5|        reader.IncPtr(temp + 76); /* skip unknown stuff */
  190|       |
  191|      5|        obj.name = std::string(head, temp);
  192|       |
  193|       |        // read edge table
  194|      5|        temp = file_format >= 12 ? reader.GetU4() : reader.GetU2();
  ------------------
  |  Branch (194:16): [True: 1, False: 4]
  ------------------
  195|      5|        obj.edges.reserve(temp);
  196|    994|        for (unsigned int e = 0; e < temp; ++e) {
  ------------------
  |  Branch (196:34): [True: 989, False: 5]
  ------------------
  197|       |
  198|    989|            obj.edges.emplace_back();
  199|    989|            Edge& edge = obj.edges.back();
  200|       |
  201|  8.89k|            for (unsigned int i = 0; i< 8; ++i) {
  ------------------
  |  Branch (201:38): [True: 7.90k, False: 989]
  ------------------
  202|  7.90k|                edge.edge[i] = file_format >= 12 ? reader.GetU4() : reader.GetU2();
  ------------------
  |  Branch (202:32): [True: 3.79k, False: 4.11k]
  ------------------
  203|  7.90k|            }
  204|    989|            edge.hard =  file_format >= 11 ? reader.GetU1() : 0;
  ------------------
  |  Branch (204:26): [True: 988, False: 1]
  ------------------
  205|  8.89k|            for (unsigned int i = 0; i< 8; ++i) {
  ------------------
  |  Branch (205:38): [True: 7.90k, False: 989]
  ------------------
  206|  7.90k|                edge.color[i] = reader.GetU1();
  207|  7.90k|            }
  208|    989|        }
  209|       |
  210|       |        // read face table
  211|      5|        temp = file_format >= 12 ? reader.GetU4() : reader.GetU2();
  ------------------
  |  Branch (211:16): [True: 0, False: 5]
  ------------------
  212|      5|        obj.faces.reserve(temp);
  213|      5|        for (unsigned int e = 0; e < temp; ++e) {
  ------------------
  |  Branch (213:34): [True: 0, False: 5]
  ------------------
  214|       |
  215|      0|            obj.faces.emplace_back();
  216|      0|            Face& face = obj.faces.back();
  217|       |
  218|      0|            face.elem = file_format >= 12 ? reader.GetU4() : reader.GetU2();
  ------------------
  |  Branch (218:25): [True: 0, False: 0]
  ------------------
  219|      0|        }
  220|       |
  221|       |        // read vertex table
  222|      5|        temp = file_format >= 12 ? reader.GetU4() : reader.GetU2();
  ------------------
  |  Branch (222:16): [True: 0, False: 5]
  ------------------
  223|      5|        obj.vertices.reserve(temp);
  224|      5|        for (unsigned int e = 0; e < temp; ++e) {
  ------------------
  |  Branch (224:34): [True: 0, False: 5]
  ------------------
  225|       |
  226|      0|            obj.vertices.emplace_back();
  227|      0|            Vertex& v = obj.vertices.back();
  228|       |
  229|      0|            v.num = file_format >= 12 ? reader.GetU4() : reader.GetU2();
  ------------------
  |  Branch (229:21): [True: 0, False: 0]
  ------------------
  230|      0|            v.val.x = reader.GetF4();
  231|      0|            v.val.y = reader.GetF4();
  232|      0|            v.val.z = reader.GetF4();
  233|      0|        }
  234|       |
  235|       |        // read UVs
  236|      5|        temp = file_format >= 12 ? reader.GetU4() : reader.GetU2();
  ------------------
  |  Branch (236:16): [True: 0, False: 5]
  ------------------
  237|      5|        for (unsigned int e = 0; e < temp; ++e) {
  ------------------
  |  Branch (237:34): [True: 0, False: 5]
  ------------------
  238|      0|             file_format >= 12 ? reader.GetU4() : reader.GetU2();
  ------------------
  |  Branch (238:14): [True: 0, False: 0]
  ------------------
  239|      0|        }
  240|       |
  241|      5|        temp = file_format >= 12 ? reader.GetU4() : reader.GetU2();
  ------------------
  |  Branch (241:16): [True: 0, False: 5]
  ------------------
  242|      5|        for (unsigned int e = 0; e < temp; ++e) {
  ------------------
  |  Branch (242:34): [True: 0, False: 5]
  ------------------
  243|      0|             file_format >= 12 ? reader.GetU4() : reader.GetU2();
  ------------------
  |  Branch (243:14): [True: 0, False: 0]
  ------------------
  244|      0|        }
  245|       |
  246|      5|        if (reader.GetU1()) {
  ------------------
  |  Branch (246:13): [True: 0, False: 5]
  ------------------
  247|      0|            const unsigned int x = reader.GetU2(), y = reader.GetU2();
  248|      0|            temp = 0;
  249|      0|            while (temp < x*y)  {
  ------------------
  |  Branch (249:20): [True: 0, False: 0]
  ------------------
  250|      0|                unsigned int repeat = reader.GetU1();
  251|      0|                reader.GetU1();
  252|      0|                reader.GetU1();
  253|      0|                reader.GetU1();
  254|      0|                temp += repeat;
  255|      0|            }
  256|      0|        }
  257|      5|    }
  258|       |
  259|       |    // construct a dummy node graph and add all named objects as child nodes
  260|      3|    aiNode* root = pScene->mRootNode = new aiNode("$NDODummyRoot");
  261|      3|    aiNode** cc = root->mChildren = new aiNode* [ root->mNumChildren = static_cast<unsigned int>( objects.size()) ] ();
  262|      3|    pScene->mMeshes = new aiMesh* [ root->mNumChildren] ();
  263|       |
  264|      3|    std::vector<aiVector3D> vertices;
  265|      3|    std::vector<unsigned int> indices;
  266|       |
  267|     40|    for(const Object& obj : objects) {
  ------------------
  |  Branch (267:27): [True: 40, False: 3]
  ------------------
  268|     40|        aiNode* nd = *cc++ = new aiNode(obj.name);
  269|     40|        nd->mParent = root;
  270|       |
  271|       |        // translated from a python dict() - a vector might be sufficient as well
  272|     40|        typedef std::map<unsigned int, unsigned int>  FaceTable;
  273|     40|        FaceTable face_table;
  274|       |
  275|     40|        unsigned int n = 0;
  276|    514|        for(const Edge& edge : obj.edges) {
  ------------------
  |  Branch (276:30): [True: 514, False: 40]
  ------------------
  277|       |
  278|    514|            face_table[edge.edge[2]] = n;
  279|    514|            face_table[edge.edge[3]] = n;
  280|       |
  281|    514|            ++n;
  282|    514|        }
  283|       |
  284|     40|        aiMesh* mesh = new aiMesh();
  285|     40|        mesh->mNumFaces=static_cast<unsigned int>(face_table.size());
  286|     40|        aiFace* faces = mesh->mFaces = new aiFace[mesh->mNumFaces];
  287|       |
  288|     40|        vertices.clear();
  289|     40|        vertices.reserve(4 * face_table.size()); // arbitrarily chosen
  290|     46|        for(FaceTable::value_type& v : face_table) {
  ------------------
  |  Branch (290:38): [True: 46, False: 40]
  ------------------
  291|     46|            indices.clear();
  292|       |
  293|     46|            aiFace& f = *faces++;
  294|       |
  295|     46|            ProcessFaceEdgesAndVertices(obj, v.second, v.first, vertices, indices);
  296|       |
  297|     46|            f.mIndices = new unsigned int[f.mNumIndices = static_cast<unsigned int>(indices.size())];
  298|     46|            std::copy(indices.begin(),indices.end(),f.mIndices);
  299|     46|        }
  300|       |
  301|     40|        mesh->mVertices = new aiVector3D[mesh->mNumVertices = static_cast<unsigned int>(vertices.size())];
  302|     40|        std::copy(vertices.begin(),vertices.end(),mesh->mVertices);
  303|       |
  304|     40|        if (mesh->mNumVertices) {
  ------------------
  |  Branch (304:13): [True: 0, False: 40]
  ------------------
  305|      0|            pScene->mMeshes[pScene->mNumMeshes] = mesh;
  306|       |
  307|      0|            (nd->mMeshes = new unsigned int[nd->mNumMeshes=1])[0]=pScene->mNumMeshes++;
  308|      0|        }else
  309|     40|            delete mesh;
  310|     40|    }
  311|      3|}

_ZN6Assimp11NDOImporterC2Ev:
   68|    624|    NDOImporter() = default;

_ZNK6Assimp11NFFImporter7CanReadERKNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEPNS_8IOSystemEb:
   76|    353|bool NFFImporter::CanRead(const std::string & pFile, IOSystem * /*pIOHandler*/, bool /*checkSig*/) const {
   77|    353|    return SimpleExtensionCheck(pFile, "nff", "enff");
   78|    353|}
_ZNK6Assimp11NFFImporter7GetInfoEv:
   82|    643|const aiImporterDesc *NFFImporter::GetInfo() const {
   83|    643|    return &desc;
   84|    643|}
_ZN6Assimp11NFFImporter14InternReadFileERKNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEP7aiScenePNS_8IOSystemE:
  201|      9|void NFFImporter::InternReadFile(const std::string &file, aiScene *pScene, IOSystem *pIOHandler) {
  202|      9|    std::unique_ptr<IOStream> stream(pIOHandler->Open(file, "rb"));
  203|      9|    if (!stream) {
  ------------------
  |  Branch (203:9): [True: 0, False: 9]
  ------------------
  204|      0|        throw DeadlyImportError("Failed to open NFF file ", file, ".");
  205|      0|    }
  206|       |
  207|       |    // allocate storage and copy the contents of the file to a memory buffer
  208|       |    // (terminate it with zero)
  209|      9|    std::vector<char> mBuffer2;
  210|      9|    TextFileToBuffer(stream.get(), mBuffer2);
  211|      9|    const char *buffer = &mBuffer2[0];
  212|       |
  213|       |    // mesh arrays - separate here to make the handling of the pointers below easier.
  214|      9|    std::vector<MeshInfo> meshes;
  215|      9|    std::vector<MeshInfo> meshesWithNormals;
  216|      9|    std::vector<MeshInfo> meshesWithUVCoords;
  217|      9|    std::vector<MeshInfo> meshesLocked;
  218|       |
  219|      9|    char line[4096];
  220|      9|    const char *lineEnd = &line[4096];
  221|      9|    const char *sz;
  222|       |
  223|       |
  224|       |    // camera parameters
  225|      9|    aiVector3D camPos, camUp(0.f, 1.f, 0.f), camLookAt(0.f, 0.f, 1.f);
  226|      9|    ai_real angle = 45.f;
  227|      9|    aiVector2D resolution;
  228|       |
  229|      9|    bool hasCam = false;
  230|       |
  231|      9|    MeshInfo *currentMeshWithNormals = nullptr;
  232|      9|    MeshInfo *currentMesh = nullptr;
  233|      9|    MeshInfo *currentMeshWithUVCoords = nullptr;
  234|       |
  235|      9|    ShadingInfo s; // current material info
  236|       |
  237|       |    // degree of tessellation
  238|      9|    unsigned int iTesselation = 4;
  239|       |
  240|       |    // some temporary variables we need to parse the file
  241|      9|    unsigned int sphere = 0,
  242|      9|                 cylinder = 0,
  243|      9|                 cone = 0,
  244|      9|                 numNamed = 0,
  245|      9|                 dodecahedron = 0,
  246|      9|                 octahedron = 0,
  247|      9|                 tetrahedron = 0,
  248|      9|                 hexahedron = 0;
  249|       |
  250|       |    // lights imported from the file
  251|      9|    std::vector<Light> lights;
  252|       |
  253|       |    // check whether this is the NFF2 file format
  254|      9|    if (TokenMatch(buffer, "nff", 3)) {
  ------------------
  |  Branch (254:9): [True: 0, False: 9]
  ------------------
  255|      0|        const ai_real qnan = get_qnan();
  256|      0|        const aiColor4D cQNAN = aiColor4D(qnan, 0.f, 0.f, 1.f);
  257|      0|        const aiVector3D vQNAN = aiVector3D(qnan, 0.f, 0.f);
  258|       |
  259|       |        // another NFF file format ... just a raw parser has been implemented
  260|       |        // no support for further details, I don't think it is worth the effort
  261|       |        // http://ozviz.wasp.uwa.edu.au/~pbourke/dataformats/nff/nff2.html
  262|       |        // http://www.netghost.narod.ru/gff/graphics/summary/sense8.htm
  263|       |
  264|       |        // First of all: remove all comments from the file
  265|      0|        CommentRemover::RemoveLineComments("//", &mBuffer2[0]);
  266|       |
  267|      0|        while (GetNextLine(buffer, line)) {
  ------------------
  |  Branch (267:16): [True: 0, False: 0]
  ------------------
  268|      0|            SkipSpaces(line, &sz, lineEnd);
  269|      0|            if (TokenMatch(sz, "version", 7)) {
  ------------------
  |  Branch (269:17): [True: 0, False: 0]
  ------------------
  270|      0|                ASSIMP_LOG_INFO("NFF (Sense8) file format: ", sz);
  271|      0|            } else if (TokenMatch(sz, "viewpos", 7)) {
  ------------------
  |  Branch (271:24): [True: 0, False: 0]
  ------------------
  272|      0|                AI_NFF_PARSE_TRIPLE(camPos);
  ------------------
  |  |   93|      0|    AI_NFF_PARSE_FLOAT(v[0])   \
  |  |  ------------------
  |  |  |  |   88|      0|    SkipSpaces(&sz, lineEnd);          \
  |  |  |  |   89|      0|    if (!IsLineEnd(*sz)) sz = fast_atoreal_move(sz, (ai_real &)f);
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (89:9): [True: 0, False: 0]
  |  |  |  |  ------------------
  |  |  ------------------
  |  |   94|      0|    AI_NFF_PARSE_FLOAT(v[1])   \
  |  |  ------------------
  |  |  |  |   88|      0|    SkipSpaces(&sz, lineEnd);          \
  |  |  |  |   89|      0|    if (!IsLineEnd(*sz)) sz = fast_atoreal_move(sz, (ai_real &)f);
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (89:9): [True: 0, False: 0]
  |  |  |  |  ------------------
  |  |  ------------------
  |  |   95|      0|    AI_NFF_PARSE_FLOAT(v[2])
  |  |  ------------------
  |  |  |  |   88|      0|    SkipSpaces(&sz, lineEnd);          \
  |  |  |  |   89|      0|    if (!IsLineEnd(*sz)) sz = fast_atoreal_move(sz, (ai_real &)f);
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (89:9): [True: 0, False: 0]
  |  |  |  |  ------------------
  |  |  ------------------
  ------------------
  273|      0|                hasCam = true;
  274|      0|            } else if (TokenMatch(sz, "viewdir", 7)) {
  ------------------
  |  Branch (274:24): [True: 0, False: 0]
  ------------------
  275|      0|                AI_NFF_PARSE_TRIPLE(camLookAt);
  ------------------
  |  |   93|      0|    AI_NFF_PARSE_FLOAT(v[0])   \
  |  |  ------------------
  |  |  |  |   88|      0|    SkipSpaces(&sz, lineEnd);          \
  |  |  |  |   89|      0|    if (!IsLineEnd(*sz)) sz = fast_atoreal_move(sz, (ai_real &)f);
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (89:9): [True: 0, False: 0]
  |  |  |  |  ------------------
  |  |  ------------------
  |  |   94|      0|    AI_NFF_PARSE_FLOAT(v[1])   \
  |  |  ------------------
  |  |  |  |   88|      0|    SkipSpaces(&sz, lineEnd);          \
  |  |  |  |   89|      0|    if (!IsLineEnd(*sz)) sz = fast_atoreal_move(sz, (ai_real &)f);
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (89:9): [True: 0, False: 0]
  |  |  |  |  ------------------
  |  |  ------------------
  |  |   95|      0|    AI_NFF_PARSE_FLOAT(v[2])
  |  |  ------------------
  |  |  |  |   88|      0|    SkipSpaces(&sz, lineEnd);          \
  |  |  |  |   89|      0|    if (!IsLineEnd(*sz)) sz = fast_atoreal_move(sz, (ai_real &)f);
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (89:9): [True: 0, False: 0]
  |  |  |  |  ------------------
  |  |  ------------------
  ------------------
  276|      0|                hasCam = true;
  277|      0|            }
  278|       |            // This starts a new object section
  279|      0|            else if (!IsSpaceOrNewLine(*sz)) {
  ------------------
  |  Branch (279:22): [True: 0, False: 0]
  ------------------
  280|      0|                unsigned int subMeshIdx = 0;
  281|       |
  282|       |                // read the name of the object, skip all spaces
  283|       |                // at the end of it.
  284|      0|                const char *sz3 = sz;
  285|      0|                while (!IsSpaceOrNewLine(*sz))
  ------------------
  |  Branch (285:24): [True: 0, False: 0]
  ------------------
  286|      0|                    ++sz;
  287|      0|                std::string objectName = std::string(sz3, (unsigned int)(sz - sz3));
  288|       |
  289|      0|                const unsigned int objStart = (unsigned int)meshes.size();
  290|       |
  291|       |                // There could be a material table in a separate file
  292|      0|                std::vector<ShadingInfo> materialTable;
  293|      0|                while (true) {
  ------------------
  |  Branch (293:24): [True: 0, Folded]
  ------------------
  294|      0|                    AI_NFF2_GET_NEXT_TOKEN();
  ------------------
  |  |  109|      0|    do {                                                                    \
  |  |  110|      0|        if (!GetNextLine(buffer, line)) {                                   \
  |  |  ------------------
  |  |  |  Branch (110:13): [True: 0, False: 0]
  |  |  ------------------
  |  |  111|      0|            ASSIMP_LOG_WARN("NFF2: Unexpected EOF, can't read next token"); \
  |  |  112|      0|            break;                                                          \
  |  |  113|      0|        }                                                                   \
  |  |  114|      0|        SkipSpaces(line, &sz, lineEnd);                                              \
  |  |  115|      0|    } while (IsLineEnd(*sz))
  |  |  ------------------
  |  |  |  Branch (115:14): [True: 0, False: 0]
  |  |  ------------------
  ------------------
  295|       |
  296|       |                    // material table - an external file
  297|      0|                    if (TokenMatch(sz, "mtable", 6)) {
  ------------------
  |  Branch (297:25): [True: 0, False: 0]
  ------------------
  298|      0|                        SkipSpaces(&sz, lineEnd);
  299|      0|                        sz3 = sz;
  300|      0|                        while (!IsSpaceOrNewLine(*sz))
  ------------------
  |  Branch (300:32): [True: 0, False: 0]
  ------------------
  301|      0|                            ++sz;
  302|      0|                        const unsigned int diff = (unsigned int)(sz - sz3);
  303|      0|                        if (!diff)
  ------------------
  |  Branch (303:29): [True: 0, False: 0]
  ------------------
  304|      0|                            ASSIMP_LOG_WARN("NFF2: Found empty mtable token");
  305|      0|                        else {
  306|       |                            // The material table has the file extension .mat.
  307|       |                            // If it is not there, we need to append it
  308|      0|                            std::string path = std::string(sz3, diff);
  309|      0|                            if (std::string::npos == path.find_last_of(".mat")) {
  ------------------
  |  Branch (309:33): [True: 0, False: 0]
  ------------------
  310|      0|                                path.append(".mat");
  311|      0|                            }
  312|       |
  313|       |                            // Now extract the working directory from the path to
  314|       |                            // this file and append the material library filename
  315|       |                            // to it.
  316|      0|                            std::string::size_type sepPos;
  317|      0|                            if ((std::string::npos == (sepPos = path.find_last_of('\\')) || !sepPos) &&
  ------------------
  |  Branch (317:34): [True: 0, False: 0]
  |  Branch (317:93): [True: 0, False: 0]
  ------------------
  318|      0|                                    (std::string::npos == (sepPos = path.find_last_of('/')) || !sepPos)) {
  ------------------
  |  Branch (318:38): [True: 0, False: 0]
  |  Branch (318:96): [True: 0, False: 0]
  ------------------
  319|      0|                                sepPos = file.find_last_of('\\');
  320|      0|                                if (std::string::npos == sepPos) {
  ------------------
  |  Branch (320:37): [True: 0, False: 0]
  ------------------
  321|      0|                                    sepPos = file.find_last_of('/');
  322|      0|                                }
  323|      0|                                if (std::string::npos != sepPos) {
  ------------------
  |  Branch (323:37): [True: 0, False: 0]
  ------------------
  324|      0|                                    path = file.substr(0, sepPos + 1) + path;
  325|      0|                                }
  326|      0|                            }
  327|      0|                            LoadNFF2MaterialTable(materialTable, path, pIOHandler);
  328|      0|                        }
  329|      0|                    } else
  330|      0|                        break;
  331|      0|                }
  332|       |
  333|       |                // read the number of vertices
  334|      0|                unsigned int num = strtoul10(sz, &sz);
  335|       |
  336|       |                // temporary storage
  337|      0|                std::vector<aiColor4D> tempColors;
  338|      0|                std::vector<aiVector3D> tempPositions, tempTextureCoords, tempNormals;
  339|       |
  340|      0|                bool hasNormals = false, hasUVs = false, hasColor = false;
  341|       |
  342|      0|                tempPositions.reserve(num);
  343|      0|                tempColors.reserve(num);
  344|      0|                tempNormals.reserve(num);
  345|      0|                tempTextureCoords.reserve(num);
  346|      0|                for (unsigned int i = 0; i < num; ++i) {
  ------------------
  |  Branch (346:42): [True: 0, False: 0]
  ------------------
  347|      0|                    AI_NFF2_GET_NEXT_TOKEN();
  ------------------
  |  |  109|      0|    do {                                                                    \
  |  |  110|      0|        if (!GetNextLine(buffer, line)) {                                   \
  |  |  ------------------
  |  |  |  Branch (110:13): [True: 0, False: 0]
  |  |  ------------------
  |  |  111|      0|            ASSIMP_LOG_WARN("NFF2: Unexpected EOF, can't read next token"); \
  |  |  112|      0|            break;                                                          \
  |  |  113|      0|        }                                                                   \
  |  |  114|      0|        SkipSpaces(line, &sz, lineEnd);                                              \
  |  |  115|      0|    } while (IsLineEnd(*sz))
  |  |  ------------------
  |  |  |  Branch (115:14): [True: 0, False: 0]
  |  |  ------------------
  ------------------
  348|      0|                    aiVector3D v;
  349|      0|                    AI_NFF_PARSE_TRIPLE(v);
  ------------------
  |  |   93|      0|    AI_NFF_PARSE_FLOAT(v[0])   \
  |  |  ------------------
  |  |  |  |   88|      0|    SkipSpaces(&sz, lineEnd);          \
  |  |  |  |   89|      0|    if (!IsLineEnd(*sz)) sz = fast_atoreal_move(sz, (ai_real &)f);
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (89:9): [True: 0, False: 0]
  |  |  |  |  ------------------
  |  |  ------------------
  |  |   94|      0|    AI_NFF_PARSE_FLOAT(v[1])   \
  |  |  ------------------
  |  |  |  |   88|      0|    SkipSpaces(&sz, lineEnd);          \
  |  |  |  |   89|      0|    if (!IsLineEnd(*sz)) sz = fast_atoreal_move(sz, (ai_real &)f);
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (89:9): [True: 0, False: 0]
  |  |  |  |  ------------------
  |  |  ------------------
  |  |   95|      0|    AI_NFF_PARSE_FLOAT(v[2])
  |  |  ------------------
  |  |  |  |   88|      0|    SkipSpaces(&sz, lineEnd);          \
  |  |  |  |   89|      0|    if (!IsLineEnd(*sz)) sz = fast_atoreal_move(sz, (ai_real &)f);
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (89:9): [True: 0, False: 0]
  |  |  |  |  ------------------
  |  |  ------------------
  ------------------
  350|      0|                    tempPositions.push_back(v);
  351|       |
  352|       |                    // parse all other attributes in the line
  353|      0|                    while (true) {
  ------------------
  |  Branch (353:28): [True: 0, Folded]
  ------------------
  354|      0|                        SkipSpaces(&sz, lineEnd);
  355|      0|                        if (IsLineEnd(*sz)) break;
  ------------------
  |  Branch (355:29): [True: 0, False: 0]
  ------------------
  356|       |
  357|       |                        // color definition
  358|      0|                        if (TokenMatch(sz, "0x", 2)) {
  ------------------
  |  Branch (358:29): [True: 0, False: 0]
  ------------------
  359|      0|                            hasColor = true;
  360|      0|                            unsigned int numIdx = strtoul16(sz, &sz);
  361|      0|                            aiColor4D clr;
  362|      0|                            clr.a = 1.f;
  363|       |
  364|       |                            // 0xRRGGBB
  365|      0|                            clr.r = ((numIdx >> 16u) & 0xff) / 255.f;
  366|      0|                            clr.g = ((numIdx >> 8u) & 0xff) / 255.f;
  367|      0|                            clr.b = ((numIdx)&0xff) / 255.f;
  368|      0|                            tempColors.push_back(clr);
  369|      0|                        }
  370|       |                        // normal vector
  371|      0|                        else if (TokenMatch(sz, "norm", 4)) {
  ------------------
  |  Branch (371:34): [True: 0, False: 0]
  ------------------
  372|      0|                            hasNormals = true;
  373|      0|                            AI_NFF_PARSE_TRIPLE(v);
  ------------------
  |  |   93|      0|    AI_NFF_PARSE_FLOAT(v[0])   \
  |  |  ------------------
  |  |  |  |   88|      0|    SkipSpaces(&sz, lineEnd);          \
  |  |  |  |   89|      0|    if (!IsLineEnd(*sz)) sz = fast_atoreal_move(sz, (ai_real &)f);
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (89:9): [True: 0, False: 0]
  |  |  |  |  ------------------
  |  |  ------------------
  |  |   94|      0|    AI_NFF_PARSE_FLOAT(v[1])   \
  |  |  ------------------
  |  |  |  |   88|      0|    SkipSpaces(&sz, lineEnd);          \
  |  |  |  |   89|      0|    if (!IsLineEnd(*sz)) sz = fast_atoreal_move(sz, (ai_real &)f);
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (89:9): [True: 0, False: 0]
  |  |  |  |  ------------------
  |  |  ------------------
  |  |   95|      0|    AI_NFF_PARSE_FLOAT(v[2])
  |  |  ------------------
  |  |  |  |   88|      0|    SkipSpaces(&sz, lineEnd);          \
  |  |  |  |   89|      0|    if (!IsLineEnd(*sz)) sz = fast_atoreal_move(sz, (ai_real &)f);
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (89:9): [True: 0, False: 0]
  |  |  |  |  ------------------
  |  |  ------------------
  ------------------
  374|      0|                            tempNormals.push_back(v);
  375|      0|                        }
  376|       |                        // UV coordinate
  377|      0|                        else if (TokenMatch(sz, "uv", 2)) {
  ------------------
  |  Branch (377:34): [True: 0, False: 0]
  ------------------
  378|      0|                            hasUVs = true;
  379|      0|                            AI_NFF_PARSE_FLOAT(v.x);
  ------------------
  |  |   88|      0|    SkipSpaces(&sz, lineEnd);          \
  |  |   89|      0|    if (!IsLineEnd(*sz)) sz = fast_atoreal_move(sz, (ai_real &)f);
  |  |  ------------------
  |  |  |  Branch (89:9): [True: 0, False: 0]
  |  |  ------------------
  ------------------
  380|      0|                            AI_NFF_PARSE_FLOAT(v.y);
  ------------------
  |  |   88|      0|    SkipSpaces(&sz, lineEnd);          \
  |  |   89|      0|    if (!IsLineEnd(*sz)) sz = fast_atoreal_move(sz, (ai_real &)f);
  |  |  ------------------
  |  |  |  Branch (89:9): [True: 0, False: 0]
  |  |  ------------------
  ------------------
  381|      0|                            v.z = 0.f;
  382|      0|                            tempTextureCoords.push_back(v);
  383|      0|                        }
  384|      0|                    }
  385|       |
  386|       |                    // fill in dummies for all attributes that have not been set
  387|      0|                    if (tempNormals.size() != tempPositions.size())
  ------------------
  |  Branch (387:25): [True: 0, False: 0]
  ------------------
  388|      0|                        tempNormals.push_back(vQNAN);
  389|       |
  390|      0|                    if (tempTextureCoords.size() != tempPositions.size())
  ------------------
  |  Branch (390:25): [True: 0, False: 0]
  ------------------
  391|      0|                        tempTextureCoords.push_back(vQNAN);
  392|       |
  393|      0|                    if (tempColors.size() != tempPositions.size())
  ------------------
  |  Branch (393:25): [True: 0, False: 0]
  ------------------
  394|      0|                        tempColors.push_back(cQNAN);
  395|      0|                }
  396|       |
  397|      0|                AI_NFF2_GET_NEXT_TOKEN();
  ------------------
  |  |  109|      0|    do {                                                                    \
  |  |  110|      0|        if (!GetNextLine(buffer, line)) {                                   \
  |  |  ------------------
  |  |  |  Branch (110:13): [True: 0, False: 0]
  |  |  ------------------
  |  |  111|      0|            ASSIMP_LOG_WARN("NFF2: Unexpected EOF, can't read next token"); \
  |  |  112|      0|            break;                                                          \
  |  |  113|      0|        }                                                                   \
  |  |  114|      0|        SkipSpaces(line, &sz, lineEnd);                                              \
  |  |  115|      0|    } while (IsLineEnd(*sz))
  |  |  ------------------
  |  |  |  Branch (115:14): [True: 0, False: 0]
  |  |  ------------------
  ------------------
  398|      0|                if (!num)
  ------------------
  |  Branch (398:21): [True: 0, False: 0]
  ------------------
  399|      0|                    throw DeadlyImportError("NFF2: There are zero vertices");
  400|      0|                num = strtoul10(sz, &sz);
  401|       |
  402|      0|                std::vector<unsigned int> tempIdx;
  403|      0|                tempIdx.reserve(10);
  404|      0|                for (unsigned int i = 0; i < num; ++i) {
  ------------------
  |  Branch (404:42): [True: 0, False: 0]
  ------------------
  405|      0|                    AI_NFF2_GET_NEXT_TOKEN();
  ------------------
  |  |  109|      0|    do {                                                                    \
  |  |  110|      0|        if (!GetNextLine(buffer, line)) {                                   \
  |  |  ------------------
  |  |  |  Branch (110:13): [True: 0, False: 0]
  |  |  ------------------
  |  |  111|      0|            ASSIMP_LOG_WARN("NFF2: Unexpected EOF, can't read next token"); \
  |  |  112|      0|            break;                                                          \
  |  |  113|      0|        }                                                                   \
  |  |  114|      0|        SkipSpaces(line, &sz, lineEnd);                                              \
  |  |  115|      0|    } while (IsLineEnd(*sz))
  |  |  ------------------
  |  |  |  Branch (115:14): [True: 0, False: 0]
  |  |  ------------------
  ------------------
  406|      0|                    SkipSpaces(line, &sz, lineEnd);
  407|      0|                    unsigned int numIdx = strtoul10(sz, &sz);
  408|       |
  409|       |                    // read all faces indices
  410|      0|                    if (numIdx) {
  ------------------
  |  Branch (410:25): [True: 0, False: 0]
  ------------------
  411|      0|                        tempIdx.resize(numIdx);
  412|       |
  413|      0|                        for (unsigned int a = 0; a < numIdx; ++a) {
  ------------------
  |  Branch (413:50): [True: 0, False: 0]
  ------------------
  414|      0|                            SkipSpaces(sz, &sz, lineEnd);
  415|      0|                            unsigned int m = strtoul10(sz, &sz);
  416|      0|                            if (m >= (unsigned int)tempPositions.size()) {
  ------------------
  |  Branch (416:33): [True: 0, False: 0]
  ------------------
  417|      0|                                ASSIMP_LOG_ERROR("NFF2: Vertex index overflow");
  418|      0|                                m = 0;
  419|      0|                            }
  420|      0|                            tempIdx[a] = m;
  421|      0|                        }
  422|      0|                    }
  423|       |
  424|       |                    // build a temporary shader object for the face.
  425|      0|                    ShadingInfo shader;
  426|      0|                    unsigned int matIdx = 0;
  427|       |
  428|       |                    // white material color - we have vertex colors
  429|      0|                    shader.color = aiColor3D(1.f, 1.f, 1.f);
  430|      0|                    aiColor4D c = aiColor4D(1.f, 1.f, 1.f, 1.f);
  431|      0|                    while (true) {
  ------------------
  |  Branch (431:28): [True: 0, Folded]
  ------------------
  432|      0|                        SkipSpaces(sz, &sz, lineEnd);
  433|      0|                        if (IsLineEnd(*sz)) break;
  ------------------
  |  Branch (433:29): [True: 0, False: 0]
  ------------------
  434|       |
  435|       |                        // per-polygon colors
  436|      0|                        if (TokenMatch(sz, "0x", 2)) {
  ------------------
  |  Branch (436:29): [True: 0, False: 0]
  ------------------
  437|      0|                            hasColor = true;
  438|      0|                            const char *sz2 = sz;
  439|      0|                            numIdx = strtoul16(sz, &sz);
  440|      0|                            const unsigned int diff = (unsigned int)(sz - sz2);
  441|       |
  442|       |                            // 0xRRGGBB
  443|      0|                            if (diff > 3) {
  ------------------
  |  Branch (443:33): [True: 0, False: 0]
  ------------------
  444|      0|                                c.r = ((numIdx >> 16u) & 0xff) / 255.f;
  445|      0|                                c.g = ((numIdx >> 8u) & 0xff) / 255.f;
  446|      0|                                c.b = ((numIdx)&0xff) / 255.f;
  447|      0|                            }
  448|       |                            // 0xRGB
  449|      0|                            else {
  450|      0|                                c.r = ((numIdx >> 8u) & 0xf) / 16.f;
  451|      0|                                c.g = ((numIdx >> 4u) & 0xf) / 16.f;
  452|      0|                                c.b = ((numIdx)&0xf) / 16.f;
  453|      0|                            }
  454|      0|                        }
  455|       |                        // TODO - implement texture mapping here
  456|       |#if 0
  457|       |                        // mirror vertex texture coordinate?
  458|       |                        else if (TokenMatch(sz,"mirror",6))
  459|       |                        {
  460|       |                        }
  461|       |                        // texture coordinate scaling
  462|       |                        else if (TokenMatch(sz,"scale",5))
  463|       |                        {
  464|       |                        }
  465|       |                        // texture coordinate translation
  466|       |                        else if (TokenMatch(sz,"trans",5))
  467|       |                        {
  468|       |                        }
  469|       |                        // texture coordinate rotation angle
  470|       |                        else if (TokenMatch(sz,"rot",3))
  471|       |                        {
  472|       |                        }
  473|       |#endif
  474|       |
  475|       |                        // texture file name for this polygon + mapping information
  476|      0|                        else if ('_' == sz[0]) {
  ------------------
  |  Branch (476:34): [True: 0, False: 0]
  ------------------
  477|       |                            // get mapping information
  478|      0|                            switch (sz[1]) {
  ------------------
  |  Branch (478:37): [True: 0, False: 0]
  ------------------
  479|      0|                                case 'v':
  ------------------
  |  Branch (479:33): [True: 0, False: 0]
  ------------------
  480|      0|                                case 'V':
  ------------------
  |  Branch (480:33): [True: 0, False: 0]
  ------------------
  481|       |
  482|      0|                                    shader.shaded = false;
  483|      0|                                    break;
  484|       |
  485|      0|                                case 't':
  ------------------
  |  Branch (485:33): [True: 0, False: 0]
  ------------------
  486|      0|                                case 'T':
  ------------------
  |  Branch (486:33): [True: 0, False: 0]
  ------------------
  487|      0|                                case 'u':
  ------------------
  |  Branch (487:33): [True: 0, False: 0]
  ------------------
  488|      0|                                case 'U':
  ------------------
  |  Branch (488:33): [True: 0, False: 0]
  ------------------
  489|       |
  490|      0|                                    ASSIMP_LOG_WARN("Unsupported NFF2 texture attribute: trans");
  491|      0|                            };
  492|      0|                            if (!sz[1] || '_' != sz[2]) {
  ------------------
  |  Branch (492:33): [True: 0, False: 0]
  |  Branch (492:43): [True: 0, False: 0]
  ------------------
  493|      0|                                ASSIMP_LOG_WARN("NFF2: Expected underscore after texture attributes");
  494|      0|                                continue;
  495|      0|                            }
  496|      0|                            const char *sz2 = sz + 3;
  497|      0|                            while (!IsSpaceOrNewLine(*sz))
  ------------------
  |  Branch (497:36): [True: 0, False: 0]
  ------------------
  498|      0|                                ++sz;
  499|      0|                            const unsigned int diff = (unsigned int)(sz - sz2);
  500|      0|                            if (diff) shader.texFile = std::string(sz2, diff);
  ------------------
  |  Branch (500:33): [True: 0, False: 0]
  ------------------
  501|      0|                        }
  502|       |
  503|       |                        // Two-sided material?
  504|      0|                        else if (TokenMatch(sz, "both", 4)) {
  ------------------
  |  Branch (504:34): [True: 0, False: 0]
  ------------------
  505|      0|                            shader.twoSided = true;
  506|      0|                        }
  507|       |
  508|       |                        // Material ID?
  509|      0|                        else if (!materialTable.empty() && TokenMatch(sz, "matid", 5)) {
  ------------------
  |  Branch (509:34): [True: 0, False: 0]
  |  Branch (509:60): [True: 0, False: 0]
  ------------------
  510|      0|                            SkipSpaces(&sz, lineEnd);
  511|      0|                            matIdx = strtoul10(sz, &sz);
  512|      0|                            if (matIdx >= materialTable.size()) {
  ------------------
  |  Branch (512:33): [True: 0, False: 0]
  ------------------
  513|      0|                                ASSIMP_LOG_ERROR("NFF2: Material index overflow.");
  514|      0|                                matIdx = 0;
  515|      0|                            }
  516|       |
  517|       |                            // now combine our current shader with the shader we
  518|       |                            // read from the material table.
  519|      0|                            ShadingInfo &mat = materialTable[matIdx];
  520|      0|                            shader.ambient = mat.ambient;
  521|      0|                            shader.diffuse = mat.diffuse;
  522|      0|                            shader.emissive = mat.emissive;
  523|      0|                            shader.opacity = mat.opacity;
  524|      0|                            shader.specular = mat.specular;
  525|      0|                            shader.shininess = mat.shininess;
  526|      0|                        } else
  527|      0|                            SkipToken(sz, lineEnd);
  528|      0|                    }
  529|       |
  530|       |                    // search the list of all shaders we have for this object whether
  531|       |                    // there is an identical one. In this case, we append our mesh
  532|       |                    // data to it.
  533|      0|                    MeshInfo *mesh = nullptr;
  534|      0|                    for (std::vector<MeshInfo>::iterator it = meshes.begin() + objStart, end = meshes.end();
  535|      0|                            it != end; ++it) {
  ------------------
  |  Branch (535:29): [True: 0, False: 0]
  ------------------
  536|      0|                        if ((*it).shader == shader && (*it).matIndex == matIdx) {
  ------------------
  |  Branch (536:29): [True: 0, False: 0]
  |  Branch (536:55): [True: 0, False: 0]
  ------------------
  537|       |                            // we have one, we can append our data to it
  538|      0|                            mesh = &(*it);
  539|      0|                        }
  540|      0|                    }
  541|      0|                    if (!mesh) {
  ------------------
  |  Branch (541:25): [True: 0, False: 0]
  ------------------
  542|      0|                        meshes.emplace_back(PatchType_Simple, false);
  543|      0|                        mesh = &meshes.back();
  544|      0|                        mesh->matIndex = matIdx;
  545|       |
  546|       |                        // We need to add a new mesh to the list. We assign
  547|       |                        // an unique name to it to make sure the scene will
  548|       |                        // pass the validation step for the moment.
  549|       |                        // TODO: fix naming of objects in the scene-graph later
  550|      0|                        if (objectName.length()) {
  ------------------
  |  Branch (550:29): [True: 0, False: 0]
  ------------------
  551|      0|                            ::strncpy(mesh->name, objectName.c_str(), objectName.size());
  552|      0|                            ASSIMP_itoa10(&mesh->name[objectName.length()], 30, subMeshIdx++);
  553|      0|                        }
  554|       |
  555|       |                        // copy the shader to the mesh.
  556|      0|                        mesh->shader = shader;
  557|      0|                    }
  558|       |
  559|       |                    // fill the mesh with data
  560|      0|                    if (!tempIdx.empty()) {
  ------------------
  |  Branch (560:25): [True: 0, False: 0]
  ------------------
  561|      0|                        mesh->faces.push_back((unsigned int)tempIdx.size());
  562|      0|                        for (std::vector<unsigned int>::const_iterator it = tempIdx.begin(), end = tempIdx.end();
  563|      0|                                it != end; ++it) {
  ------------------
  |  Branch (563:33): [True: 0, False: 0]
  ------------------
  564|      0|                            unsigned int m = *it;
  565|       |
  566|       |                            // copy colors -vertex color specifications override polygon color specifications
  567|      0|                            if (hasColor) {
  ------------------
  |  Branch (567:33): [True: 0, False: 0]
  ------------------
  568|      0|                                const aiColor4D &clr = tempColors[m];
  569|      0|                                mesh->colors.push_back((is_qnan(clr.r) ? c : clr));
  ------------------
  |  Branch (569:57): [True: 0, False: 0]
  ------------------
  570|      0|                            }
  571|       |
  572|       |                            // positions should always be there
  573|      0|                            mesh->vertices.push_back(tempPositions[m]);
  574|       |
  575|       |                            // copy normal vectors
  576|      0|                            if (hasNormals)
  ------------------
  |  Branch (576:33): [True: 0, False: 0]
  ------------------
  577|      0|                                mesh->normals.push_back(tempNormals[m]);
  578|       |
  579|       |                            // copy texture coordinates
  580|      0|                            if (hasUVs)
  ------------------
  |  Branch (580:33): [True: 0, False: 0]
  ------------------
  581|      0|                                mesh->uvs.push_back(tempTextureCoords[m]);
  582|      0|                        }
  583|      0|                    }
  584|      0|                }
  585|      0|                if (!num) throw DeadlyImportError("NFF2: There are zero faces");
  ------------------
  |  Branch (585:21): [True: 0, False: 0]
  ------------------
  586|      0|            }
  587|      0|        }
  588|      0|        camLookAt = camLookAt + camPos;
  589|      0|    } else // "Normal" Neutral file format that is quite more common
  590|      9|    {
  591|  8.76k|        while (GetNextLine(buffer, line)) {
  ------------------
  |  Branch (591:16): [True: 8.75k, False: 9]
  ------------------
  592|  8.75k|            sz = line;
  593|  8.75k|            if ('p' == line[0] || TokenMatch(sz, "tpp", 3)) {
  ------------------
  |  Branch (593:17): [True: 0, False: 8.75k]
  |  Branch (593:35): [True: 0, False: 8.75k]
  ------------------
  594|      0|                MeshInfo *out = nullptr;
  595|       |
  596|       |                // 'tpp' - texture polygon patch primitive
  597|      0|                if ('t' == line[0]) {
  ------------------
  |  Branch (597:21): [True: 0, False: 0]
  ------------------
  598|      0|                    currentMeshWithUVCoords = nullptr;
  599|      0|                    for (auto &mesh : meshesWithUVCoords) {
  ------------------
  |  Branch (599:37): [True: 0, False: 0]
  ------------------
  600|      0|                        if (mesh.shader == s) {
  ------------------
  |  Branch (600:29): [True: 0, False: 0]
  ------------------
  601|      0|                            currentMeshWithUVCoords = &mesh;
  602|      0|                            break;
  603|      0|                        }
  604|      0|                    }
  605|       |
  606|      0|                    if (!currentMeshWithUVCoords) {
  ------------------
  |  Branch (606:25): [True: 0, False: 0]
  ------------------
  607|      0|                        meshesWithUVCoords.emplace_back(PatchType_UVAndNormals);
  608|      0|                        currentMeshWithUVCoords = &meshesWithUVCoords.back();
  609|      0|                        currentMeshWithUVCoords->shader = s;
  610|      0|                    }
  611|      0|                    out = currentMeshWithUVCoords;
  612|      0|                }
  613|       |                // 'pp' - polygon patch primitive
  614|      0|                else if ('p' == line[1]) {
  ------------------
  |  Branch (614:26): [True: 0, False: 0]
  ------------------
  615|      0|                    currentMeshWithNormals = nullptr;
  616|      0|                    for (auto &mesh : meshesWithNormals) {
  ------------------
  |  Branch (616:37): [True: 0, False: 0]
  ------------------
  617|      0|                        if (mesh.shader == s) {
  ------------------
  |  Branch (617:29): [True: 0, False: 0]
  ------------------
  618|      0|                            currentMeshWithNormals = &mesh;
  619|      0|                            break;
  620|      0|                        }
  621|      0|                    }
  622|       |
  623|      0|                    if (!currentMeshWithNormals) {
  ------------------
  |  Branch (623:25): [True: 0, False: 0]
  ------------------
  624|      0|                        meshesWithNormals.emplace_back(PatchType_Normals);
  625|      0|                        currentMeshWithNormals = &meshesWithNormals.back();
  626|      0|                        currentMeshWithNormals->shader = s;
  627|      0|                    }
  628|      0|                    sz = &line[2];
  629|      0|                    out = currentMeshWithNormals;
  630|      0|                }
  631|       |                // 'p' - polygon primitive
  632|      0|                else {
  633|      0|                    currentMesh = nullptr;
  634|      0|                    for (auto &mesh : meshes) {
  ------------------
  |  Branch (634:37): [True: 0, False: 0]
  ------------------
  635|      0|                        if (mesh.shader == s) {
  ------------------
  |  Branch (635:29): [True: 0, False: 0]
  ------------------
  636|      0|                            currentMesh = &mesh;
  637|      0|                            break;
  638|      0|                        }
  639|      0|                    }
  640|       |
  641|      0|                    if (!currentMesh) {
  ------------------
  |  Branch (641:25): [True: 0, False: 0]
  ------------------
  642|      0|                        meshes.emplace_back(PatchType_Simple);
  643|      0|                        currentMesh = &meshes.back();
  644|      0|                        currentMesh->shader = s;
  645|      0|                    }
  646|      0|                    sz = &line[1];
  647|      0|                    out = currentMesh;
  648|      0|                }
  649|      0|                SkipSpaces(sz, &sz, lineEnd);
  650|      0|                unsigned int m = strtoul10(sz);
  651|       |
  652|       |                // ---- flip the face order
  653|      0|                out->vertices.resize(out->vertices.size() + m);
  654|      0|                if (out != currentMesh) {
  ------------------
  |  Branch (654:21): [True: 0, False: 0]
  ------------------
  655|      0|                    out->normals.resize(out->vertices.size());
  656|      0|                }
  657|      0|                if (out == currentMeshWithUVCoords) {
  ------------------
  |  Branch (657:21): [True: 0, False: 0]
  ------------------
  658|      0|                    out->uvs.resize(out->vertices.size());
  659|      0|                }
  660|      0|                for (unsigned int n = 0; n < m; ++n) {
  ------------------
  |  Branch (660:42): [True: 0, False: 0]
  ------------------
  661|      0|                    if (!GetNextLine(buffer, line)) {
  ------------------
  |  Branch (661:25): [True: 0, False: 0]
  ------------------
  662|      0|                        ASSIMP_LOG_ERROR("NFF: Unexpected EOF was encountered. Patch definition incomplete");
  663|      0|                        continue;
  664|      0|                    }
  665|       |
  666|      0|                    aiVector3D v;
  667|      0|                    sz = &line[0];
  668|      0|                    AI_NFF_PARSE_TRIPLE(v);
  ------------------
  |  |   93|      0|    AI_NFF_PARSE_FLOAT(v[0])   \
  |  |  ------------------
  |  |  |  |   88|      0|    SkipSpaces(&sz, lineEnd);          \
  |  |  |  |   89|      0|    if (!IsLineEnd(*sz)) sz = fast_atoreal_move(sz, (ai_real &)f);
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (89:9): [True: 0, False: 0]
  |  |  |  |  ------------------
  |  |  ------------------
  |  |   94|      0|    AI_NFF_PARSE_FLOAT(v[1])   \
  |  |  ------------------
  |  |  |  |   88|      0|    SkipSpaces(&sz, lineEnd);          \
  |  |  |  |   89|      0|    if (!IsLineEnd(*sz)) sz = fast_atoreal_move(sz, (ai_real &)f);
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (89:9): [True: 0, False: 0]
  |  |  |  |  ------------------
  |  |  ------------------
  |  |   95|      0|    AI_NFF_PARSE_FLOAT(v[2])
  |  |  ------------------
  |  |  |  |   88|      0|    SkipSpaces(&sz, lineEnd);          \
  |  |  |  |   89|      0|    if (!IsLineEnd(*sz)) sz = fast_atoreal_move(sz, (ai_real &)f);
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (89:9): [True: 0, False: 0]
  |  |  |  |  ------------------
  |  |  ------------------
  ------------------
  669|      0|                    out->vertices[out->vertices.size() - n - 1] = v;
  670|       |
  671|      0|                    if (out != currentMesh) {
  ------------------
  |  Branch (671:25): [True: 0, False: 0]
  ------------------
  672|      0|                        AI_NFF_PARSE_TRIPLE(v);
  ------------------
  |  |   93|      0|    AI_NFF_PARSE_FLOAT(v[0])   \
  |  |  ------------------
  |  |  |  |   88|      0|    SkipSpaces(&sz, lineEnd);          \
  |  |  |  |   89|      0|    if (!IsLineEnd(*sz)) sz = fast_atoreal_move(sz, (ai_real &)f);
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (89:9): [True: 0, False: 0]
  |  |  |  |  ------------------
  |  |  ------------------
  |  |   94|      0|    AI_NFF_PARSE_FLOAT(v[1])   \
  |  |  ------------------
  |  |  |  |   88|      0|    SkipSpaces(&sz, lineEnd);          \
  |  |  |  |   89|      0|    if (!IsLineEnd(*sz)) sz = fast_atoreal_move(sz, (ai_real &)f);
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (89:9): [True: 0, False: 0]
  |  |  |  |  ------------------
  |  |  ------------------
  |  |   95|      0|    AI_NFF_PARSE_FLOAT(v[2])
  |  |  ------------------
  |  |  |  |   88|      0|    SkipSpaces(&sz, lineEnd);          \
  |  |  |  |   89|      0|    if (!IsLineEnd(*sz)) sz = fast_atoreal_move(sz, (ai_real &)f);
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (89:9): [True: 0, False: 0]
  |  |  |  |  ------------------
  |  |  ------------------
  ------------------
  673|      0|                        out->normals[out->vertices.size() - n - 1] = v;
  674|      0|                    }
  675|      0|                    if (out == currentMeshWithUVCoords) {
  ------------------
  |  Branch (675:25): [True: 0, False: 0]
  ------------------
  676|       |                        // FIX: in one test file this wraps over multiple lines
  677|      0|                        SkipSpaces(&sz, lineEnd);
  678|      0|                        if (IsLineEnd(*sz)) {
  ------------------
  |  Branch (678:29): [True: 0, False: 0]
  ------------------
  679|      0|                            GetNextLine(buffer, line);
  680|      0|                            sz = line;
  681|      0|                        }
  682|      0|                        AI_NFF_PARSE_FLOAT(v.x);
  ------------------
  |  |   88|      0|    SkipSpaces(&sz, lineEnd);          \
  |  |   89|      0|    if (!IsLineEnd(*sz)) sz = fast_atoreal_move(sz, (ai_real &)f);
  |  |  ------------------
  |  |  |  Branch (89:9): [True: 0, False: 0]
  |  |  ------------------
  ------------------
  683|      0|                        SkipSpaces(&sz, lineEnd);
  684|      0|                        if (IsLineEnd(*sz)) {
  ------------------
  |  Branch (684:29): [True: 0, False: 0]
  ------------------
  685|      0|                            GetNextLine(buffer, line);
  686|      0|                            sz = line;
  687|      0|                        }
  688|      0|                        AI_NFF_PARSE_FLOAT(v.y);
  ------------------
  |  |   88|      0|    SkipSpaces(&sz, lineEnd);          \
  |  |   89|      0|    if (!IsLineEnd(*sz)) sz = fast_atoreal_move(sz, (ai_real &)f);
  |  |  ------------------
  |  |  |  Branch (89:9): [True: 0, False: 0]
  |  |  ------------------
  ------------------
  689|      0|                        v.y = 1.f - v.y;
  690|      0|                        out->uvs[out->vertices.size() - n - 1] = v;
  691|      0|                    }
  692|      0|                }
  693|      0|                out->faces.push_back(m);
  694|      0|            }
  695|       |            // 'f' - shading information block
  696|  8.75k|            else if (TokenMatch(sz, "f", 1)) {
  ------------------
  |  Branch (696:22): [True: 0, False: 8.75k]
  ------------------
  697|      0|                ai_real d;
  698|       |
  699|       |                // read the RGB colors
  700|      0|                AI_NFF_PARSE_TRIPLE(s.color);
  ------------------
  |  |   93|      0|    AI_NFF_PARSE_FLOAT(v[0])   \
  |  |  ------------------
  |  |  |  |   88|      0|    SkipSpaces(&sz, lineEnd);          \
  |  |  |  |   89|      0|    if (!IsLineEnd(*sz)) sz = fast_atoreal_move(sz, (ai_real &)f);
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (89:9): [True: 0, False: 0]
  |  |  |  |  ------------------
  |  |  ------------------
  |  |   94|      0|    AI_NFF_PARSE_FLOAT(v[1])   \
  |  |  ------------------
  |  |  |  |   88|      0|    SkipSpaces(&sz, lineEnd);          \
  |  |  |  |   89|      0|    if (!IsLineEnd(*sz)) sz = fast_atoreal_move(sz, (ai_real &)f);
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (89:9): [True: 0, False: 0]
  |  |  |  |  ------------------
  |  |  ------------------
  |  |   95|      0|    AI_NFF_PARSE_FLOAT(v[2])
  |  |  ------------------
  |  |  |  |   88|      0|    SkipSpaces(&sz, lineEnd);          \
  |  |  |  |   89|      0|    if (!IsLineEnd(*sz)) sz = fast_atoreal_move(sz, (ai_real &)f);
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (89:9): [True: 0, False: 0]
  |  |  |  |  ------------------
  |  |  ------------------
  ------------------
  701|       |
  702|       |                // read the other properties
  703|      0|                AI_NFF_PARSE_FLOAT(s.diffuse.r);
  ------------------
  |  |   88|      0|    SkipSpaces(&sz, lineEnd);          \
  |  |   89|      0|    if (!IsLineEnd(*sz)) sz = fast_atoreal_move(sz, (ai_real &)f);
  |  |  ------------------
  |  |  |  Branch (89:9): [True: 0, False: 0]
  |  |  ------------------
  ------------------
  704|      0|                AI_NFF_PARSE_FLOAT(s.specular.r);
  ------------------
  |  |   88|      0|    SkipSpaces(&sz, lineEnd);          \
  |  |   89|      0|    if (!IsLineEnd(*sz)) sz = fast_atoreal_move(sz, (ai_real &)f);
  |  |  ------------------
  |  |  |  Branch (89:9): [True: 0, False: 0]
  |  |  ------------------
  ------------------
  705|      0|                AI_NFF_PARSE_FLOAT(d); // skip shininess and transmittance
  ------------------
  |  |   88|      0|    SkipSpaces(&sz, lineEnd);          \
  |  |   89|      0|    if (!IsLineEnd(*sz)) sz = fast_atoreal_move(sz, (ai_real &)f);
  |  |  ------------------
  |  |  |  Branch (89:9): [True: 0, False: 0]
  |  |  ------------------
  ------------------
  706|      0|                AI_NFF_PARSE_FLOAT(d);
  ------------------
  |  |   88|      0|    SkipSpaces(&sz, lineEnd);          \
  |  |   89|      0|    if (!IsLineEnd(*sz)) sz = fast_atoreal_move(sz, (ai_real &)f);
  |  |  ------------------
  |  |  |  Branch (89:9): [True: 0, False: 0]
  |  |  ------------------
  ------------------
  707|      0|                AI_NFF_PARSE_FLOAT(s.refracti);
  ------------------
  |  |   88|      0|    SkipSpaces(&sz, lineEnd);          \
  |  |   89|      0|    if (!IsLineEnd(*sz)) sz = fast_atoreal_move(sz, (ai_real &)f);
  |  |  ------------------
  |  |  |  Branch (89:9): [True: 0, False: 0]
  |  |  ------------------
  ------------------
  708|       |
  709|       |                // NFF2 uses full colors here so we need to use them too
  710|       |                // although NFF uses simple scaling factors
  711|      0|                s.diffuse.g = s.diffuse.b = s.diffuse.r;
  712|      0|                s.specular.g = s.specular.b = s.specular.r;
  713|       |
  714|       |                // if the next one is NOT a number we assume it is a texture file name
  715|       |                // this feature is used by some NFF files on the internet and it has
  716|       |                // been implemented as it can be really useful
  717|      0|                SkipSpaces(&sz, lineEnd);
  718|      0|                if (!IsNumeric(*sz)) {
  ------------------
  |  Branch (718:21): [True: 0, False: 0]
  ------------------
  719|       |                    // TODO: Support full file names with spaces and quotation marks ...
  720|      0|                    const char *p = sz;
  721|      0|                    while (!IsSpaceOrNewLine(*sz))
  ------------------
  |  Branch (721:28): [True: 0, False: 0]
  ------------------
  722|      0|                        ++sz;
  723|       |
  724|      0|                    unsigned int diff = (unsigned int)(sz - p);
  725|      0|                    if (diff) {
  ------------------
  |  Branch (725:25): [True: 0, False: 0]
  ------------------
  726|      0|                        s.texFile = std::string(p, diff);
  727|      0|                    }
  728|      0|                } else {
  729|      0|                    AI_NFF_PARSE_FLOAT(s.ambient); // optional
  ------------------
  |  |   88|      0|    SkipSpaces(&sz, lineEnd);          \
  |  |   89|      0|    if (!IsLineEnd(*sz)) sz = fast_atoreal_move(sz, (ai_real &)f);
  |  |  ------------------
  |  |  |  Branch (89:9): [True: 0, False: 0]
  |  |  ------------------
  ------------------
  730|      0|                }
  731|  8.75k|            } else if (TokenMatch(sz, "shader", 6)) { // 'shader' - other way to specify a texture
  ------------------
  |  Branch (731:24): [True: 0, False: 8.75k]
  ------------------
  732|      0|                SkipSpaces(&sz, lineEnd);
  733|      0|                const char *old = sz;
  734|      0|                while (!IsSpaceOrNewLine(*sz))
  ------------------
  |  Branch (734:24): [True: 0, False: 0]
  ------------------
  735|      0|                    ++sz;
  736|      0|                s.texFile = std::string(old, (uintptr_t)sz - (uintptr_t)old);
  737|      0|            }
  738|       |            // 'l' - light source
  739|  8.75k|            else if (TokenMatch(sz, "l", 1)) {
  ------------------
  |  Branch (739:22): [True: 0, False: 8.75k]
  ------------------
  740|      0|                lights.emplace_back();
  741|      0|                Light &light = lights.back();
  742|       |
  743|      0|                AI_NFF_PARSE_TRIPLE(light.position);
  ------------------
  |  |   93|      0|    AI_NFF_PARSE_FLOAT(v[0])   \
  |  |  ------------------
  |  |  |  |   88|      0|    SkipSpaces(&sz, lineEnd);          \
  |  |  |  |   89|      0|    if (!IsLineEnd(*sz)) sz = fast_atoreal_move(sz, (ai_real &)f);
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (89:9): [True: 0, False: 0]
  |  |  |  |  ------------------
  |  |  ------------------
  |  |   94|      0|    AI_NFF_PARSE_FLOAT(v[1])   \
  |  |  ------------------
  |  |  |  |   88|      0|    SkipSpaces(&sz, lineEnd);          \
  |  |  |  |   89|      0|    if (!IsLineEnd(*sz)) sz = fast_atoreal_move(sz, (ai_real &)f);
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (89:9): [True: 0, False: 0]
  |  |  |  |  ------------------
  |  |  ------------------
  |  |   95|      0|    AI_NFF_PARSE_FLOAT(v[2])
  |  |  ------------------
  |  |  |  |   88|      0|    SkipSpaces(&sz, lineEnd);          \
  |  |  |  |   89|      0|    if (!IsLineEnd(*sz)) sz = fast_atoreal_move(sz, (ai_real &)f);
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (89:9): [True: 0, False: 0]
  |  |  |  |  ------------------
  |  |  ------------------
  ------------------
  744|      0|                AI_NFF_PARSE_FLOAT(light.intensity);
  ------------------
  |  |   88|      0|    SkipSpaces(&sz, lineEnd);          \
  |  |   89|      0|    if (!IsLineEnd(*sz)) sz = fast_atoreal_move(sz, (ai_real &)f);
  |  |  ------------------
  |  |  |  Branch (89:9): [True: 0, False: 0]
  |  |  ------------------
  ------------------
  745|      0|                AI_NFF_PARSE_TRIPLE(light.color);
  ------------------
  |  |   93|      0|    AI_NFF_PARSE_FLOAT(v[0])   \
  |  |  ------------------
  |  |  |  |   88|      0|    SkipSpaces(&sz, lineEnd);          \
  |  |  |  |   89|      0|    if (!IsLineEnd(*sz)) sz = fast_atoreal_move(sz, (ai_real &)f);
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (89:9): [True: 0, False: 0]
  |  |  |  |  ------------------
  |  |  ------------------
  |  |   94|      0|    AI_NFF_PARSE_FLOAT(v[1])   \
  |  |  ------------------
  |  |  |  |   88|      0|    SkipSpaces(&sz, lineEnd);          \
  |  |  |  |   89|      0|    if (!IsLineEnd(*sz)) sz = fast_atoreal_move(sz, (ai_real &)f);
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (89:9): [True: 0, False: 0]
  |  |  |  |  ------------------
  |  |  ------------------
  |  |   95|      0|    AI_NFF_PARSE_FLOAT(v[2])
  |  |  ------------------
  |  |  |  |   88|      0|    SkipSpaces(&sz, lineEnd);          \
  |  |  |  |   89|      0|    if (!IsLineEnd(*sz)) sz = fast_atoreal_move(sz, (ai_real &)f);
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (89:9): [True: 0, False: 0]
  |  |  |  |  ------------------
  |  |  ------------------
  ------------------
  746|      0|            }
  747|       |            // 's' - sphere
  748|  8.75k|            else if (TokenMatch(sz, "s", 1)) {
  ------------------
  |  Branch (748:22): [True: 6, False: 8.75k]
  ------------------
  749|      6|                meshesLocked.emplace_back(PatchType_Simple, true);
  750|      6|                MeshInfo &curMesh = meshesLocked.back();
  751|      6|                curMesh.shader = s;
  752|      6|                curMesh.shader.mapping = aiTextureMapping_SPHERE;
  753|       |
  754|      6|                AI_NFF_PARSE_SHAPE_INFORMATION();
  ------------------
  |  |   99|      6|    aiVector3D center, radius(1.0f, get_qnan(), get_qnan()); \
  |  |  100|      6|    AI_NFF_PARSE_TRIPLE(center);                             \
  |  |  ------------------
  |  |  |  |   93|      6|    AI_NFF_PARSE_FLOAT(v[0])   \
  |  |  |  |  ------------------
  |  |  |  |  |  |   88|      6|    SkipSpaces(&sz, lineEnd);          \
  |  |  |  |  |  |   89|      6|    if (!IsLineEnd(*sz)) sz = fast_atoreal_move(sz, (ai_real &)f);
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  Branch (89:9): [True: 3, False: 3]
  |  |  |  |  |  |  ------------------
  |  |  |  |  ------------------
  |  |  |  |   94|      6|    AI_NFF_PARSE_FLOAT(v[1])   \
  |  |  |  |  ------------------
  |  |  |  |  |  |   88|      6|    SkipSpaces(&sz, lineEnd);          \
  |  |  |  |  |  |   89|      6|    if (!IsLineEnd(*sz)) sz = fast_atoreal_move(sz, (ai_real &)f);
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  Branch (89:9): [True: 0, False: 6]
  |  |  |  |  |  |  ------------------
  |  |  |  |  ------------------
  |  |  |  |   95|      6|    AI_NFF_PARSE_FLOAT(v[2])
  |  |  |  |  ------------------
  |  |  |  |  |  |   88|      6|    SkipSpaces(&sz, lineEnd);          \
  |  |  |  |  |  |   89|      6|    if (!IsLineEnd(*sz)) sz = fast_atoreal_move(sz, (ai_real &)f);
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  Branch (89:9): [True: 0, False: 6]
  |  |  |  |  |  |  ------------------
  |  |  |  |  ------------------
  |  |  ------------------
  |  |  101|      6|    AI_NFF_PARSE_TRIPLE(radius);                             \
  |  |  ------------------
  |  |  |  |   93|      6|    AI_NFF_PARSE_FLOAT(v[0])   \
  |  |  |  |  ------------------
  |  |  |  |  |  |   88|      6|    SkipSpaces(&sz, lineEnd);          \
  |  |  |  |  |  |   89|      6|    if (!IsLineEnd(*sz)) sz = fast_atoreal_move(sz, (ai_real &)f);
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  Branch (89:9): [True: 0, False: 6]
  |  |  |  |  |  |  ------------------
  |  |  |  |  ------------------
  |  |  |  |   94|      6|    AI_NFF_PARSE_FLOAT(v[1])   \
  |  |  |  |  ------------------
  |  |  |  |  |  |   88|      6|    SkipSpaces(&sz, lineEnd);          \
  |  |  |  |  |  |   89|      6|    if (!IsLineEnd(*sz)) sz = fast_atoreal_move(sz, (ai_real &)f);
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  Branch (89:9): [True: 0, False: 6]
  |  |  |  |  |  |  ------------------
  |  |  |  |  ------------------
  |  |  |  |   95|      6|    AI_NFF_PARSE_FLOAT(v[2])
  |  |  |  |  ------------------
  |  |  |  |  |  |   88|      6|    SkipSpaces(&sz, lineEnd);          \
  |  |  |  |  |  |   89|      6|    if (!IsLineEnd(*sz)) sz = fast_atoreal_move(sz, (ai_real &)f);
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  Branch (89:9): [True: 0, False: 6]
  |  |  |  |  |  |  ------------------
  |  |  |  |  ------------------
  |  |  ------------------
  |  |  102|      6|    if (is_qnan(radius.z)) radius.z = radius.x;              \
  |  |  ------------------
  |  |  |  Branch (102:9): [True: 3, False: 3]
  |  |  ------------------
  |  |  103|      6|    if (is_qnan(radius.y)) radius.y = radius.x;              \
  |  |  ------------------
  |  |  |  Branch (103:9): [True: 3, False: 3]
  |  |  ------------------
  |  |  104|      6|    curMesh.radius = radius;                                 \
  |  |  105|      6|    curMesh.center = center;
  ------------------
  755|       |
  756|       |                // we don't need scaling or translation here - we do it in the node's transform
  757|      6|                StandardShapes::MakeSphere(iTesselation, curMesh.vertices);
  758|      6|                curMesh.faces.resize(curMesh.vertices.size() / 3, 3);
  759|       |
  760|       |                // generate a name for the mesh
  761|      6|                ::ai_snprintf(curMesh.name, MeshInfo::MaxNameLen, "sphere_%i", sphere++);
  762|      6|            }
  763|       |            // 'dod' - dodecahedron
  764|  8.75k|            else if (TokenMatch(sz, "dod", 3)) {
  ------------------
  |  Branch (764:22): [True: 1.76k, False: 6.98k]
  ------------------
  765|  1.76k|                meshesLocked.emplace_back(PatchType_Simple, true);
  766|  1.76k|                MeshInfo &curMesh = meshesLocked.back();
  767|  1.76k|                curMesh.shader = s;
  768|  1.76k|                curMesh.shader.mapping = aiTextureMapping_SPHERE;
  769|       |
  770|  1.76k|                AI_NFF_PARSE_SHAPE_INFORMATION();
  ------------------
  |  |   99|  1.76k|    aiVector3D center, radius(1.0f, get_qnan(), get_qnan()); \
  |  |  100|  1.76k|    AI_NFF_PARSE_TRIPLE(center);                             \
  |  |  ------------------
  |  |  |  |   93|  1.76k|    AI_NFF_PARSE_FLOAT(v[0])   \
  |  |  |  |  ------------------
  |  |  |  |  |  |   88|  1.76k|    SkipSpaces(&sz, lineEnd);          \
  |  |  |  |  |  |   89|  1.76k|    if (!IsLineEnd(*sz)) sz = fast_atoreal_move(sz, (ai_real &)f);
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  Branch (89:9): [True: 3, False: 1.76k]
  |  |  |  |  |  |  ------------------
  |  |  |  |  ------------------
  |  |  |  |   94|  1.76k|    AI_NFF_PARSE_FLOAT(v[1])   \
  |  |  |  |  ------------------
  |  |  |  |  |  |   88|  1.76k|    SkipSpaces(&sz, lineEnd);          \
  |  |  |  |  |  |   89|  1.76k|    if (!IsLineEnd(*sz)) sz = fast_atoreal_move(sz, (ai_real &)f);
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  Branch (89:9): [True: 0, False: 1.76k]
  |  |  |  |  |  |  ------------------
  |  |  |  |  ------------------
  |  |  |  |   95|  1.76k|    AI_NFF_PARSE_FLOAT(v[2])
  |  |  |  |  ------------------
  |  |  |  |  |  |   88|  1.76k|    SkipSpaces(&sz, lineEnd);          \
  |  |  |  |  |  |   89|  1.76k|    if (!IsLineEnd(*sz)) sz = fast_atoreal_move(sz, (ai_real &)f);
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  Branch (89:9): [True: 0, False: 1.76k]
  |  |  |  |  |  |  ------------------
  |  |  |  |  ------------------
  |  |  ------------------
  |  |  101|  1.76k|    AI_NFF_PARSE_TRIPLE(radius);                             \
  |  |  ------------------
  |  |  |  |   93|  1.76k|    AI_NFF_PARSE_FLOAT(v[0])   \
  |  |  |  |  ------------------
  |  |  |  |  |  |   88|  1.76k|    SkipSpaces(&sz, lineEnd);          \
  |  |  |  |  |  |   89|  1.76k|    if (!IsLineEnd(*sz)) sz = fast_atoreal_move(sz, (ai_real &)f);
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  Branch (89:9): [True: 0, False: 1.76k]
  |  |  |  |  |  |  ------------------
  |  |  |  |  ------------------
  |  |  |  |   94|  1.76k|    AI_NFF_PARSE_FLOAT(v[1])   \
  |  |  |  |  ------------------
  |  |  |  |  |  |   88|  1.76k|    SkipSpaces(&sz, lineEnd);          \
  |  |  |  |  |  |   89|  1.76k|    if (!IsLineEnd(*sz)) sz = fast_atoreal_move(sz, (ai_real &)f);
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  Branch (89:9): [True: 0, False: 1.76k]
  |  |  |  |  |  |  ------------------
  |  |  |  |  ------------------
  |  |  |  |   95|  1.76k|    AI_NFF_PARSE_FLOAT(v[2])
  |  |  |  |  ------------------
  |  |  |  |  |  |   88|  1.76k|    SkipSpaces(&sz, lineEnd);          \
  |  |  |  |  |  |   89|  1.76k|    if (!IsLineEnd(*sz)) sz = fast_atoreal_move(sz, (ai_real &)f);
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  Branch (89:9): [True: 0, False: 1.76k]
  |  |  |  |  |  |  ------------------
  |  |  |  |  ------------------
  |  |  ------------------
  |  |  102|  1.76k|    if (is_qnan(radius.z)) radius.z = radius.x;              \
  |  |  ------------------
  |  |  |  Branch (102:9): [True: 1.76k, False: 3]
  |  |  ------------------
  |  |  103|  1.76k|    if (is_qnan(radius.y)) radius.y = radius.x;              \
  |  |  ------------------
  |  |  |  Branch (103:9): [True: 1.76k, False: 3]
  |  |  ------------------
  |  |  104|  1.76k|    curMesh.radius = radius;                                 \
  |  |  105|  1.76k|    curMesh.center = center;
  ------------------
  771|       |
  772|       |                // we don't need scaling or translation here - we do it in the node's transform
  773|  1.76k|                StandardShapes::MakeDodecahedron(curMesh.vertices);
  774|  1.76k|                curMesh.faces.resize(curMesh.vertices.size() / 3, 3);
  775|       |
  776|       |                // generate a name for the mesh
  777|  1.76k|                ::ai_snprintf(curMesh.name, 128, "dodecahedron_%i", dodecahedron++);
  778|  1.76k|            }
  779|       |
  780|       |            // 'oct' - octahedron
  781|  6.98k|            else if (TokenMatch(sz, "oct", 3)) {
  ------------------
  |  Branch (781:22): [True: 0, False: 6.98k]
  ------------------
  782|      0|                meshesLocked.emplace_back(PatchType_Simple, true);
  783|      0|                MeshInfo &curMesh = meshesLocked.back();
  784|      0|                curMesh.shader = s;
  785|      0|                curMesh.shader.mapping = aiTextureMapping_SPHERE;
  786|       |
  787|      0|                AI_NFF_PARSE_SHAPE_INFORMATION();
  ------------------
  |  |   99|      0|    aiVector3D center, radius(1.0f, get_qnan(), get_qnan()); \
  |  |  100|      0|    AI_NFF_PARSE_TRIPLE(center);                             \
  |  |  ------------------
  |  |  |  |   93|      0|    AI_NFF_PARSE_FLOAT(v[0])   \
  |  |  |  |  ------------------
  |  |  |  |  |  |   88|      0|    SkipSpaces(&sz, lineEnd);          \
  |  |  |  |  |  |   89|      0|    if (!IsLineEnd(*sz)) sz = fast_atoreal_move(sz, (ai_real &)f);
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  Branch (89:9): [True: 0, False: 0]
  |  |  |  |  |  |  ------------------
  |  |  |  |  ------------------
  |  |  |  |   94|      0|    AI_NFF_PARSE_FLOAT(v[1])   \
  |  |  |  |  ------------------
  |  |  |  |  |  |   88|      0|    SkipSpaces(&sz, lineEnd);          \
  |  |  |  |  |  |   89|      0|    if (!IsLineEnd(*sz)) sz = fast_atoreal_move(sz, (ai_real &)f);
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  Branch (89:9): [True: 0, False: 0]
  |  |  |  |  |  |  ------------------
  |  |  |  |  ------------------
  |  |  |  |   95|      0|    AI_NFF_PARSE_FLOAT(v[2])
  |  |  |  |  ------------------
  |  |  |  |  |  |   88|      0|    SkipSpaces(&sz, lineEnd);          \
  |  |  |  |  |  |   89|      0|    if (!IsLineEnd(*sz)) sz = fast_atoreal_move(sz, (ai_real &)f);
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  Branch (89:9): [True: 0, False: 0]
  |  |  |  |  |  |  ------------------
  |  |  |  |  ------------------
  |  |  ------------------
  |  |  101|      0|    AI_NFF_PARSE_TRIPLE(radius);                             \
  |  |  ------------------
  |  |  |  |   93|      0|    AI_NFF_PARSE_FLOAT(v[0])   \
  |  |  |  |  ------------------
  |  |  |  |  |  |   88|      0|    SkipSpaces(&sz, lineEnd);          \
  |  |  |  |  |  |   89|      0|    if (!IsLineEnd(*sz)) sz = fast_atoreal_move(sz, (ai_real &)f);
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  Branch (89:9): [True: 0, False: 0]
  |  |  |  |  |  |  ------------------
  |  |  |  |  ------------------
  |  |  |  |   94|      0|    AI_NFF_PARSE_FLOAT(v[1])   \
  |  |  |  |  ------------------
  |  |  |  |  |  |   88|      0|    SkipSpaces(&sz, lineEnd);          \
  |  |  |  |  |  |   89|      0|    if (!IsLineEnd(*sz)) sz = fast_atoreal_move(sz, (ai_real &)f);
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  Branch (89:9): [True: 0, False: 0]
  |  |  |  |  |  |  ------------------
  |  |  |  |  ------------------
  |  |  |  |   95|      0|    AI_NFF_PARSE_FLOAT(v[2])
  |  |  |  |  ------------------
  |  |  |  |  |  |   88|      0|    SkipSpaces(&sz, lineEnd);          \
  |  |  |  |  |  |   89|      0|    if (!IsLineEnd(*sz)) sz = fast_atoreal_move(sz, (ai_real &)f);
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  Branch (89:9): [True: 0, False: 0]
  |  |  |  |  |  |  ------------------
  |  |  |  |  ------------------
  |  |  ------------------
  |  |  102|      0|    if (is_qnan(radius.z)) radius.z = radius.x;              \
  |  |  ------------------
  |  |  |  Branch (102:9): [True: 0, False: 0]
  |  |  ------------------
  |  |  103|      0|    if (is_qnan(radius.y)) radius.y = radius.x;              \
  |  |  ------------------
  |  |  |  Branch (103:9): [True: 0, False: 0]
  |  |  ------------------
  |  |  104|      0|    curMesh.radius = radius;                                 \
  |  |  105|      0|    curMesh.center = center;
  ------------------
  788|       |
  789|       |                // we don't need scaling or translation here - we do it in the node's transform
  790|      0|                StandardShapes::MakeOctahedron(curMesh.vertices);
  791|      0|                curMesh.faces.resize(curMesh.vertices.size() / 3, 3);
  792|       |
  793|       |                // generate a name for the mesh
  794|      0|                ::ai_snprintf(curMesh.name, MeshInfo::MaxNameLen, "octahedron_%i", octahedron++);
  795|      0|            }
  796|       |
  797|       |            // 'tet' - tetrahedron
  798|  6.98k|            else if (TokenMatch(sz, "tet", 3)) {
  ------------------
  |  Branch (798:22): [True: 0, False: 6.98k]
  ------------------
  799|      0|                meshesLocked.emplace_back(PatchType_Simple, true);
  800|      0|                MeshInfo &curMesh = meshesLocked.back();
  801|      0|                curMesh.shader = s;
  802|      0|                curMesh.shader.mapping = aiTextureMapping_SPHERE;
  803|       |
  804|      0|                AI_NFF_PARSE_SHAPE_INFORMATION();
  ------------------
  |  |   99|      0|    aiVector3D center, radius(1.0f, get_qnan(), get_qnan()); \
  |  |  100|      0|    AI_NFF_PARSE_TRIPLE(center);                             \
  |  |  ------------------
  |  |  |  |   93|      0|    AI_NFF_PARSE_FLOAT(v[0])   \
  |  |  |  |  ------------------
  |  |  |  |  |  |   88|      0|    SkipSpaces(&sz, lineEnd);          \
  |  |  |  |  |  |   89|      0|    if (!IsLineEnd(*sz)) sz = fast_atoreal_move(sz, (ai_real &)f);
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  Branch (89:9): [True: 0, False: 0]
  |  |  |  |  |  |  ------------------
  |  |  |  |  ------------------
  |  |  |  |   94|      0|    AI_NFF_PARSE_FLOAT(v[1])   \
  |  |  |  |  ------------------
  |  |  |  |  |  |   88|      0|    SkipSpaces(&sz, lineEnd);          \
  |  |  |  |  |  |   89|      0|    if (!IsLineEnd(*sz)) sz = fast_atoreal_move(sz, (ai_real &)f);
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  Branch (89:9): [True: 0, False: 0]
  |  |  |  |  |  |  ------------------
  |  |  |  |  ------------------
  |  |  |  |   95|      0|    AI_NFF_PARSE_FLOAT(v[2])
  |  |  |  |  ------------------
  |  |  |  |  |  |   88|      0|    SkipSpaces(&sz, lineEnd);          \
  |  |  |  |  |  |   89|      0|    if (!IsLineEnd(*sz)) sz = fast_atoreal_move(sz, (ai_real &)f);
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  Branch (89:9): [True: 0, False: 0]
  |  |  |  |  |  |  ------------------
  |  |  |  |  ------------------
  |  |  ------------------
  |  |  101|      0|    AI_NFF_PARSE_TRIPLE(radius);                             \
  |  |  ------------------
  |  |  |  |   93|      0|    AI_NFF_PARSE_FLOAT(v[0])   \
  |  |  |  |  ------------------
  |  |  |  |  |  |   88|      0|    SkipSpaces(&sz, lineEnd);          \
  |  |  |  |  |  |   89|      0|    if (!IsLineEnd(*sz)) sz = fast_atoreal_move(sz, (ai_real &)f);
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  Branch (89:9): [True: 0, False: 0]
  |  |  |  |  |  |  ------------------
  |  |  |  |  ------------------
  |  |  |  |   94|      0|    AI_NFF_PARSE_FLOAT(v[1])   \
  |  |  |  |  ------------------
  |  |  |  |  |  |   88|      0|    SkipSpaces(&sz, lineEnd);          \
  |  |  |  |  |  |   89|      0|    if (!IsLineEnd(*sz)) sz = fast_atoreal_move(sz, (ai_real &)f);
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  Branch (89:9): [True: 0, False: 0]
  |  |  |  |  |  |  ------------------
  |  |  |  |  ------------------
  |  |  |  |   95|      0|    AI_NFF_PARSE_FLOAT(v[2])
  |  |  |  |  ------------------
  |  |  |  |  |  |   88|      0|    SkipSpaces(&sz, lineEnd);          \
  |  |  |  |  |  |   89|      0|    if (!IsLineEnd(*sz)) sz = fast_atoreal_move(sz, (ai_real &)f);
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  Branch (89:9): [True: 0, False: 0]
  |  |  |  |  |  |  ------------------
  |  |  |  |  ------------------
  |  |  ------------------
  |  |  102|      0|    if (is_qnan(radius.z)) radius.z = radius.x;              \
  |  |  ------------------
  |  |  |  Branch (102:9): [True: 0, False: 0]
  |  |  ------------------
  |  |  103|      0|    if (is_qnan(radius.y)) radius.y = radius.x;              \
  |  |  ------------------
  |  |  |  Branch (103:9): [True: 0, False: 0]
  |  |  ------------------
  |  |  104|      0|    curMesh.radius = radius;                                 \
  |  |  105|      0|    curMesh.center = center;
  ------------------
  805|       |
  806|       |                // we don't need scaling or translation here - we do it in the node's transform
  807|      0|                StandardShapes::MakeTetrahedron(curMesh.vertices);
  808|      0|                curMesh.faces.resize(curMesh.vertices.size() / 3, 3);
  809|       |
  810|       |                // generate a name for the mesh
  811|      0|                ::ai_snprintf(curMesh.name, MeshInfo::MaxNameLen, "tetrahedron_%i", tetrahedron++);
  812|      0|            }
  813|       |
  814|       |            // 'hex' - hexahedron
  815|  6.98k|            else if (TokenMatch(sz, "hex", 3)) {
  ------------------
  |  Branch (815:22): [True: 0, False: 6.98k]
  ------------------
  816|      0|                meshesLocked.emplace_back(PatchType_Simple, true);
  817|      0|                MeshInfo &curMesh = meshesLocked.back();
  818|      0|                curMesh.shader = s;
  819|      0|                curMesh.shader.mapping = aiTextureMapping_BOX;
  820|       |
  821|      0|                AI_NFF_PARSE_SHAPE_INFORMATION();
  ------------------
  |  |   99|      0|    aiVector3D center, radius(1.0f, get_qnan(), get_qnan()); \
  |  |  100|      0|    AI_NFF_PARSE_TRIPLE(center);                             \
  |  |  ------------------
  |  |  |  |   93|      0|    AI_NFF_PARSE_FLOAT(v[0])   \
  |  |  |  |  ------------------
  |  |  |  |  |  |   88|      0|    SkipSpaces(&sz, lineEnd);          \
  |  |  |  |  |  |   89|      0|    if (!IsLineEnd(*sz)) sz = fast_atoreal_move(sz, (ai_real &)f);
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  Branch (89:9): [True: 0, False: 0]
  |  |  |  |  |  |  ------------------
  |  |  |  |  ------------------
  |  |  |  |   94|      0|    AI_NFF_PARSE_FLOAT(v[1])   \
  |  |  |  |  ------------------
  |  |  |  |  |  |   88|      0|    SkipSpaces(&sz, lineEnd);          \
  |  |  |  |  |  |   89|      0|    if (!IsLineEnd(*sz)) sz = fast_atoreal_move(sz, (ai_real &)f);
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  Branch (89:9): [True: 0, False: 0]
  |  |  |  |  |  |  ------------------
  |  |  |  |  ------------------
  |  |  |  |   95|      0|    AI_NFF_PARSE_FLOAT(v[2])
  |  |  |  |  ------------------
  |  |  |  |  |  |   88|      0|    SkipSpaces(&sz, lineEnd);          \
  |  |  |  |  |  |   89|      0|    if (!IsLineEnd(*sz)) sz = fast_atoreal_move(sz, (ai_real &)f);
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  Branch (89:9): [True: 0, False: 0]
  |  |  |  |  |  |  ------------------
  |  |  |  |  ------------------
  |  |  ------------------
  |  |  101|      0|    AI_NFF_PARSE_TRIPLE(radius);                             \
  |  |  ------------------
  |  |  |  |   93|      0|    AI_NFF_PARSE_FLOAT(v[0])   \
  |  |  |  |  ------------------
  |  |  |  |  |  |   88|      0|    SkipSpaces(&sz, lineEnd);          \
  |  |  |  |  |  |   89|      0|    if (!IsLineEnd(*sz)) sz = fast_atoreal_move(sz, (ai_real &)f);
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  Branch (89:9): [True: 0, False: 0]
  |  |  |  |  |  |  ------------------
  |  |  |  |  ------------------
  |  |  |  |   94|      0|    AI_NFF_PARSE_FLOAT(v[1])   \
  |  |  |  |  ------------------
  |  |  |  |  |  |   88|      0|    SkipSpaces(&sz, lineEnd);          \
  |  |  |  |  |  |   89|      0|    if (!IsLineEnd(*sz)) sz = fast_atoreal_move(sz, (ai_real &)f);
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  Branch (89:9): [True: 0, False: 0]
  |  |  |  |  |  |  ------------------
  |  |  |  |  ------------------
  |  |  |  |   95|      0|    AI_NFF_PARSE_FLOAT(v[2])
  |  |  |  |  ------------------
  |  |  |  |  |  |   88|      0|    SkipSpaces(&sz, lineEnd);          \
  |  |  |  |  |  |   89|      0|    if (!IsLineEnd(*sz)) sz = fast_atoreal_move(sz, (ai_real &)f);
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  Branch (89:9): [True: 0, False: 0]
  |  |  |  |  |  |  ------------------
  |  |  |  |  ------------------
  |  |  ------------------
  |  |  102|      0|    if (is_qnan(radius.z)) radius.z = radius.x;              \
  |  |  ------------------
  |  |  |  Branch (102:9): [True: 0, False: 0]
  |  |  ------------------
  |  |  103|      0|    if (is_qnan(radius.y)) radius.y = radius.x;              \
  |  |  ------------------
  |  |  |  Branch (103:9): [True: 0, False: 0]
  |  |  ------------------
  |  |  104|      0|    curMesh.radius = radius;                                 \
  |  |  105|      0|    curMesh.center = center;
  ------------------
  822|       |
  823|       |                // we don't need scaling or translation here - we do it in the node's transform
  824|      0|                StandardShapes::MakeHexahedron(curMesh.vertices);
  825|      0|                curMesh.faces.resize(curMesh.vertices.size() / 3, 3);
  826|       |
  827|       |                // generate a name for the mesh
  828|      0|                ::ai_snprintf(curMesh.name, MeshInfo::MaxNameLen, "hexahedron_%i", hexahedron++);
  829|      0|            }
  830|       |            // 'c' - cone
  831|  6.98k|            else if (TokenMatch(sz, "c", 1)) {
  ------------------
  |  Branch (831:22): [True: 0, False: 6.98k]
  ------------------
  832|      0|                meshesLocked.emplace_back(PatchType_Simple, true);
  833|      0|                MeshInfo &curMesh = meshesLocked.back();
  834|      0|                curMesh.shader = s;
  835|      0|                curMesh.shader.mapping = aiTextureMapping_CYLINDER;
  836|       |
  837|      0|                if (!GetNextLine(buffer, line)) {
  ------------------
  |  Branch (837:21): [True: 0, False: 0]
  ------------------
  838|      0|                    ASSIMP_LOG_ERROR("NFF: Unexpected end of file (cone definition not complete)");
  839|      0|                    break;
  840|      0|                }
  841|      0|                sz = line;
  842|       |
  843|       |                // read the two center points and the respective radii
  844|      0|                aiVector3D center1, center2;
  845|      0|                ai_real radius1 = 0.f, radius2 = 0.f;
  846|      0|                AI_NFF_PARSE_TRIPLE(center1);
  ------------------
  |  |   93|      0|    AI_NFF_PARSE_FLOAT(v[0])   \
  |  |  ------------------
  |  |  |  |   88|      0|    SkipSpaces(&sz, lineEnd);          \
  |  |  |  |   89|      0|    if (!IsLineEnd(*sz)) sz = fast_atoreal_move(sz, (ai_real &)f);
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (89:9): [True: 0, False: 0]
  |  |  |  |  ------------------
  |  |  ------------------
  |  |   94|      0|    AI_NFF_PARSE_FLOAT(v[1])   \
  |  |  ------------------
  |  |  |  |   88|      0|    SkipSpaces(&sz, lineEnd);          \
  |  |  |  |   89|      0|    if (!IsLineEnd(*sz)) sz = fast_atoreal_move(sz, (ai_real &)f);
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (89:9): [True: 0, False: 0]
  |  |  |  |  ------------------
  |  |  ------------------
  |  |   95|      0|    AI_NFF_PARSE_FLOAT(v[2])
  |  |  ------------------
  |  |  |  |   88|      0|    SkipSpaces(&sz, lineEnd);          \
  |  |  |  |   89|      0|    if (!IsLineEnd(*sz)) sz = fast_atoreal_move(sz, (ai_real &)f);
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (89:9): [True: 0, False: 0]
  |  |  |  |  ------------------
  |  |  ------------------
  ------------------
  847|      0|                AI_NFF_PARSE_FLOAT(radius1);
  ------------------
  |  |   88|      0|    SkipSpaces(&sz, lineEnd);          \
  |  |   89|      0|    if (!IsLineEnd(*sz)) sz = fast_atoreal_move(sz, (ai_real &)f);
  |  |  ------------------
  |  |  |  Branch (89:9): [True: 0, False: 0]
  |  |  ------------------
  ------------------
  848|       |
  849|      0|                if (!GetNextLine(buffer, line)) {
  ------------------
  |  Branch (849:21): [True: 0, False: 0]
  ------------------
  850|      0|                    ASSIMP_LOG_ERROR("NFF: Unexpected end of file (cone definition not complete)");
  851|      0|                    break;
  852|      0|                }
  853|      0|                sz = line;
  854|       |
  855|      0|                AI_NFF_PARSE_TRIPLE(center2);
  ------------------
  |  |   93|      0|    AI_NFF_PARSE_FLOAT(v[0])   \
  |  |  ------------------
  |  |  |  |   88|      0|    SkipSpaces(&sz, lineEnd);          \
  |  |  |  |   89|      0|    if (!IsLineEnd(*sz)) sz = fast_atoreal_move(sz, (ai_real &)f);
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (89:9): [True: 0, False: 0]
  |  |  |  |  ------------------
  |  |  ------------------
  |  |   94|      0|    AI_NFF_PARSE_FLOAT(v[1])   \
  |  |  ------------------
  |  |  |  |   88|      0|    SkipSpaces(&sz, lineEnd);          \
  |  |  |  |   89|      0|    if (!IsLineEnd(*sz)) sz = fast_atoreal_move(sz, (ai_real &)f);
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (89:9): [True: 0, False: 0]
  |  |  |  |  ------------------
  |  |  ------------------
  |  |   95|      0|    AI_NFF_PARSE_FLOAT(v[2])
  |  |  ------------------
  |  |  |  |   88|      0|    SkipSpaces(&sz, lineEnd);          \
  |  |  |  |   89|      0|    if (!IsLineEnd(*sz)) sz = fast_atoreal_move(sz, (ai_real &)f);
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (89:9): [True: 0, False: 0]
  |  |  |  |  ------------------
  |  |  ------------------
  ------------------
  856|      0|                AI_NFF_PARSE_FLOAT(radius2);
  ------------------
  |  |   88|      0|    SkipSpaces(&sz, lineEnd);          \
  |  |   89|      0|    if (!IsLineEnd(*sz)) sz = fast_atoreal_move(sz, (ai_real &)f);
  |  |  ------------------
  |  |  |  Branch (89:9): [True: 0, False: 0]
  |  |  ------------------
  ------------------
  857|       |
  858|       |                // compute the center point of the cone/cylinder -
  859|       |                // it is its local transformation origin
  860|      0|                curMesh.dir = center2 - center1;
  861|      0|                curMesh.center = center1 + curMesh.dir / (ai_real)2.0;
  862|       |
  863|      0|                ai_real f;
  864|      0|                if ((f = curMesh.dir.Length()) < 10e-3f) {
  ------------------
  |  Branch (864:21): [True: 0, False: 0]
  ------------------
  865|      0|                    ASSIMP_LOG_ERROR("NFF: Cone height is close to zero");
  866|      0|                    continue;
  867|      0|                }
  868|      0|                curMesh.dir /= f; // normalize
  869|       |
  870|       |                // generate the cone - it consists of simple triangles
  871|      0|                StandardShapes::MakeCone(f, radius1, radius2,
  872|      0|                        integer_pow(4, iTesselation), curMesh.vertices);
  873|       |
  874|       |                // MakeCone() returns tris
  875|      0|                curMesh.faces.resize(curMesh.vertices.size() / 3, 3);
  876|       |
  877|       |                // generate a name for the mesh. 'cone' if it a cone,
  878|       |                // 'cylinder' if it is a cylinder. Funny, isn't it?
  879|      0|                if (radius1 != radius2) {
  ------------------
  |  Branch (879:21): [True: 0, False: 0]
  ------------------
  880|      0|                    ::ai_snprintf(curMesh.name, MeshInfo::MaxNameLen, "cone_%i", cone++);
  881|      0|                } else {
  882|      0|                    ::ai_snprintf(curMesh.name, MeshInfo::MaxNameLen, "cylinder_%i", cylinder++);
  883|      0|                }
  884|      0|            }
  885|       |            // 'tess' - tessellation
  886|  6.98k|            else if (TokenMatch(sz, "tess", 4)) {
  ------------------
  |  Branch (886:22): [True: 0, False: 6.98k]
  ------------------
  887|      0|                SkipSpaces(&sz, lineEnd);
  888|      0|                iTesselation = strtoul10(sz);
  889|      0|            }
  890|       |            // 'from' - camera position
  891|  6.98k|            else if (TokenMatch(sz, "from", 4)) {
  ------------------
  |  Branch (891:22): [True: 0, False: 6.98k]
  ------------------
  892|      0|                AI_NFF_PARSE_TRIPLE(camPos);
  ------------------
  |  |   93|      0|    AI_NFF_PARSE_FLOAT(v[0])   \
  |  |  ------------------
  |  |  |  |   88|      0|    SkipSpaces(&sz, lineEnd);          \
  |  |  |  |   89|      0|    if (!IsLineEnd(*sz)) sz = fast_atoreal_move(sz, (ai_real &)f);
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (89:9): [True: 0, False: 0]
  |  |  |  |  ------------------
  |  |  ------------------
  |  |   94|      0|    AI_NFF_PARSE_FLOAT(v[1])   \
  |  |  ------------------
  |  |  |  |   88|      0|    SkipSpaces(&sz, lineEnd);          \
  |  |  |  |   89|      0|    if (!IsLineEnd(*sz)) sz = fast_atoreal_move(sz, (ai_real &)f);
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (89:9): [True: 0, False: 0]
  |  |  |  |  ------------------
  |  |  ------------------
  |  |   95|      0|    AI_NFF_PARSE_FLOAT(v[2])
  |  |  ------------------
  |  |  |  |   88|      0|    SkipSpaces(&sz, lineEnd);          \
  |  |  |  |   89|      0|    if (!IsLineEnd(*sz)) sz = fast_atoreal_move(sz, (ai_real &)f);
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (89:9): [True: 0, False: 0]
  |  |  |  |  ------------------
  |  |  ------------------
  ------------------
  893|      0|                hasCam = true;
  894|      0|            }
  895|       |            // 'at' - camera look-at vector
  896|  6.98k|            else if (TokenMatch(sz, "at", 2)) {
  ------------------
  |  Branch (896:22): [True: 0, False: 6.98k]
  ------------------
  897|      0|                AI_NFF_PARSE_TRIPLE(camLookAt);
  ------------------
  |  |   93|      0|    AI_NFF_PARSE_FLOAT(v[0])   \
  |  |  ------------------
  |  |  |  |   88|      0|    SkipSpaces(&sz, lineEnd);          \
  |  |  |  |   89|      0|    if (!IsLineEnd(*sz)) sz = fast_atoreal_move(sz, (ai_real &)f);
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (89:9): [True: 0, False: 0]
  |  |  |  |  ------------------
  |  |  ------------------
  |  |   94|      0|    AI_NFF_PARSE_FLOAT(v[1])   \
  |  |  ------------------
  |  |  |  |   88|      0|    SkipSpaces(&sz, lineEnd);          \
  |  |  |  |   89|      0|    if (!IsLineEnd(*sz)) sz = fast_atoreal_move(sz, (ai_real &)f);
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (89:9): [True: 0, False: 0]
  |  |  |  |  ------------------
  |  |  ------------------
  |  |   95|      0|    AI_NFF_PARSE_FLOAT(v[2])
  |  |  ------------------
  |  |  |  |   88|      0|    SkipSpaces(&sz, lineEnd);          \
  |  |  |  |   89|      0|    if (!IsLineEnd(*sz)) sz = fast_atoreal_move(sz, (ai_real &)f);
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (89:9): [True: 0, False: 0]
  |  |  |  |  ------------------
  |  |  ------------------
  ------------------
  898|      0|                hasCam = true;
  899|      0|            }
  900|       |            // 'up' - camera up vector
  901|  6.98k|            else if (TokenMatch(sz, "up", 2)) {
  ------------------
  |  Branch (901:22): [True: 0, False: 6.98k]
  ------------------
  902|      0|                AI_NFF_PARSE_TRIPLE(camUp);
  ------------------
  |  |   93|      0|    AI_NFF_PARSE_FLOAT(v[0])   \
  |  |  ------------------
  |  |  |  |   88|      0|    SkipSpaces(&sz, lineEnd);          \
  |  |  |  |   89|      0|    if (!IsLineEnd(*sz)) sz = fast_atoreal_move(sz, (ai_real &)f);
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (89:9): [True: 0, False: 0]
  |  |  |  |  ------------------
  |  |  ------------------
  |  |   94|      0|    AI_NFF_PARSE_FLOAT(v[1])   \
  |  |  ------------------
  |  |  |  |   88|      0|    SkipSpaces(&sz, lineEnd);          \
  |  |  |  |   89|      0|    if (!IsLineEnd(*sz)) sz = fast_atoreal_move(sz, (ai_real &)f);
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (89:9): [True: 0, False: 0]
  |  |  |  |  ------------------
  |  |  ------------------
  |  |   95|      0|    AI_NFF_PARSE_FLOAT(v[2])
  |  |  ------------------
  |  |  |  |   88|      0|    SkipSpaces(&sz, lineEnd);          \
  |  |  |  |   89|      0|    if (!IsLineEnd(*sz)) sz = fast_atoreal_move(sz, (ai_real &)f);
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (89:9): [True: 0, False: 0]
  |  |  |  |  ------------------
  |  |  ------------------
  ------------------
  903|      0|                hasCam = true;
  904|      0|            }
  905|       |            // 'angle' - (half?) camera field of view
  906|  6.98k|            else if (TokenMatch(sz, "angle", 5)) {
  ------------------
  |  Branch (906:22): [True: 0, False: 6.98k]
  ------------------
  907|      0|                AI_NFF_PARSE_FLOAT(angle);
  ------------------
  |  |   88|      0|    SkipSpaces(&sz, lineEnd);          \
  |  |   89|      0|    if (!IsLineEnd(*sz)) sz = fast_atoreal_move(sz, (ai_real &)f);
  |  |  ------------------
  |  |  |  Branch (89:9): [True: 0, False: 0]
  |  |  ------------------
  ------------------
  908|      0|                hasCam = true;
  909|      0|            }
  910|       |            // 'resolution' - used to compute the screen aspect
  911|  6.98k|            else if (TokenMatch(sz, "resolution", 10)) {
  ------------------
  |  Branch (911:22): [True: 0, False: 6.98k]
  ------------------
  912|      0|                AI_NFF_PARSE_FLOAT(resolution.x);
  ------------------
  |  |   88|      0|    SkipSpaces(&sz, lineEnd);          \
  |  |   89|      0|    if (!IsLineEnd(*sz)) sz = fast_atoreal_move(sz, (ai_real &)f);
  |  |  ------------------
  |  |  |  Branch (89:9): [True: 0, False: 0]
  |  |  ------------------
  ------------------
  913|      0|                AI_NFF_PARSE_FLOAT(resolution.y);
  ------------------
  |  |   88|      0|    SkipSpaces(&sz, lineEnd);          \
  |  |   89|      0|    if (!IsLineEnd(*sz)) sz = fast_atoreal_move(sz, (ai_real &)f);
  |  |  ------------------
  |  |  |  Branch (89:9): [True: 0, False: 0]
  |  |  ------------------
  ------------------
  914|      0|                hasCam = true;
  915|      0|            }
  916|       |            // 'pb' - bezier patch. Not supported yet
  917|  6.98k|            else if (TokenMatch(sz, "pb", 2)) {
  ------------------
  |  Branch (917:22): [True: 0, False: 6.98k]
  ------------------
  918|      0|                ASSIMP_LOG_ERROR("NFF: Encountered unsupported ID: bezier patch");
  919|      0|            }
  920|       |            // 'pn' - NURBS. Not supported yet
  921|  6.98k|            else if (TokenMatch(sz, "pn", 2) || TokenMatch(sz, "pnn", 3)) {
  ------------------
  |  Branch (921:22): [True: 0, False: 6.98k]
  |  Branch (921:49): [True: 0, False: 6.98k]
  ------------------
  922|      0|                ASSIMP_LOG_ERROR("NFF: Encountered unsupported ID: NURBS");
  923|      0|            }
  924|       |            // '' - comment
  925|  6.98k|            else if ('#' == line[0]) {
  ------------------
  |  Branch (925:22): [True: 0, False: 6.98k]
  ------------------
  926|      0|                const char *space;
  927|      0|                SkipSpaces(&line[1], &space, lineEnd);
  928|      0|                if (!IsLineEnd(*space)) {
  ------------------
  |  Branch (928:21): [True: 0, False: 0]
  ------------------
  929|      0|                    ASSIMP_LOG_INFO(space);
  930|      0|                }
  931|      0|            }
  932|  8.75k|        }
  933|      9|    }
  934|       |
  935|       |    // copy all arrays into one large
  936|      9|    meshes.reserve(meshes.size() + meshesLocked.size() + meshesWithNormals.size() + meshesWithUVCoords.size());
  937|      9|    meshes.insert(meshes.end(), meshesLocked.begin(), meshesLocked.end());
  938|      9|    meshes.insert(meshes.end(), meshesWithNormals.begin(), meshesWithNormals.end());
  939|      9|    meshes.insert(meshes.end(), meshesWithUVCoords.begin(), meshesWithUVCoords.end());
  940|       |
  941|       |    // now generate output meshes. first find out how many meshes we'll need
  942|      9|    std::vector<MeshInfo>::const_iterator it = meshes.begin(), end = meshes.end();
  943|  1.59k|    for (; it != end; ++it) {
  ------------------
  |  Branch (943:12): [True: 1.59k, False: 9]
  ------------------
  944|  1.59k|        if (!(*it).faces.empty()) {
  ------------------
  |  Branch (944:13): [True: 1.59k, False: 0]
  ------------------
  945|  1.59k|            ++pScene->mNumMeshes;
  946|  1.59k|            if ((*it).name[0]) ++numNamed;
  ------------------
  |  Branch (946:17): [True: 1.59k, False: 0]
  ------------------
  947|  1.59k|        }
  948|  1.59k|    }
  949|       |
  950|       |    // generate a dummy root node - assign all unnamed elements such
  951|       |    // as polygons and polygon patches to the root node and generate
  952|       |    // sub nodes for named objects such as spheres and cones.
  953|      9|    aiNode *const root = new aiNode();
  954|      9|    root->mName.Set("<NFF_Root>");
  955|      9|    root->mNumChildren = numNamed + (hasCam ? 1 : 0) + (unsigned int)lights.size();
  ------------------
  |  Branch (955:38): [True: 0, False: 9]
  ------------------
  956|      9|    root->mNumMeshes = pScene->mNumMeshes - numNamed;
  957|       |
  958|      9|    aiNode **ppcChildren = nullptr;
  959|      9|    unsigned int *pMeshes = nullptr;
  960|      9|    if (root->mNumMeshes)
  ------------------
  |  Branch (960:9): [True: 0, False: 9]
  ------------------
  961|      0|        pMeshes = root->mMeshes = new unsigned int[root->mNumMeshes];
  962|      9|    if (root->mNumChildren)
  ------------------
  |  Branch (962:9): [True: 3, False: 6]
  ------------------
  963|      3|        ppcChildren = root->mChildren = new aiNode *[root->mNumChildren];
  964|       |
  965|       |    // generate the camera
  966|      9|    if (hasCam) {
  ------------------
  |  Branch (966:9): [True: 0, False: 9]
  ------------------
  967|      0|        ai_assert(ppcChildren);
  968|      0|        aiNode *nd = new aiNode();
  969|      0|        *ppcChildren = nd;
  970|      0|        nd->mName.Set("<NFF_Camera>");
  971|      0|        nd->mParent = root;
  972|       |
  973|       |        // allocate the camera in the scene
  974|      0|        pScene->mNumCameras = 1;
  975|      0|        pScene->mCameras = new aiCamera *[1];
  976|      0|        aiCamera *c = pScene->mCameras[0] = new aiCamera;
  977|       |
  978|      0|        c->mName = nd->mName; // make sure the names are identical
  979|      0|        c->mHorizontalFOV = AI_DEG_TO_RAD(angle);
  980|      0|        c->mLookAt = camLookAt - camPos;
  981|      0|        c->mPosition = camPos;
  982|      0|        c->mUp = camUp;
  983|       |
  984|       |        // If the resolution is not specified in the file, we
  985|       |        // need to set 1.0 as aspect.
  986|      0|        c->mAspect = (!resolution.y ? 0.f : resolution.x / resolution.y);
  ------------------
  |  Branch (986:23): [True: 0, False: 0]
  ------------------
  987|      0|        ++ppcChildren;
  988|      0|    }
  989|       |
  990|       |    // generate light sources
  991|      9|    if (!lights.empty()) {
  ------------------
  |  Branch (991:9): [True: 0, False: 9]
  ------------------
  992|      0|        ai_assert(ppcChildren);
  993|      0|        pScene->mNumLights = (unsigned int)lights.size();
  994|      0|        pScene->mLights = new aiLight *[pScene->mNumLights];
  995|      0|        for (unsigned int i = 0; i < pScene->mNumLights; ++i, ++ppcChildren) {
  ------------------
  |  Branch (995:34): [True: 0, False: 0]
  ------------------
  996|      0|            const Light &l = lights[i];
  997|       |
  998|      0|            aiNode *nd = new aiNode();
  999|      0|            *ppcChildren = nd;
 1000|      0|            nd->mParent = root;
 1001|       |
 1002|      0|            nd->mName.length = ::ai_snprintf(nd->mName.data, 1024, "<NFF_Light%u>", i);
 1003|       |
 1004|       |            // allocate the light in the scene data structure
 1005|      0|            aiLight *out = pScene->mLights[i] = new aiLight();
 1006|      0|            out->mName = nd->mName; // make sure the names are identical
 1007|      0|            out->mType = aiLightSource_POINT;
 1008|      0|            out->mColorDiffuse = out->mColorSpecular = l.color * l.intensity;
 1009|      0|            out->mPosition = l.position;
 1010|      0|        }
 1011|      0|    }
 1012|       |
 1013|      9|    if (!pScene->mNumMeshes) throw DeadlyImportError("NFF: No meshes loaded");
  ------------------
  |  Branch (1013:9): [True: 0, False: 9]
  ------------------
 1014|      9|    pScene->mMeshes = new aiMesh *[pScene->mNumMeshes];
 1015|      9|    pScene->mMaterials = new aiMaterial *[pScene->mNumMaterials = pScene->mNumMeshes];
 1016|      9|    unsigned int m = 0;
 1017|  1.59k|    for (it = meshes.begin(); it != end; ++it) {
  ------------------
  |  Branch (1017:31): [True: 1.59k, False: 9]
  ------------------
 1018|  1.59k|        if ((*it).faces.empty()) continue;
  ------------------
  |  Branch (1018:13): [True: 0, False: 1.59k]
  ------------------
 1019|       |
 1020|  1.59k|        const MeshInfo &src = *it;
 1021|  1.59k|        aiMesh *const mesh = pScene->mMeshes[m] = new aiMesh();
 1022|  1.59k|        mesh->mNumVertices = (unsigned int)src.vertices.size();
 1023|  1.59k|        mesh->mNumFaces = (unsigned int)src.faces.size();
 1024|       |
 1025|       |        // Generate sub nodes for named meshes
 1026|  1.59k|        if (src.name[0] && nullptr != ppcChildren) {
  ------------------
  |  Branch (1026:13): [True: 1.59k, False: 0]
  |  Branch (1026:28): [True: 1.59k, False: 0]
  ------------------
 1027|  1.59k|            aiNode *const node = *ppcChildren = new aiNode();
 1028|  1.59k|            node->mParent = root;
 1029|  1.59k|            node->mNumMeshes = 1;
 1030|  1.59k|            node->mMeshes = new unsigned int[1];
 1031|  1.59k|            node->mMeshes[0] = m;
 1032|  1.59k|            node->mName.Set(src.name);
 1033|       |
 1034|       |            // setup the transformation matrix of the node
 1035|  1.59k|            aiMatrix4x4::FromToMatrix(aiVector3D(0.f, 1.f, 0.f),
 1036|  1.59k|                    src.dir, node->mTransformation);
 1037|       |
 1038|  1.59k|            aiMatrix4x4 &mat = node->mTransformation;
 1039|  1.59k|            mat.a1 *= src.radius.x;
 1040|  1.59k|            mat.b1 *= src.radius.x;
 1041|  1.59k|            mat.c1 *= src.radius.x;
 1042|  1.59k|            mat.a2 *= src.radius.y;
 1043|  1.59k|            mat.b2 *= src.radius.y;
 1044|  1.59k|            mat.c2 *= src.radius.y;
 1045|  1.59k|            mat.a3 *= src.radius.z;
 1046|  1.59k|            mat.b3 *= src.radius.z;
 1047|  1.59k|            mat.c3 *= src.radius.z;
 1048|  1.59k|            mat.a4 = src.center.x;
 1049|  1.59k|            mat.b4 = src.center.y;
 1050|  1.59k|            mat.c4 = src.center.z;
 1051|       |
 1052|  1.59k|            ++ppcChildren;
 1053|  1.59k|        } else {
 1054|      0|            *pMeshes++ = m;
 1055|      0|        }
 1056|       |
 1057|       |        // copy vertex positions
 1058|  1.59k|        mesh->mVertices = new aiVector3D[mesh->mNumVertices];
 1059|  1.59k|        ::memcpy(mesh->mVertices, &src.vertices[0],
 1060|  1.59k|                sizeof(aiVector3D) * mesh->mNumVertices);
 1061|       |
 1062|       |        // NFF2: there could be vertex colors
 1063|  1.59k|        if (!src.colors.empty()) {
  ------------------
  |  Branch (1063:13): [True: 0, False: 1.59k]
  ------------------
 1064|      0|            ai_assert(src.colors.size() == src.vertices.size());
 1065|       |
 1066|       |            // copy vertex colors
 1067|      0|            mesh->mColors[0] = new aiColor4D[mesh->mNumVertices];
 1068|      0|            ::memcpy(mesh->mColors[0], &src.colors[0],
 1069|      0|                    sizeof(aiColor4D) * mesh->mNumVertices);
 1070|      0|        }
 1071|       |
 1072|  1.59k|        if (!src.normals.empty()) {
  ------------------
  |  Branch (1072:13): [True: 0, False: 1.59k]
  ------------------
 1073|      0|            ai_assert(src.normals.size() == src.vertices.size());
 1074|       |
 1075|       |            // copy normal vectors
 1076|      0|            mesh->mNormals = new aiVector3D[mesh->mNumVertices];
 1077|      0|            ::memcpy(mesh->mNormals, &src.normals[0],
 1078|      0|                    sizeof(aiVector3D) * mesh->mNumVertices);
 1079|      0|        }
 1080|       |
 1081|  1.59k|        if (!src.uvs.empty()) {
  ------------------
  |  Branch (1081:13): [True: 0, False: 1.59k]
  ------------------
 1082|      0|            ai_assert(src.uvs.size() == src.vertices.size());
 1083|       |
 1084|       |            // copy texture coordinates
 1085|      0|            mesh->mTextureCoords[0] = new aiVector3D[mesh->mNumVertices];
 1086|      0|            ::memcpy(mesh->mTextureCoords[0], &src.uvs[0],
 1087|      0|                    sizeof(aiVector3D) * mesh->mNumVertices);
 1088|      0|        }
 1089|       |
 1090|       |        // generate faces
 1091|  1.59k|        unsigned int p = 0;
 1092|  1.59k|        aiFace *pFace = mesh->mFaces = new aiFace[mesh->mNumFaces];
 1093|  1.59k|        for (std::vector<unsigned int>::const_iterator it2 = src.faces.begin(),
 1094|  1.59k|                                                       end2 = src.faces.end();
 1095|  58.8k|                it2 != end2; ++it2, ++pFace) {
  ------------------
  |  Branch (1095:17): [True: 57.2k, False: 1.59k]
  ------------------
 1096|  57.2k|            pFace->mIndices = new unsigned int[pFace->mNumIndices = *it2];
 1097|   228k|            for (unsigned int o = 0; o < pFace->mNumIndices; ++o)
  ------------------
  |  Branch (1097:38): [True: 171k, False: 57.2k]
  ------------------
 1098|   171k|                pFace->mIndices[o] = p++;
 1099|  57.2k|        }
 1100|       |
 1101|       |        // generate a material for the mesh
 1102|  1.59k|        aiMaterial *pcMat = (aiMaterial *)(pScene->mMaterials[m] = new aiMaterial());
 1103|       |
 1104|  1.59k|        mesh->mMaterialIndex = m++;
 1105|       |
 1106|  1.59k|        aiString matName;
 1107|  1.59k|        matName.Set(AI_DEFAULT_MATERIAL_NAME);
 1108|  1.59k|        pcMat->AddProperty(&matName, AI_MATKEY_NAME);
 1109|       |
 1110|       |        // FIX: Ignore diffuse == 0
 1111|  1.59k|        aiColor3D c = src.shader.color * (src.shader.diffuse.r ? src.shader.diffuse : aiColor3D(1.f, 1.f, 1.f));
  ------------------
  |  Branch (1111:43): [True: 1.59k, False: 0]
  ------------------
 1112|  1.59k|        pcMat->AddProperty(&c, 1, AI_MATKEY_COLOR_DIFFUSE);
 1113|  1.59k|        c = src.shader.color * src.shader.specular;
 1114|  1.59k|        pcMat->AddProperty(&c, 1, AI_MATKEY_COLOR_SPECULAR);
 1115|       |
 1116|       |        // NFF2 - default values for NFF
 1117|  1.59k|        pcMat->AddProperty(&src.shader.ambient, 1, AI_MATKEY_COLOR_AMBIENT);
 1118|  1.59k|        pcMat->AddProperty(&src.shader.emissive, 1, AI_MATKEY_COLOR_EMISSIVE);
 1119|  1.59k|        pcMat->AddProperty(&src.shader.opacity, 1, AI_MATKEY_OPACITY);
 1120|       |
 1121|       |        // setup the first texture layer, if existing
 1122|  1.59k|        if (src.shader.texFile.length()) {
  ------------------
  |  Branch (1122:13): [True: 0, False: 1.59k]
  ------------------
 1123|      0|            matName.Set(src.shader.texFile);
 1124|      0|            pcMat->AddProperty(&matName, AI_MATKEY_TEXTURE_DIFFUSE(0));
 1125|       |
 1126|      0|            if (aiTextureMapping_UV != src.shader.mapping) {
  ------------------
  |  Branch (1126:17): [True: 0, False: 0]
  ------------------
 1127|       |
 1128|      0|                aiVector3D v(0.f, -1.f, 0.f);
 1129|      0|                pcMat->AddProperty(&v, 1, AI_MATKEY_TEXMAP_AXIS_DIFFUSE(0));
 1130|      0|                pcMat->AddProperty((int *)&src.shader.mapping, 1, AI_MATKEY_MAPPING_DIFFUSE(0));
 1131|      0|            }
 1132|      0|        }
 1133|       |
 1134|       |        // setup the name of the material
 1135|  1.59k|        if (src.shader.name.length()) {
  ------------------
  |  Branch (1135:13): [True: 0, False: 1.59k]
  ------------------
 1136|      0|            matName.Set(src.shader.texFile);
 1137|      0|            pcMat->AddProperty(&matName, AI_MATKEY_NAME);
 1138|      0|        }
 1139|       |
 1140|       |        // setup some more material properties that are specific to NFF2
 1141|  1.59k|        int i;
 1142|  1.59k|        if (src.shader.twoSided) {
  ------------------
  |  Branch (1142:13): [True: 0, False: 1.59k]
  ------------------
 1143|      0|            i = 1;
 1144|      0|            pcMat->AddProperty(&i, 1, AI_MATKEY_TWOSIDED);
 1145|      0|        }
 1146|  1.59k|        i = (src.shader.shaded ? aiShadingMode_Gouraud : aiShadingMode_NoShading);
  ------------------
  |  Branch (1146:14): [True: 1.59k, False: 0]
  ------------------
 1147|  1.59k|        if (src.shader.shininess) {
  ------------------
  |  Branch (1147:13): [True: 0, False: 1.59k]
  ------------------
 1148|      0|            i = aiShadingMode_Phong;
 1149|      0|            pcMat->AddProperty(&src.shader.shininess, 1, AI_MATKEY_SHININESS);
 1150|      0|        }
 1151|       |        pcMat->AddProperty(&i, 1, AI_MATKEY_SHADING_MODEL);
 1152|  1.59k|    }
 1153|      9|    pScene->mRootNode = root;
 1154|      9|}

_ZN6Assimp11NFFImporterC2Ev:
   65|    624|    NFFImporter() = default;
_ZN6Assimp11NFFImporter11ShadingInfoC2Ev:
   93|  1.77k|                color(0.6f, 0.6f, 0.6f),
   94|  1.77k|                diffuse(1.f, 1.f, 1.f),
   95|  1.77k|                specular(1.f, 1.f, 1.f),
   96|  1.77k|                ambient(0.f, 0.f, 0.f),
   97|  1.77k|                emissive(0.f, 0.f, 0.f),
   98|  1.77k|                refracti(1.f),
   99|  1.77k|                twoSided(false), // for NFF2
  100|  1.77k|                shaded(true), // for NFF2
  101|  1.77k|                opacity(1.f),
  102|  1.77k|                shininess(0.f),
  103|  1.77k|                mapping(aiTextureMapping_UV) {
  104|       |            // empty
  105|  1.77k|        }
_ZN6Assimp11NFFImporter8MeshInfoC2ENS0_9PatchTypeEb:
  155|  1.77k|                pType(_pType), bLocked(bL), radius(1.f, 1.f, 1.f), dir(0.f, 1.f, 0.f), matIndex(0) {
  156|  1.77k|            name[0] = '\0'; // by default meshes are unnamed
  157|  1.77k|        }

_ZNK6Assimp11OFFImporter7CanReadERKNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEPNS_8IOSystemEb:
   75|    353|bool OFFImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool /*checkSig*/) const {
   76|    353|    static const char *tokens[] = { "off" };
   77|       |    return SearchFileHeaderForToken(pIOHandler, pFile, tokens, AI_COUNT_OF(tokens), 3);
   78|    353|}
_ZNK6Assimp11OFFImporter7GetInfoEv:
   81|    635|const aiImporterDesc *OFFImporter::GetInfo() const {
   82|    635|    return &desc;
   83|    635|}
_ZN6Assimp11OFFImporter14InternReadFileERKNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEP7aiScenePNS_8IOSystemE:
   96|      1|void OFFImporter::InternReadFile(const std::string &pFile, aiScene *pScene, IOSystem *pIOHandler) {
   97|      1|    std::unique_ptr<IOStream> file(pIOHandler->Open(pFile, "rb"));
   98|       |
   99|       |    // Check whether we can read from the file
  100|      1|    if (file == nullptr) {
  ------------------
  |  Branch (100:9): [True: 0, False: 1]
  ------------------
  101|      0|        throw DeadlyImportError("Failed to open OFF file ", pFile, ".");
  102|      0|    }
  103|       |
  104|       |    // allocate storage and copy the contents of the file to a memory buffer
  105|      1|    std::vector<char> mBuffer2;
  106|      1|    TextFileToBuffer(file.get(), mBuffer2);
  107|      1|    const char *buffer = &mBuffer2[0];
  108|       |
  109|       |    // Proper OFF header parser. We only implement normal loading for now.
  110|      1|    bool hasTexCoord = false, hasNormals = false, hasColors = false;
  111|      1|    bool hasHomogenous = false, hasDimension = false;
  112|      1|    unsigned int dimensions = 3;
  113|      1|    const char *car = buffer;
  114|      1|    const char *end = buffer + mBuffer2.size();
  115|      1|    NextToken(&car, end);
  116|       |
  117|      1|    if (car < end - 2 && car[0] == 'S' && car[1] == 'T') {
  ------------------
  |  Branch (117:9): [True: 1, False: 0]
  |  Branch (117:26): [True: 0, False: 1]
  |  Branch (117:43): [True: 0, False: 0]
  ------------------
  118|      0|        hasTexCoord = true;
  119|      0|        car += 2;
  120|      0|    }
  121|      1|    if (car < end - 1 && car[0] == 'C') {
  ------------------
  |  Branch (121:9): [True: 1, False: 0]
  |  Branch (121:26): [True: 0, False: 1]
  ------------------
  122|      0|        hasColors = true;
  123|      0|        car++;
  124|      0|    }
  125|      1|    if (car < end - 1 && car[0] == 'N') {
  ------------------
  |  Branch (125:9): [True: 1, False: 0]
  |  Branch (125:26): [True: 0, False: 1]
  ------------------
  126|      0|        hasNormals = true;
  127|      0|        car++;
  128|      0|    }
  129|      1|    if (car < end - 1 && car[0] == '4') {
  ------------------
  |  Branch (129:9): [True: 1, False: 0]
  |  Branch (129:26): [True: 0, False: 1]
  ------------------
  130|      0|        hasHomogenous = true;
  131|      0|        car++;
  132|      0|    }
  133|      1|    if (car < end - 1 && car[0] == 'n') {
  ------------------
  |  Branch (133:9): [True: 1, False: 0]
  |  Branch (133:26): [True: 0, False: 1]
  ------------------
  134|      0|        hasDimension = true;
  135|      0|        car++;
  136|      0|    }
  137|      1|    if (car < end - 3 && car[0] == 'O' && car[1] == 'F' && car[2] == 'F') {
  ------------------
  |  Branch (137:9): [True: 1, False: 0]
  |  Branch (137:26): [True: 1, False: 0]
  |  Branch (137:43): [True: 1, False: 0]
  |  Branch (137:60): [True: 1, False: 0]
  ------------------
  138|      1|        car += 3;
  139|      1|        NextToken(&car, end);
  140|      1|    } else {
  141|       |        // in case there is no OFF header (which is allowed by the
  142|       |        // specification...), then we might have unintentionally read an
  143|       |        // additional dimension from the primitive count fields
  144|      0|        dimensions = 3;
  145|      0|        hasHomogenous = false;
  146|      0|        NextToken(&car, end);
  147|       |
  148|       |        // at this point the next token should be an integer number
  149|      0|        if (car >= end - 1 || *car < '0' || *car > '9') {
  ------------------
  |  Branch (149:13): [True: 0, False: 0]
  |  Branch (149:31): [True: 0, False: 0]
  |  Branch (149:45): [True: 0, False: 0]
  ------------------
  150|      0|            throw DeadlyImportError("OFF: Header is invalid");
  151|      0|        }
  152|      0|    }
  153|      1|    if (hasDimension) {
  ------------------
  |  Branch (153:9): [True: 0, False: 1]
  ------------------
  154|      0|        dimensions = strtoul10(car, &car);
  155|      0|        NextToken(&car, end);
  156|      0|    }
  157|      1|    if (dimensions > 3) {
  ------------------
  |  Branch (157:9): [True: 0, False: 1]
  ------------------
  158|      0|        throw DeadlyImportError("OFF: Number of vertex coordinates higher than 3 unsupported");
  159|      0|    }
  160|       |
  161|      1|    NextToken(&car, end);
  162|      1|    const unsigned int numVertices = strtoul10(car, &car);
  163|      1|    NextToken(&car, end);
  164|      1|    const unsigned int numFaces = strtoul10(car, &car);
  165|      1|    NextToken(&car, end);
  166|      1|    strtoul10(car, &car); // skip edge count
  167|      1|    NextToken(&car, end);
  168|       |
  169|      1|    if (!numVertices) {
  ------------------
  |  Branch (169:9): [True: 0, False: 1]
  ------------------
  170|      0|        throw DeadlyImportError("OFF: There are no valid vertices");
  171|      0|    }
  172|      1|    if (!numFaces) {
  ------------------
  |  Branch (172:9): [True: 0, False: 1]
  ------------------
  173|      0|        throw DeadlyImportError("OFF: There are no valid faces");
  174|      0|    }
  175|       |
  176|      1|    pScene->mNumMeshes = 1;
  177|      1|    pScene->mMeshes = new aiMesh *[pScene->mNumMeshes];
  178|       |
  179|      1|    aiMesh *mesh = new aiMesh();
  180|      1|    pScene->mMeshes[0] = mesh;
  181|       |
  182|      1|    mesh->mNumFaces = numFaces;
  183|      1|    aiFace *faces = new aiFace[mesh->mNumFaces];
  184|      1|    mesh->mFaces = faces;
  185|       |
  186|      1|    mesh->mNumVertices = numVertices;
  187|      1|    mesh->mVertices = new aiVector3D[numVertices];
  188|      1|    mesh->mNormals = hasNormals ? new aiVector3D[numVertices] : nullptr;
  ------------------
  |  Branch (188:22): [True: 0, False: 1]
  ------------------
  189|      1|    mesh->mColors[0] = hasColors ? new aiColor4D[numVertices] : nullptr;
  ------------------
  |  Branch (189:24): [True: 0, False: 1]
  ------------------
  190|       |
  191|      1|    if (hasTexCoord) {
  ------------------
  |  Branch (191:9): [True: 0, False: 1]
  ------------------
  192|      0|        mesh->mNumUVComponents[0] = 2;
  193|      0|        mesh->mTextureCoords[0] = new aiVector3D[numVertices];
  194|      0|    }
  195|      1|    char line[4096];
  196|      1|    buffer = car;
  197|      1|    const char *sz = car;
  198|      1|    const char *lineEnd = &line[4096];
  199|       |
  200|       |    // now read all vertex lines
  201|  3.20k|    for (unsigned int i = 0; i < numVertices; ++i) {
  ------------------
  |  Branch (201:30): [True: 3.20k, False: 1]
  ------------------
  202|  3.20k|        if (!GetNextLine(buffer, line)) {
  ------------------
  |  Branch (202:13): [True: 0, False: 3.20k]
  ------------------
  203|      0|            ASSIMP_LOG_ERROR("OFF: The number of verts in the header is incorrect");
  204|      0|            break;
  205|      0|        }
  206|  3.20k|        aiVector3D &v = mesh->mVertices[i];
  207|  3.20k|        sz = line;
  208|       |
  209|       |        // helper array to write a for loop over possible dimension values
  210|  3.20k|        ai_real *vec[3] = { &v.x, &v.y, &v.z };
  211|       |
  212|       |        // stop at dimensions: this allows loading 1D or 2D coordinate vertices
  213|  12.8k|        for (unsigned int dim = 0; dim < dimensions; ++dim) {
  ------------------
  |  Branch (213:36): [True: 9.61k, False: 3.20k]
  ------------------
  214|  9.61k|            SkipSpaces(&sz, lineEnd);
  215|  9.61k|            sz = fast_atoreal_move(sz, *vec[dim]);
  216|  9.61k|        }
  217|       |
  218|       |        // if has homogeneous coordinate, divide others by this one
  219|  3.20k|        if (hasHomogenous) {
  ------------------
  |  Branch (219:13): [True: 0, False: 3.20k]
  ------------------
  220|      0|            SkipSpaces(&sz, lineEnd);
  221|      0|            ai_real w = 1.;
  222|      0|            sz = fast_atoreal_move(sz, w);
  223|      0|            for (unsigned int dim = 0; dim < dimensions; ++dim) {
  ------------------
  |  Branch (223:40): [True: 0, False: 0]
  ------------------
  224|      0|                *(vec[dim]) /= w;
  225|      0|            }
  226|      0|        }
  227|       |
  228|       |        // read optional normals
  229|  3.20k|        if (hasNormals) {
  ------------------
  |  Branch (229:13): [True: 0, False: 3.20k]
  ------------------
  230|      0|            aiVector3D &n = mesh->mNormals[i];
  231|      0|            SkipSpaces(&sz, lineEnd);
  232|      0|            sz = fast_atoreal_move(sz, n.x);
  233|      0|            SkipSpaces(&sz, lineEnd);
  234|      0|            sz = fast_atoreal_move(sz, n.y);
  235|      0|            SkipSpaces(&sz, lineEnd);
  236|      0|            fast_atoreal_move(sz, n.z);
  237|      0|        }
  238|       |
  239|       |        // reading colors is a pain because the specification says it can be
  240|       |        // integers or floats, and any number of them between 1 and 4 included,
  241|       |        // until the next comment or end of line
  242|       |        // in theory should be testing type !
  243|  3.20k|        if (hasColors) {
  ------------------
  |  Branch (243:13): [True: 0, False: 3.20k]
  ------------------
  244|      0|            aiColor4D &c = mesh->mColors[0][i];
  245|      0|            SkipSpaces(&sz, lineEnd);
  246|      0|            sz = fast_atoreal_move(sz, c.r);
  247|      0|            if (*sz != '#' && *sz != '\n' && *sz != '\r') {
  ------------------
  |  Branch (247:17): [True: 0, False: 0]
  |  Branch (247:31): [True: 0, False: 0]
  |  Branch (247:46): [True: 0, False: 0]
  ------------------
  248|      0|                SkipSpaces(&sz, lineEnd);
  249|      0|                sz = fast_atoreal_move(sz, c.g);
  250|      0|            } else {
  251|      0|                c.g = 0.;
  252|      0|            }
  253|      0|            if (*sz != '#' && *sz != '\n' && *sz != '\r') {
  ------------------
  |  Branch (253:17): [True: 0, False: 0]
  |  Branch (253:31): [True: 0, False: 0]
  |  Branch (253:46): [True: 0, False: 0]
  ------------------
  254|      0|                SkipSpaces(&sz, lineEnd);
  255|      0|                sz = fast_atoreal_move(sz, c.b);
  256|      0|            } else {
  257|      0|                c.b = 0.;
  258|      0|            }
  259|      0|            if (*sz != '#' && *sz != '\n' && *sz != '\r') {
  ------------------
  |  Branch (259:17): [True: 0, False: 0]
  |  Branch (259:31): [True: 0, False: 0]
  |  Branch (259:46): [True: 0, False: 0]
  ------------------
  260|      0|                SkipSpaces(&sz, lineEnd);
  261|      0|                sz = fast_atoreal_move(sz, c.a);
  262|      0|            } else {
  263|      0|                c.a = 1.;
  264|      0|            }
  265|      0|        }
  266|  3.20k|        if (hasTexCoord) {
  ------------------
  |  Branch (266:13): [True: 0, False: 3.20k]
  ------------------
  267|      0|            aiVector3D &t = mesh->mTextureCoords[0][i];
  268|      0|            SkipSpaces(&sz, lineEnd);
  269|      0|            sz = fast_atoreal_move(sz, t.x);
  270|      0|            SkipSpaces(&sz, lineEnd);
  271|      0|            fast_atoreal_move(sz, t.y);
  272|      0|        }
  273|  3.20k|    }
  274|       |
  275|       |    // load faces with their indices
  276|      1|    faces = mesh->mFaces;
  277|  3.73k|    for (unsigned int i = 0; i < numFaces;) {
  ------------------
  |  Branch (277:30): [True: 3.73k, False: 1]
  ------------------
  278|  3.73k|        if (!GetNextLine(buffer, line)) {
  ------------------
  |  Branch (278:13): [True: 0, False: 3.73k]
  ------------------
  279|      0|            ASSIMP_LOG_ERROR("OFF: The number of faces in the header is incorrect");
  280|      0|            throw DeadlyImportError("OFF: The number of faces in the header is incorrect");
  281|      0|        }
  282|  3.73k|        unsigned int idx;
  283|  3.73k|        sz = line;
  284|  3.73k|        SkipSpaces(&sz, lineEnd);
  285|  3.73k|        idx = strtoul10(sz, &sz);
  286|  3.73k|        if (!idx || idx > 9) {
  ------------------
  |  Branch (286:13): [True: 0, False: 3.73k]
  |  Branch (286:21): [True: 0, False: 3.73k]
  ------------------
  287|      0|            ASSIMP_LOG_ERROR("OFF: Faces with zero indices aren't allowed");
  288|      0|            --mesh->mNumFaces;
  289|      0|            ++i;
  290|      0|            continue;
  291|      0|        }
  292|  3.73k|        faces->mNumIndices = idx;
  293|  3.73k|        faces->mIndices = new unsigned int[faces->mNumIndices];
  294|  14.9k|        for (unsigned int m = 0; m < faces->mNumIndices; ++m) {
  ------------------
  |  Branch (294:34): [True: 11.1k, False: 3.73k]
  ------------------
  295|  11.1k|            SkipSpaces(&sz, lineEnd);
  296|  11.1k|            idx = strtoul10(sz, &sz);
  297|  11.1k|            if (idx >= numVertices) {
  ------------------
  |  Branch (297:17): [True: 0, False: 11.1k]
  ------------------
  298|      0|                ASSIMP_LOG_ERROR("OFF: Vertex index is out of range");
  299|      0|                idx = numVertices - 1;
  300|      0|            }
  301|  11.1k|            faces->mIndices[m] = idx;
  302|  11.1k|        }
  303|  3.73k|        ++i;
  304|  3.73k|        ++faces;
  305|  3.73k|    }
  306|       |
  307|       |    // generate the output node graph
  308|      1|    pScene->mRootNode = new aiNode();
  309|      1|    pScene->mRootNode->mName.Set("<OFFRoot>");
  310|      1|    pScene->mRootNode->mNumMeshes = 1;
  311|      1|    pScene->mRootNode->mMeshes = new unsigned int[pScene->mRootNode->mNumMeshes];
  312|      1|    pScene->mRootNode->mMeshes[0] = 0;
  313|       |
  314|       |    // generate a default material
  315|      1|    pScene->mNumMaterials = 1;
  316|      1|    pScene->mMaterials = new aiMaterial *[pScene->mNumMaterials];
  317|      1|    aiMaterial *pcMat = new aiMaterial();
  318|       |
  319|      1|    aiColor4D clr(0.6f, 0.6f, 0.6f, 1.0f);
  320|      1|    pcMat->AddProperty(&clr, 1, AI_MATKEY_COLOR_DIFFUSE);
  321|      1|    pScene->mMaterials[0] = pcMat;
  322|       |
  323|      1|    const int twosided = 1;
  324|       |    pcMat->AddProperty(&twosided, 1, AI_MATKEY_TWOSIDED);
  325|      1|}
OFFLoader.cpp:_ZN6AssimpL9NextTokenEPPKcS1_:
   86|      6|static void NextToken(const char **car, const char *end) {
   87|      6|    SkipSpacesAndLineEnd(car, end);
   88|      6|    while (*car < end && (**car == '#' || **car == '\n' || **car == '\r')) {
  ------------------
  |  Branch (88:12): [True: 6, False: 0]
  |  Branch (88:27): [True: 0, False: 6]
  |  Branch (88:43): [True: 0, False: 6]
  |  Branch (88:60): [True: 0, False: 6]
  ------------------
   89|      0|        SkipLine(car, end);
   90|      0|        SkipSpacesAndLineEnd(car, end);
   91|      0|    }
   92|      6|}

_ZN6Assimp11OFFImporterC2Ev:
   60|    624|    OFFImporter() = default;

_ZN6Assimp7ObjFile6ObjectD2Ev:
  110|  11.2k|    ~Object() {
  111|  11.2k|        for (std::vector<Object *>::iterator it = m_SubObjects.begin(); it != m_SubObjects.end(); ++it) {
  ------------------
  |  Branch (111:73): [True: 0, False: 11.2k]
  ------------------
  112|      0|            delete *it;
  113|      0|        }
  114|  11.2k|    }
_ZN6Assimp7ObjFile5ModelD2Ev:
  324|     88|    ~Model() {
  325|  11.2k|        for (auto & it : mObjects) {
  ------------------
  |  Branch (325:24): [True: 11.2k, False: 88]
  ------------------
  326|  11.2k|            delete it;
  327|  11.2k|        }
  328|  11.9k|        for (auto & Meshe : mMeshes) {
  ------------------
  |  Branch (328:27): [True: 11.9k, False: 88]
  ------------------
  329|  11.9k|            delete Meshe;
  330|  11.9k|        }
  331|    447|        for (auto & Group : mGroups) {
  ------------------
  |  Branch (331:27): [True: 447, False: 88]
  ------------------
  332|    447|            delete Group.second;
  333|    447|        }
  334|    519|        for (auto & it : mMaterialMap) {
  ------------------
  |  Branch (334:24): [True: 519, False: 88]
  ------------------
  335|    519|            delete it.second;
  336|    519|        }
  337|     88|    }
_ZN6Assimp7ObjFile4MeshD2Ev:
  258|  11.9k|    ~Mesh() {
  259|  11.9k|        for (std::vector<Face *>::iterator it = m_Faces.begin();
  260|  24.5k|                it != m_Faces.end(); ++it) {
  ------------------
  |  Branch (260:17): [True: 12.6k, False: 11.9k]
  ------------------
  261|  12.6k|            delete *it;
  262|  12.6k|        }
  263|  11.9k|    }
_ZN6Assimp7ObjFile4FaceD2Ev:
   84|  13.9k|    ~Face() = default;
_ZN6Assimp7ObjFile4FaceC2E15aiPrimitiveType:
   79|  13.9k|            mPrimitiveType(pt), m_vertices(), m_normals(), m_texturCoords(), m_pMaterial(nullptr) {
   80|       |        // empty
   81|  13.9k|    }
_ZN6Assimp7ObjFile8MaterialC2Ev:
  218|    519|    Material() {
  219|    519|        std::fill_n(clamp, static_cast<unsigned int>(TextureTypeCount), false);
  220|    519|    }
_ZN6Assimp7ObjFile4MeshC2ERKNSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEE:
  249|  11.9k|            m_name(name),
  250|  11.9k|            m_pMaterial(nullptr),
  251|  11.9k|            m_uiNumIndices(0),
  252|  11.9k|            m_uiMaterialIndex(NoMaterial),
  253|  11.9k|            m_hasNormals(false) {
  254|       |        memset(m_uiUVCoordinates, 0, sizeof(unsigned int) * AI_MAX_NUMBER_OF_TEXTURECOORDS);
  255|  11.9k|    }
_ZN6Assimp7ObjFile5ModelC2Ev:
  312|     88|            mModelName(),
  313|     88|            mCurrentObject(nullptr),
  314|     88|            mCurrentMaterial(nullptr),
  315|     88|            mDefaultMaterial(nullptr),
  316|     88|            mGroupFaceIDs(nullptr),
  317|     88|            mActiveGroup(),
  318|     88|            mTextureCoordDim(0),
  319|     88|            mCurrentMesh(nullptr) {
  320|       |        // empty
  321|     88|    }
_ZN6Assimp7ObjFile6ObjectC2Ev:
  107|  11.2k|    Object() = default;

_ZN6Assimp15ObjFileImporterC2Ev:
   79|    624|        m_Buffer(),
   80|    624|        m_pRootObject(nullptr),
   81|    624|        m_strAbsPath(std::string(1, DefaultIOSystem().getOsSeparator())) {
   82|       |    // empty
   83|    624|}
_ZN6Assimp15ObjFileImporterD2Ev:
   87|    624|ObjFileImporter::~ObjFileImporter() {
   88|    624|    delete m_pRootObject;
   89|    624|}
_ZNK6Assimp15ObjFileImporter7CanReadERKNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEPNS_8IOSystemEb:
   93|    558|bool ObjFileImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool /*checkSig*/) const {
   94|    558|    static const char *tokens[] = { "mtllib", "usemtl", "v ", "vt ", "vn ", "o ", "g ", "s ", "f " };
   95|       |    return BaseImporter::SearchFileHeaderForToken(pIOHandler, pFile, tokens, AI_COUNT_OF(tokens), 200, false, true);
   96|    558|}
_ZNK6Assimp15ObjFileImporter7GetInfoEv:
   99|    722|const aiImporterDesc *ObjFileImporter::GetInfo() const {
  100|    722|    return &desc;
  101|    722|}
_ZN6Assimp15ObjFileImporter14InternReadFileERKNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEP7aiScenePNS_8IOSystemE:
  105|     88|void ObjFileImporter::InternReadFile(const std::string &file, aiScene *pScene, IOSystem *pIOHandler) {
  106|     88|    if (m_pRootObject != nullptr) {
  ------------------
  |  Branch (106:9): [True: 0, False: 88]
  ------------------
  107|      0|        delete m_pRootObject;
  108|      0|        m_pRootObject = nullptr;
  109|      0|    }
  110|       |
  111|       |    // Read file into memory
  112|     88|    static constexpr char mode[] = "rb";
  113|     88|    auto streamCloser = [&](IOStream *pStream) {
  114|     88|        pIOHandler->Close(pStream);
  115|     88|    };
  116|     88|    std::unique_ptr<IOStream, decltype(streamCloser)> fileStream(pIOHandler->Open(file, mode), streamCloser);
  117|     88|    if (!fileStream) {
  ------------------
  |  Branch (117:9): [True: 0, False: 88]
  ------------------
  118|      0|        throw DeadlyImportError("Failed to open file ", file, ".");
  119|      0|    }
  120|       |
  121|       |    // Get the file-size and validate it, throwing an exception when fails
  122|     88|    size_t fileSize = fileStream->FileSize();
  123|     88|    if (fileSize < ObjMinSize) {
  ------------------
  |  Branch (123:9): [True: 0, False: 88]
  ------------------
  124|      0|        throw DeadlyImportError("OBJ-file is too small.");
  125|      0|    }
  126|       |
  127|     88|    IOStreamBuffer<char> streamedBuffer;
  128|     88|    streamedBuffer.open(fileStream.get());
  129|       |
  130|       |    // Allocate buffer and read file into it
  131|       |    //TextFileToBuffer( fileStream.get(),m_Buffer);
  132|       |
  133|       |    // Get the model name
  134|     88|    std::string modelName, folderName;
  135|     88|    std::string::size_type pos = file.find_last_of("\\/");
  136|     88|    if (pos != std::string::npos) {
  ------------------
  |  Branch (136:9): [True: 12, False: 76]
  ------------------
  137|     12|        modelName = file.substr(pos + 1, file.size() - pos - 1);
  138|     12|        folderName = file.substr(0, pos);
  139|     12|        if (!folderName.empty()) {
  ------------------
  |  Branch (139:13): [True: 12, False: 0]
  ------------------
  140|     12|            pIOHandler->PushDirectory(folderName);
  141|     12|        }
  142|     76|    } else {
  143|     76|        modelName = file;
  144|     76|    }
  145|       |
  146|       |    // parse the file into a temporary representation
  147|     88|    ObjFileParser parser(streamedBuffer, modelName, pIOHandler, m_progress, file);
  148|       |
  149|       |    // And create the proper return structures out of it
  150|     88|    CreateDataFromImport(parser.GetModel(), pScene);
  151|       |
  152|     88|    streamedBuffer.close();
  153|       |
  154|       |    // Clean up allocated storage for the next import
  155|     88|    m_Buffer.clear();
  156|       |
  157|       |    // Pop directory stack
  158|     88|    if (pIOHandler->StackSize() > 0) {
  ------------------
  |  Branch (158:9): [True: 9, False: 79]
  ------------------
  159|      9|        pIOHandler->PopDirectory();
  160|      9|    }
  161|     88|}
_ZN6Assimp15ObjFileImporter20CreateDataFromImportEPKNS_7ObjFile5ModelEP7aiScene:
  165|     78|void ObjFileImporter::CreateDataFromImport(const ObjFile::Model *pModel, aiScene *pScene) {
  166|     78|    if (pModel == nullptr) {
  ------------------
  |  Branch (166:9): [True: 0, False: 78]
  ------------------
  167|      0|        return;
  168|      0|    }
  169|       |
  170|       |    // Create the root node of the scene
  171|     78|    pScene->mRootNode = new aiNode;
  172|     78|    if (!pModel->mModelName.empty()) {
  ------------------
  |  Branch (172:9): [True: 78, False: 0]
  ------------------
  173|       |        // Set the name of the scene
  174|     78|        pScene->mRootNode->mName.Set(pModel->mModelName);
  175|     78|    } else {
  176|       |        // This is a fatal error, so break down the application
  177|      0|        ai_assert(false);
  ------------------
  |  |   67|      0|#   define ai_assert(expression) (void)((!!(expression)) || (Assimp::aiAssertViolation(#expression, __FILE__, __LINE__), 0))
  |  |  ------------------
  |  |  |  Branch (67:41): [Folded, False: 0]
  |  |  |  Branch (67:61): [True: 0, False: 0]
  |  |  ------------------
  ------------------
  178|      0|    }
  179|       |
  180|     78|    if (!pModel->mObjects.empty()) {
  ------------------
  |  Branch (180:9): [True: 56, False: 22]
  ------------------
  181|     56|        unsigned int meshCount = 0;
  182|     56|        unsigned int childCount = 0;
  183|       |
  184|  10.9k|        for (auto object : pModel->mObjects) {
  ------------------
  |  Branch (184:26): [True: 10.9k, False: 56]
  ------------------
  185|  10.9k|            if (object) {
  ------------------
  |  Branch (185:17): [True: 10.9k, False: 0]
  ------------------
  186|  10.9k|                ++childCount;
  187|  10.9k|                meshCount += (unsigned int)object->m_Meshes.size();
  188|  10.9k|            }
  189|  10.9k|        }
  190|       |
  191|       |        // Allocate space for the child nodes on the root node
  192|     56|        pScene->mRootNode->mChildren = new aiNode *[childCount];
  193|       |
  194|       |        // Create nodes for the whole scene
  195|     56|        std::vector<std::unique_ptr<aiMesh>> MeshArray;
  196|     56|        MeshArray.reserve(meshCount);
  197|  11.0k|        for (size_t index = 0; index < pModel->mObjects.size(); ++index) {
  ------------------
  |  Branch (197:32): [True: 10.9k, False: 56]
  ------------------
  198|  10.9k|            createNodes(pModel, pModel->mObjects[index], pScene->mRootNode, pScene, MeshArray);
  199|  10.9k|        }
  200|       |
  201|     56|        ai_assert(pScene->mRootNode->mNumChildren == childCount);
  ------------------
  |  |   67|     56|#   define ai_assert(expression) (void)((!!(expression)) || (Assimp::aiAssertViolation(#expression, __FILE__, __LINE__), 0))
  |  |  ------------------
  |  |  |  Branch (67:41): [True: 56, False: 0]
  |  |  |  Branch (67:61): [True: 0, False: 0]
  |  |  ------------------
  ------------------
  202|       |
  203|       |        // Create mesh pointer buffer for this scene
  204|     56|        if (pScene->mNumMeshes > 0) {
  ------------------
  |  Branch (204:13): [True: 43, False: 13]
  ------------------
  205|     43|            pScene->mMeshes = new aiMesh *[MeshArray.size()];
  206|  1.38k|            for (size_t index = 0; index < MeshArray.size(); ++index) {
  ------------------
  |  Branch (206:36): [True: 1.34k, False: 43]
  ------------------
  207|  1.34k|                pScene->mMeshes[index] = MeshArray[index].release();
  208|  1.34k|            }
  209|     43|        }
  210|       |
  211|       |        // Create all materials
  212|     56|        createMaterials(pModel, pScene);
  213|     56|    } else {
  214|     22|        if (pModel->mVertices.empty()) {
  ------------------
  |  Branch (214:13): [True: 22, False: 0]
  ------------------
  215|     22|            return;
  216|     22|        }
  217|       |
  218|      0|        std::unique_ptr<aiMesh> mesh(new aiMesh);
  219|      0|        mesh->mPrimitiveTypes = aiPrimitiveType_POINT;
  220|      0|        unsigned int n = (unsigned int)pModel->mVertices.size();
  221|      0|        mesh->mNumVertices = n;
  222|       |
  223|      0|        mesh->mVertices = new aiVector3D[n];
  224|      0|        memcpy(mesh->mVertices, pModel->mVertices.data(), n * sizeof(aiVector3D));
  225|       |
  226|      0|        if (!pModel->mNormals.empty()) {
  ------------------
  |  Branch (226:13): [True: 0, False: 0]
  ------------------
  227|      0|            mesh->mNormals = new aiVector3D[n];
  228|      0|            if (pModel->mNormals.size() < n) {
  ------------------
  |  Branch (228:17): [True: 0, False: 0]
  ------------------
  229|      0|                throw DeadlyImportError("OBJ: vertex normal index out of range");
  230|      0|            }
  231|      0|            memcpy(mesh->mNormals, pModel->mNormals.data(), n * sizeof(aiVector3D));
  232|      0|        }
  233|       |
  234|      0|        if (!pModel->mVertexColors.empty()) {
  ------------------
  |  Branch (234:13): [True: 0, False: 0]
  ------------------
  235|      0|            mesh->mColors[0] = new aiColor4D[mesh->mNumVertices];
  236|      0|            for (unsigned int i = 0; i < n; ++i) {
  ------------------
  |  Branch (236:38): [True: 0, False: 0]
  ------------------
  237|      0|                if (i < pModel->mVertexColors.size()) {
  ------------------
  |  Branch (237:21): [True: 0, False: 0]
  ------------------
  238|      0|                    const aiVector3D &color = pModel->mVertexColors[i];
  239|      0|                    mesh->mColors[0][i] = aiColor4D(color.x, color.y, color.z, 1.0);
  240|      0|                } else {
  241|      0|                    throw DeadlyImportError("OBJ: vertex color index out of range");
  242|      0|                }
  243|      0|            }
  244|      0|        }
  245|       |
  246|      0|        pScene->mRootNode->mNumMeshes = 1;
  247|      0|        pScene->mRootNode->mMeshes = new unsigned int[1];
  248|      0|        pScene->mRootNode->mMeshes[0] = 0;
  249|      0|        pScene->mMeshes = new aiMesh *[1];
  250|      0|        pScene->mNumMeshes = 1;
  251|      0|        pScene->mMeshes[0] = mesh.release();
  252|      0|    }
  253|     78|}
_ZN6Assimp15ObjFileImporter11createNodesEPKNS_7ObjFile5ModelEPKNS1_6ObjectEP6aiNodeP7aiSceneRNSt3__16vectorINSC_10unique_ptrI6aiMeshNSC_14default_deleteISF_EEEENSC_9allocatorISI_EEEE:
  259|  10.9k|        std::vector<std::unique_ptr<aiMesh>> &MeshArray) {
  260|  10.9k|    if (nullptr == pObject || pModel == nullptr) {
  ------------------
  |  Branch (260:9): [True: 0, False: 10.9k]
  |  Branch (260:31): [True: 0, False: 10.9k]
  ------------------
  261|      0|        return nullptr;
  262|      0|    }
  263|       |
  264|       |    // Store older mesh size to be able to computes mesh offsets for new mesh instances
  265|  10.9k|    const size_t oldMeshSize = MeshArray.size();
  266|  10.9k|    aiNode *pNode = new aiNode;
  267|       |
  268|  10.9k|    pNode->mName = pObject->m_strObjName;
  269|       |
  270|       |    // If we have a parent node, store it
  271|  10.9k|    ai_assert(nullptr != pParent);
  ------------------
  |  |   67|  10.9k|#   define ai_assert(expression) (void)((!!(expression)) || (Assimp::aiAssertViolation(#expression, __FILE__, __LINE__), 0))
  |  |  ------------------
  |  |  |  Branch (67:41): [True: 10.9k, False: 0]
  |  |  |  Branch (67:61): [True: 0, False: 0]
  |  |  ------------------
  ------------------
  272|  10.9k|    appendChildToParentNode(pParent, pNode);
  273|       |
  274|  22.5k|    for (size_t i = 0; i < pObject->m_Meshes.size(); ++i) {
  ------------------
  |  Branch (274:24): [True: 11.5k, False: 10.9k]
  ------------------
  275|  11.5k|        unsigned int meshId = pObject->m_Meshes[i];
  276|  11.5k|        std::unique_ptr<aiMesh> pMesh = createTopology(pModel, pObject, meshId);
  277|  11.5k|        if (pMesh != nullptr) {
  ------------------
  |  Branch (277:13): [True: 1.36k, False: 10.2k]
  ------------------
  278|  1.36k|            if (pMesh->mNumFaces > 0) {
  ------------------
  |  Branch (278:17): [True: 1.36k, False: 0]
  ------------------
  279|  1.36k|                MeshArray.push_back(std::move(pMesh));
  280|  1.36k|            }
  281|  1.36k|        }
  282|  11.5k|    }
  283|       |
  284|       |    // Create all nodes from the sub-objects stored in the current object
  285|  10.9k|    if (!pObject->m_SubObjects.empty()) {
  ------------------
  |  Branch (285:9): [True: 0, False: 10.9k]
  ------------------
  286|      0|        size_t numChilds = pObject->m_SubObjects.size();
  287|      0|        pNode->mNumChildren = static_cast<unsigned int>(numChilds);
  288|      0|        pNode->mChildren = new aiNode *[numChilds];
  289|      0|        pNode->mNumMeshes = 1;
  290|      0|        pNode->mMeshes = new unsigned int[1];
  291|      0|    }
  292|       |
  293|       |    // Set mesh instances into scene- and node-instances
  294|  10.9k|    const size_t meshSizeDiff = MeshArray.size() - oldMeshSize;
  295|  10.9k|    if (meshSizeDiff > 0) {
  ------------------
  |  Branch (295:9): [True: 750, False: 10.2k]
  ------------------
  296|    750|        pNode->mMeshes = new unsigned int[meshSizeDiff];
  297|    750|        pNode->mNumMeshes = static_cast<unsigned int>(meshSizeDiff);
  298|    750|        size_t index = 0;
  299|  2.09k|        for (size_t i = oldMeshSize; i < MeshArray.size(); ++i) {
  ------------------
  |  Branch (299:38): [True: 1.34k, False: 750]
  ------------------
  300|  1.34k|            pNode->mMeshes[index] = pScene->mNumMeshes;
  301|  1.34k|            pScene->mNumMeshes++;
  302|  1.34k|            ++index;
  303|  1.34k|        }
  304|    750|    }
  305|       |
  306|  10.9k|    return pNode;
  307|  10.9k|}
_ZN6Assimp15ObjFileImporter14createTopologyEPKNS_7ObjFile5ModelEPKNS1_6ObjectEj:
  311|  11.5k|std::unique_ptr<aiMesh> ObjFileImporter::createTopology(const ObjFile::Model *pModel, const ObjFile::Object *pData, unsigned int meshIndex) {
  312|  11.5k|    if (nullptr == pData || pModel == nullptr) {
  ------------------
  |  Branch (312:9): [True: 0, False: 11.5k]
  |  Branch (312:29): [True: 0, False: 11.5k]
  ------------------
  313|      0|        return nullptr;
  314|      0|    }
  315|       |
  316|       |    // Create faces
  317|  11.5k|    ObjFile::Mesh *pObjMesh = pModel->mMeshes[meshIndex];
  318|  11.5k|    if (pObjMesh == nullptr) {
  ------------------
  |  Branch (318:9): [True: 0, False: 11.5k]
  ------------------
  319|      0|        return nullptr;
  320|      0|    }
  321|       |
  322|  11.5k|    if (pObjMesh->m_Faces.empty()) {
  ------------------
  |  Branch (322:9): [True: 10.2k, False: 1.36k]
  ------------------
  323|  10.2k|        return nullptr;
  324|  10.2k|    }
  325|       |
  326|  1.36k|    std::unique_ptr<aiMesh> pMesh(new aiMesh);
  327|  1.36k|    if (!pObjMesh->m_name.empty()) {
  ------------------
  |  Branch (327:9): [True: 1.29k, False: 70]
  ------------------
  328|  1.29k|        pMesh->mName.Set(pObjMesh->m_name);
  329|  1.29k|    }
  330|       |
  331|  13.0k|    for (size_t index = 0; index < pObjMesh->m_Faces.size(); index++) {
  ------------------
  |  Branch (331:28): [True: 11.6k, False: 1.36k]
  ------------------
  332|  11.6k|        const ObjFile::Face *inp = pObjMesh->m_Faces[index];
  333|  11.6k|        if (inp == nullptr) {
  ------------------
  |  Branch (333:13): [True: 0, False: 11.6k]
  ------------------
  334|      0|            continue;
  335|      0|        }
  336|       |
  337|  11.6k|        if (inp->mPrimitiveType == aiPrimitiveType_LINE) {
  ------------------
  |  Branch (337:13): [True: 453, False: 11.1k]
  ------------------
  338|    453|            pMesh->mNumFaces += static_cast<unsigned int>(inp->m_vertices.size() - 1);
  339|    453|            pMesh->mPrimitiveTypes |= aiPrimitiveType_LINE;
  340|  11.1k|        } else if (inp->mPrimitiveType == aiPrimitiveType_POINT) {
  ------------------
  |  Branch (340:20): [True: 340, False: 10.8k]
  ------------------
  341|    340|            pMesh->mNumFaces += static_cast<unsigned int>(inp->m_vertices.size());
  342|    340|            pMesh->mPrimitiveTypes |= aiPrimitiveType_POINT;
  343|  10.8k|        } else {
  344|  10.8k|            ++pMesh->mNumFaces;
  345|  10.8k|            if (inp->m_vertices.size() > 3) {
  ------------------
  |  Branch (345:17): [True: 1.16k, False: 9.69k]
  ------------------
  346|  1.16k|                pMesh->mPrimitiveTypes |= aiPrimitiveType_POLYGON;
  347|  9.69k|            } else {
  348|  9.69k|                pMesh->mPrimitiveTypes |= aiPrimitiveType_TRIANGLE;
  349|  9.69k|            }
  350|  10.8k|        }
  351|  11.6k|    }
  352|       |
  353|  1.36k|    unsigned int uiIdxCount = 0u;
  354|  1.36k|    if (pMesh->mNumFaces > 0) {
  ------------------
  |  Branch (354:9): [True: 1.36k, False: 1]
  ------------------
  355|  1.36k|        pMesh->mFaces = new aiFace[pMesh->mNumFaces];
  356|  1.36k|        if (pObjMesh->m_uiMaterialIndex != ObjFile::Mesh::NoMaterial) {
  ------------------
  |  Branch (356:13): [True: 1.33k, False: 34]
  ------------------
  357|  1.33k|            pMesh->mMaterialIndex = pObjMesh->m_uiMaterialIndex;
  358|  1.33k|        }
  359|       |
  360|  1.36k|        unsigned int outIndex = 0u;
  361|       |
  362|       |        // Copy all data from all stored meshes
  363|  11.6k|        for (auto &face : pObjMesh->m_Faces) {
  ------------------
  |  Branch (363:25): [True: 11.6k, False: 1.36k]
  ------------------
  364|  11.6k|            const ObjFile::Face *inp = face;
  365|  11.6k|            if (inp->mPrimitiveType == aiPrimitiveType_LINE) {
  ------------------
  |  Branch (365:17): [True: 452, False: 11.1k]
  ------------------
  366|  1.59k|                for (size_t i = 0; i < inp->m_vertices.size() - 1; ++i) {
  ------------------
  |  Branch (366:36): [True: 1.14k, False: 452]
  ------------------
  367|  1.14k|                    aiFace &f = pMesh->mFaces[outIndex++];
  368|  1.14k|                    uiIdxCount += f.mNumIndices = 2;
  369|  1.14k|                    f.mIndices = new unsigned int[2];
  370|  1.14k|                }
  371|    452|                continue;
  372|  11.1k|            } else if (inp->mPrimitiveType == aiPrimitiveType_POINT) {
  ------------------
  |  Branch (372:24): [True: 340, False: 10.8k]
  ------------------
  373|    680|                for (size_t i = 0; i < inp->m_vertices.size(); ++i) {
  ------------------
  |  Branch (373:36): [True: 340, False: 340]
  ------------------
  374|    340|                    aiFace &f = pMesh->mFaces[outIndex++];
  375|    340|                    uiIdxCount += f.mNumIndices = 1;
  376|    340|                    f.mIndices = new unsigned int[1];
  377|    340|                }
  378|    340|                continue;
  379|    340|            }
  380|       |
  381|  10.8k|            aiFace *pFace = &pMesh->mFaces[outIndex++];
  382|  10.8k|            const unsigned int uiNumIndices = (unsigned int)face->m_vertices.size();
  383|  10.8k|            uiIdxCount += pFace->mNumIndices = (unsigned int)uiNumIndices;
  384|  10.8k|            if (pFace->mNumIndices > 0) {
  ------------------
  |  Branch (384:17): [True: 10.8k, False: 0]
  ------------------
  385|  10.8k|                pFace->mIndices = new unsigned int[uiNumIndices];
  386|  10.8k|            }
  387|  10.8k|        }
  388|  1.36k|    }
  389|       |
  390|       |    // Create mesh vertices
  391|  1.36k|    createVertexArray(pModel, pData, meshIndex, pMesh.get(), uiIdxCount);
  392|       |
  393|  1.36k|    return pMesh;
  394|  11.5k|}
_ZN6Assimp15ObjFileImporter17createVertexArrayEPKNS_7ObjFile5ModelEPKNS1_6ObjectEjP6aiMeshj:
  402|  1.36k|        unsigned int numIndices) {
  403|       |    // Checking preconditions
  404|  1.36k|    if (pCurrentObject == nullptr || pModel == nullptr || pMesh == nullptr) {
  ------------------
  |  Branch (404:9): [True: 0, False: 1.36k]
  |  Branch (404:38): [True: 0, False: 1.36k]
  |  Branch (404:59): [True: 0, False: 1.36k]
  ------------------
  405|      0|        return;
  406|      0|    }
  407|       |
  408|       |    // Break, if no faces are stored in object
  409|  1.36k|    if (pCurrentObject->m_Meshes.empty()) {
  ------------------
  |  Branch (409:9): [True: 0, False: 1.36k]
  ------------------
  410|      0|        return;
  411|      0|    }
  412|       |
  413|       |    // Get current mesh
  414|  1.36k|    ObjFile::Mesh *pObjMesh = pModel->mMeshes[uiMeshIndex];
  415|  1.36k|    if (nullptr == pObjMesh || pObjMesh->m_uiNumIndices < 1) {
  ------------------
  |  Branch (415:9): [True: 0, False: 1.36k]
  |  Branch (415:32): [True: 0, False: 1.36k]
  ------------------
  416|      0|        return;
  417|      0|    }
  418|       |
  419|       |    // Copy vertices of this mesh instance
  420|  1.36k|    pMesh->mNumVertices = numIndices;
  421|  1.36k|    if (pMesh->mNumVertices == 0) {
  ------------------
  |  Branch (421:9): [True: 1, False: 1.36k]
  ------------------
  422|      1|        throw DeadlyImportError("OBJ: no vertices");
  423|  1.36k|    } else if (pMesh->mNumVertices > AI_MAX_VERTICES) {
  ------------------
  |  Branch (423:16): [True: 0, False: 1.36k]
  ------------------
  424|      0|        throw DeadlyImportError("OBJ: Too many vertices");
  425|      0|    }
  426|  1.36k|    pMesh->mVertices = new aiVector3D[pMesh->mNumVertices];
  427|       |
  428|       |    // Allocate buffer for normal vectors
  429|  1.36k|    if (!pModel->mNormals.empty() && pObjMesh->m_hasNormals)
  ------------------
  |  Branch (429:9): [True: 564, False: 804]
  |  Branch (429:38): [True: 210, False: 354]
  ------------------
  430|    210|        pMesh->mNormals = new aiVector3D[pMesh->mNumVertices];
  431|       |
  432|       |    // Allocate buffer for vertex-color vectors
  433|  1.36k|    if (!pModel->mVertexColors.empty())
  ------------------
  |  Branch (433:9): [True: 242, False: 1.12k]
  ------------------
  434|    242|        pMesh->mColors[0] = new aiColor4D[pMesh->mNumVertices];
  435|       |
  436|       |    // Allocate buffer for texture coordinates
  437|  1.36k|    if (!pModel->mTextureCoord.empty() && pObjMesh->m_uiUVCoordinates[0]) {
  ------------------
  |  Branch (437:9): [True: 405, False: 963]
  |  Branch (437:43): [True: 141, False: 264]
  ------------------
  438|    141|        pMesh->mNumUVComponents[0] = pModel->mTextureCoordDim;
  439|    141|        pMesh->mTextureCoords[0] = new aiVector3D[pMesh->mNumVertices];
  440|    141|    }
  441|       |
  442|       |    // Copy vertices, normals and textures into aiMesh instance
  443|  1.36k|    bool normalsok = true, uvok = true;
  444|  1.36k|    unsigned int newIndex = 0, outIndex = 0;
  445|  11.6k|    for (auto sourceFace : pObjMesh->m_Faces) {
  ------------------
  |  Branch (445:26): [True: 11.6k, False: 1.36k]
  ------------------
  446|       |        // Copy all index arrays
  447|  51.9k|        for (size_t vertexIndex = 0, outVertexIndex = 0; vertexIndex < sourceFace->m_vertices.size(); vertexIndex++) {
  ------------------
  |  Branch (447:58): [True: 40.2k, False: 11.6k]
  ------------------
  448|  40.2k|            const unsigned int vertex = sourceFace->m_vertices.at(vertexIndex);
  449|  40.2k|            if (vertex >= pModel->mVertices.size()) {
  ------------------
  |  Branch (449:17): [True: 2, False: 40.2k]
  ------------------
  450|      2|                throw DeadlyImportError("OBJ: vertex index out of range");
  451|      2|            }
  452|       |
  453|  40.2k|            if (pMesh->mNumVertices <= newIndex) {
  ------------------
  |  Branch (453:17): [True: 0, False: 40.2k]
  ------------------
  454|      0|                throw DeadlyImportError("OBJ: bad vertex index");
  455|      0|            }
  456|       |
  457|  40.2k|            pMesh->mVertices[newIndex] = pModel->mVertices[vertex];
  458|       |
  459|       |            // Copy all normals
  460|  40.2k|            if (normalsok && !pModel->mNormals.empty() && vertexIndex < sourceFace->m_normals.size()) {
  ------------------
  |  Branch (460:17): [True: 40.2k, False: 4]
  |  Branch (460:30): [True: 19.1k, False: 21.1k]
  |  Branch (460:59): [True: 16.3k, False: 2.77k]
  ------------------
  461|  16.3k|                const unsigned int normal = sourceFace->m_normals.at(vertexIndex);
  462|  16.3k|                if (normal >= pModel->mNormals.size()) {
  ------------------
  |  Branch (462:21): [True: 2, False: 16.3k]
  ------------------
  463|      2|                    normalsok = false;
  464|  16.3k|                } else {
  465|  16.3k|                    pMesh->mNormals[newIndex] = pModel->mNormals[normal];
  466|  16.3k|                }
  467|  16.3k|            }
  468|       |
  469|       |            // Copy all vertex colors
  470|  40.2k|            if (vertex < pModel->mVertexColors.size()) {
  ------------------
  |  Branch (470:17): [True: 1.53k, False: 38.7k]
  ------------------
  471|  1.53k|                const aiVector3D &color = pModel->mVertexColors[vertex];
  472|  1.53k|                pMesh->mColors[0][newIndex] = aiColor4D(color.x, color.y, color.z, 1.0);
  473|  1.53k|            }
  474|       |
  475|       |            // Copy all texture coordinates
  476|  40.2k|            if (uvok && !pModel->mTextureCoord.empty() && vertexIndex < sourceFace->m_texturCoords.size()) {
  ------------------
  |  Branch (476:17): [True: 39.9k, False: 320]
  |  Branch (476:25): [True: 29.2k, False: 10.7k]
  |  Branch (476:59): [True: 17.5k, False: 11.7k]
  ------------------
  477|  17.5k|                const unsigned int tex = sourceFace->m_texturCoords.at(vertexIndex);
  478|       |
  479|  17.5k|                if (tex >= pModel->mTextureCoord.size()) {
  ------------------
  |  Branch (479:21): [True: 44, False: 17.4k]
  ------------------
  480|     44|                    uvok = false;
  481|  17.4k|                } else {
  482|  17.4k|                    const aiVector3D &coord3d = pModel->mTextureCoord[tex];
  483|  17.4k|                    pMesh->mTextureCoords[0][newIndex] = aiVector3D(coord3d.x, coord3d.y, coord3d.z);
  484|  17.4k|                }
  485|  17.5k|            }
  486|       |
  487|       |            // Get destination face
  488|  40.2k|            aiFace *pDestFace = &pMesh->mFaces[outIndex];
  489|       |
  490|  40.2k|            const bool last = (vertexIndex == sourceFace->m_vertices.size() - 1);
  491|  40.2k|            if (sourceFace->mPrimitiveType != aiPrimitiveType_LINE || !last) {
  ------------------
  |  Branch (491:17): [True: 38.6k, False: 1.59k]
  |  Branch (491:71): [True: 1.14k, False: 452]
  ------------------
  492|  39.8k|                pDestFace->mIndices[outVertexIndex] = newIndex;
  493|  39.8k|                outVertexIndex++;
  494|  39.8k|            }
  495|       |
  496|  40.2k|            if (sourceFace->mPrimitiveType == aiPrimitiveType_POINT) {
  ------------------
  |  Branch (496:17): [True: 340, False: 39.9k]
  ------------------
  497|    340|                outIndex++;
  498|    340|                outVertexIndex = 0;
  499|  39.9k|            } else if (sourceFace->mPrimitiveType == aiPrimitiveType_LINE) {
  ------------------
  |  Branch (499:24): [True: 1.59k, False: 38.3k]
  ------------------
  500|  1.59k|                outVertexIndex = 0;
  501|       |
  502|  1.59k|                if (!last)
  ------------------
  |  Branch (502:21): [True: 1.14k, False: 452]
  ------------------
  503|  1.14k|                    outIndex++;
  504|       |
  505|  1.59k|                if (vertexIndex) {
  ------------------
  |  Branch (505:21): [True: 1.14k, False: 452]
  ------------------
  506|  1.14k|                    if (!last) {
  ------------------
  |  Branch (506:25): [True: 688, False: 452]
  ------------------
  507|    688|                        if (pMesh->mNumVertices <= newIndex + 1) {
  ------------------
  |  Branch (507:29): [True: 0, False: 688]
  ------------------
  508|      0|                            throw DeadlyImportError("OBJ: bad vertex index");
  509|      0|                        }
  510|       |
  511|    688|                        pMesh->mVertices[newIndex + 1] = pMesh->mVertices[newIndex];
  512|    688|                        if (!sourceFace->m_normals.empty() && !pModel->mNormals.empty()) {
  ------------------
  |  Branch (512:29): [True: 0, False: 688]
  |  Branch (512:63): [True: 0, False: 0]
  ------------------
  513|      0|                            pMesh->mNormals[newIndex + 1] = pMesh->mNormals[newIndex];
  514|      0|                        }
  515|    688|                        if (!pModel->mTextureCoord.empty()) {
  ------------------
  |  Branch (515:29): [True: 145, False: 543]
  ------------------
  516|    145|                            for (size_t i = 0; i < pMesh->GetNumUVChannels(); i++) {
  ------------------
  |  Branch (516:48): [True: 0, False: 145]
  ------------------
  517|      0|                                pMesh->mTextureCoords[i][newIndex + 1] = pMesh->mTextureCoords[i][newIndex];
  518|      0|                            }
  519|    145|                        }
  520|    688|                        ++newIndex;
  521|    688|                    }
  522|       |
  523|  1.14k|                    pDestFace[-1].mIndices[1] = newIndex;
  524|  1.14k|                }
  525|  38.3k|            } else if (last) {
  ------------------
  |  Branch (525:24): [True: 10.8k, False: 27.4k]
  ------------------
  526|  10.8k|                outIndex++;
  527|  10.8k|            }
  528|  40.2k|            ++newIndex;
  529|  40.2k|        }
  530|  11.6k|    }
  531|       |
  532|  1.36k|    if (!normalsok) {
  ------------------
  |  Branch (532:9): [True: 1, False: 1.36k]
  ------------------
  533|      1|        delete[] pMesh->mNormals;
  534|      1|        pMesh->mNormals = nullptr;
  535|      1|    }
  536|       |
  537|  1.36k|    if (!uvok) {
  ------------------
  |  Branch (537:9): [True: 44, False: 1.32k]
  ------------------
  538|     44|        delete[] pMesh->mTextureCoords[0];
  539|     44|        pMesh->mTextureCoords[0] = nullptr;
  540|     44|    }
  541|  1.36k|}
_ZN6Assimp15ObjFileImporter15createMaterialsEPKNS_7ObjFile5ModelEP7aiScene:
  571|     53|void ObjFileImporter::createMaterials(const ObjFile::Model *pModel, aiScene *pScene) {
  572|     53|    if (nullptr == pScene) {
  ------------------
  |  Branch (572:9): [True: 0, False: 53]
  ------------------
  573|      0|        return;
  574|      0|    }
  575|       |
  576|     53|    const unsigned int numMaterials = (unsigned int)pModel->mMaterialLib.size();
  577|     53|    pScene->mNumMaterials = 0;
  578|     53|    if (pModel->mMaterialLib.empty()) {
  ------------------
  |  Branch (578:9): [True: 0, False: 53]
  ------------------
  579|      0|        ASSIMP_LOG_DEBUG("OBJ: no materials specified");
  580|      0|        return;
  581|      0|    }
  582|       |
  583|     53|    pScene->mMaterials = new aiMaterial *[numMaterials];
  584|    427|    for (unsigned int matIndex = 0; matIndex < numMaterials; matIndex++) {
  ------------------
  |  Branch (584:37): [True: 374, False: 53]
  ------------------
  585|       |        // Store material name
  586|    374|        std::map<std::string, ObjFile::Material *>::const_iterator it;
  587|    374|        it = pModel->mMaterialMap.find(pModel->mMaterialLib[matIndex]);
  588|       |
  589|       |        // No material found, use the default material
  590|    374|        if (pModel->mMaterialMap.end() == it) {
  ------------------
  |  Branch (590:13): [True: 0, False: 374]
  ------------------
  591|      0|            continue;
  592|      0|        }
  593|       |
  594|    374|        aiMaterial *mat = new aiMaterial;
  595|    374|        ObjFile::Material *pCurrentMaterial = it->second;
  596|    374|        mat->AddProperty(&pCurrentMaterial->MaterialName, AI_MATKEY_NAME);
  597|       |
  598|       |        // convert illumination model
  599|    374|        int sm = 0;
  600|    374|        switch (pCurrentMaterial->illumination_model) {
  601|     42|        case 0:
  ------------------
  |  Branch (601:9): [True: 42, False: 332]
  ------------------
  602|     42|            sm = aiShadingMode_NoShading;
  603|     42|            break;
  604|    331|        case 1:
  ------------------
  |  Branch (604:9): [True: 331, False: 43]
  ------------------
  605|    331|            sm = aiShadingMode_Gouraud;
  606|    331|            break;
  607|      0|        case 2:
  ------------------
  |  Branch (607:9): [True: 0, False: 374]
  ------------------
  608|      0|            sm = aiShadingMode_Phong;
  609|      0|            break;
  610|      1|        default:
  ------------------
  |  Branch (610:9): [True: 1, False: 373]
  ------------------
  611|      1|            sm = aiShadingMode_Gouraud;
  612|      1|            ASSIMP_LOG_ERROR("OBJ: unexpected illumination model (0-2 recognized)");
  613|    374|        }
  614|       |
  615|    374|        mat->AddProperty<int>(&sm, 1, AI_MATKEY_SHADING_MODEL);
  616|       |
  617|       |        // Preserve the original illum value
  618|    374|        mat->AddProperty<int>(&pCurrentMaterial->illumination_model, 1, AI_MATKEY_OBJ_ILLUM);
  619|       |
  620|       |        // Adding material colors
  621|    374|        mat->AddProperty(&pCurrentMaterial->ambient, 1, AI_MATKEY_COLOR_AMBIENT);
  622|    374|        mat->AddProperty(&pCurrentMaterial->diffuse, 1, AI_MATKEY_COLOR_DIFFUSE);
  623|    374|        mat->AddProperty(&pCurrentMaterial->specular, 1, AI_MATKEY_COLOR_SPECULAR);
  624|    374|        mat->AddProperty(&pCurrentMaterial->emissive, 1, AI_MATKEY_COLOR_EMISSIVE);
  625|    374|        mat->AddProperty(&pCurrentMaterial->shineness, 1, AI_MATKEY_SHININESS);
  626|    374|        mat->AddProperty(&pCurrentMaterial->alpha, 1, AI_MATKEY_OPACITY);
  627|    374|        mat->AddProperty(&pCurrentMaterial->transparent, 1, AI_MATKEY_COLOR_TRANSPARENT);
  628|    374|        if (pCurrentMaterial->roughness)
  ------------------
  |  Branch (628:13): [True: 0, False: 374]
  ------------------
  629|      0|            mat->AddProperty(&pCurrentMaterial->roughness.Get(), 1, AI_MATKEY_ROUGHNESS_FACTOR);
  630|    374|        if (pCurrentMaterial->metallic)
  ------------------
  |  Branch (630:13): [True: 0, False: 374]
  ------------------
  631|      0|            mat->AddProperty(&pCurrentMaterial->metallic.Get(), 1, AI_MATKEY_METALLIC_FACTOR);
  632|    374|        if (pCurrentMaterial->sheen)
  ------------------
  |  Branch (632:13): [True: 2, False: 372]
  ------------------
  633|      2|            mat->AddProperty(&pCurrentMaterial->sheen.Get(), 1, AI_MATKEY_SHEEN_COLOR_FACTOR);
  634|    374|        if (pCurrentMaterial->clearcoat_thickness)
  ------------------
  |  Branch (634:13): [True: 0, False: 374]
  ------------------
  635|      0|            mat->AddProperty(&pCurrentMaterial->clearcoat_thickness.Get(), 1, AI_MATKEY_CLEARCOAT_FACTOR);
  636|    374|        if (pCurrentMaterial->clearcoat_roughness)
  ------------------
  |  Branch (636:13): [True: 0, False: 374]
  ------------------
  637|      0|            mat->AddProperty(&pCurrentMaterial->clearcoat_roughness.Get(), 1, AI_MATKEY_CLEARCOAT_ROUGHNESS_FACTOR);
  638|    374|        mat->AddProperty(&pCurrentMaterial->anisotropy, 1, AI_MATKEY_ANISOTROPY_FACTOR);
  639|       |
  640|       |        // Adding refraction index
  641|    374|        mat->AddProperty(&pCurrentMaterial->ior, 1, AI_MATKEY_REFRACTI);
  642|       |
  643|       |        // Adding textures
  644|    374|        const int uvwIndex = 0;
  645|       |
  646|    374|        if (0 != pCurrentMaterial->texture.length) {
  ------------------
  |  Branch (646:13): [True: 1, False: 373]
  ------------------
  647|      1|            mat->AddProperty(&pCurrentMaterial->texture, AI_MATKEY_TEXTURE_DIFFUSE(0));
  648|      1|            mat->AddProperty(&uvwIndex, 1, AI_MATKEY_UVWSRC_DIFFUSE(0));
  649|      1|            if (pCurrentMaterial->clamp[ObjFile::Material::TextureDiffuseType]) {
  ------------------
  |  Branch (649:17): [True: 0, False: 1]
  ------------------
  650|      0|                addTextureMappingModeProperty(mat, aiTextureType_DIFFUSE);
  651|      0|            }
  652|      1|        }
  653|       |
  654|    374|        if (0 != pCurrentMaterial->textureAmbient.length) {
  ------------------
  |  Branch (654:13): [True: 13, False: 361]
  ------------------
  655|     13|            mat->AddProperty(&pCurrentMaterial->textureAmbient, AI_MATKEY_TEXTURE_AMBIENT(0));
  656|     13|            mat->AddProperty(&uvwIndex, 1, AI_MATKEY_UVWSRC_AMBIENT(0));
  657|     13|            if (pCurrentMaterial->clamp[ObjFile::Material::TextureAmbientType]) {
  ------------------
  |  Branch (657:17): [True: 0, False: 13]
  ------------------
  658|      0|                addTextureMappingModeProperty(mat, aiTextureType_AMBIENT);
  659|      0|            }
  660|     13|        }
  661|       |
  662|    374|        if (0 != pCurrentMaterial->textureEmissive.length) {
  ------------------
  |  Branch (662:13): [True: 17, False: 357]
  ------------------
  663|     17|            mat->AddProperty(&pCurrentMaterial->textureEmissive, AI_MATKEY_TEXTURE_EMISSIVE(0));
  664|     17|            mat->AddProperty(&uvwIndex, 1, AI_MATKEY_UVWSRC_EMISSIVE(0));
  665|     17|        }
  666|       |
  667|    374|        if (0 != pCurrentMaterial->textureSpecular.length) {
  ------------------
  |  Branch (667:13): [True: 5, False: 369]
  ------------------
  668|      5|            mat->AddProperty(&pCurrentMaterial->textureSpecular, AI_MATKEY_TEXTURE_SPECULAR(0));
  669|      5|            mat->AddProperty(&uvwIndex, 1, AI_MATKEY_UVWSRC_SPECULAR(0));
  670|      5|            if (pCurrentMaterial->clamp[ObjFile::Material::TextureSpecularType]) {
  ------------------
  |  Branch (670:17): [True: 0, False: 5]
  ------------------
  671|      0|                addTextureMappingModeProperty(mat, aiTextureType_SPECULAR);
  672|      0|            }
  673|      5|        }
  674|       |
  675|    374|        if (0 != pCurrentMaterial->textureBump.length) {
  ------------------
  |  Branch (675:13): [True: 7, False: 367]
  ------------------
  676|      7|            mat->AddProperty(&pCurrentMaterial->textureBump, AI_MATKEY_TEXTURE_HEIGHT(0));
  677|      7|            mat->AddProperty(&uvwIndex, 1, AI_MATKEY_UVWSRC_HEIGHT(0));
  678|      7|            if (pCurrentMaterial->bump_multiplier != 1.0) {
  ------------------
  |  Branch (678:17): [True: 0, False: 7]
  ------------------
  679|      0|                mat->AddProperty(&pCurrentMaterial->bump_multiplier, 1, AI_MATKEY_OBJ_BUMPMULT_HEIGHT(0));
  680|      0|            }
  681|      7|            if (pCurrentMaterial->clamp[ObjFile::Material::TextureBumpType]) {
  ------------------
  |  Branch (681:17): [True: 0, False: 7]
  ------------------
  682|      0|                addTextureMappingModeProperty(mat, aiTextureType_HEIGHT);
  683|      0|            }
  684|      7|        }
  685|       |
  686|    374|        if (0 != pCurrentMaterial->textureNormal.length) {
  ------------------
  |  Branch (686:13): [True: 8, False: 366]
  ------------------
  687|      8|            mat->AddProperty(&pCurrentMaterial->textureNormal, AI_MATKEY_TEXTURE_NORMALS(0));
  688|      8|            mat->AddProperty(&uvwIndex, 1, AI_MATKEY_UVWSRC_NORMALS(0));
  689|      8|            if (pCurrentMaterial->bump_multiplier != 1.0) {
  ------------------
  |  Branch (689:17): [True: 4, False: 4]
  ------------------
  690|      4|                mat->AddProperty(&pCurrentMaterial->bump_multiplier, 1, AI_MATKEY_OBJ_BUMPMULT_NORMALS(0));
  691|      4|            }
  692|      8|            if (pCurrentMaterial->clamp[ObjFile::Material::TextureNormalType]) {
  ------------------
  |  Branch (692:17): [True: 0, False: 8]
  ------------------
  693|      0|                addTextureMappingModeProperty(mat, aiTextureType_NORMALS);
  694|      0|            }
  695|      8|        }
  696|       |
  697|    374|        if (0 != pCurrentMaterial->textureReflection[0].length) {
  ------------------
  |  Branch (697:13): [True: 23, False: 351]
  ------------------
  698|     23|            ObjFile::Material::TextureType type = 0 != pCurrentMaterial->textureReflection[1].length ?
  ------------------
  |  Branch (698:51): [True: 23, False: 0]
  ------------------
  699|     23|                                                          ObjFile::Material::TextureReflectionCubeTopType :
  700|     23|                                                          ObjFile::Material::TextureReflectionSphereType;
  701|       |
  702|     23|            unsigned count = type == ObjFile::Material::TextureReflectionSphereType ? 1 : 6;
  ------------------
  |  Branch (702:30): [True: 0, False: 23]
  ------------------
  703|    161|            for (unsigned i = 0; i < count; i++) {
  ------------------
  |  Branch (703:34): [True: 138, False: 23]
  ------------------
  704|    138|                mat->AddProperty(&pCurrentMaterial->textureReflection[i], AI_MATKEY_TEXTURE_REFLECTION(i));
  705|    138|                mat->AddProperty(&uvwIndex, 1, AI_MATKEY_UVWSRC_REFLECTION(i));
  706|       |
  707|    138|                if (pCurrentMaterial->clamp[type])
  ------------------
  |  Branch (707:21): [True: 0, False: 138]
  ------------------
  708|      0|                    addTextureMappingModeProperty(mat, aiTextureType_REFLECTION, 1, i);
  709|    138|            }
  710|     23|        }
  711|       |
  712|    374|        if (0 != pCurrentMaterial->textureDisp.length) {
  ------------------
  |  Branch (712:13): [True: 0, False: 374]
  ------------------
  713|      0|            mat->AddProperty(&pCurrentMaterial->textureDisp, AI_MATKEY_TEXTURE_DISPLACEMENT(0));
  714|      0|            mat->AddProperty(&uvwIndex, 1, AI_MATKEY_UVWSRC_DISPLACEMENT(0));
  715|      0|            if (pCurrentMaterial->clamp[ObjFile::Material::TextureDispType]) {
  ------------------
  |  Branch (715:17): [True: 0, False: 0]
  ------------------
  716|      0|                addTextureMappingModeProperty(mat, aiTextureType_DISPLACEMENT);
  717|      0|            }
  718|      0|        }
  719|       |
  720|    374|        if (0 != pCurrentMaterial->textureOpacity.length) {
  ------------------
  |  Branch (720:13): [True: 6, False: 368]
  ------------------
  721|      6|            mat->AddProperty(&pCurrentMaterial->textureOpacity, AI_MATKEY_TEXTURE_OPACITY(0));
  722|      6|            mat->AddProperty(&uvwIndex, 1, AI_MATKEY_UVWSRC_OPACITY(0));
  723|      6|            if (pCurrentMaterial->clamp[ObjFile::Material::TextureOpacityType]) {
  ------------------
  |  Branch (723:17): [True: 0, False: 6]
  ------------------
  724|      0|                addTextureMappingModeProperty(mat, aiTextureType_OPACITY);
  725|      0|            }
  726|      6|        }
  727|       |
  728|    374|        if (0 != pCurrentMaterial->textureSpecularity.length) {
  ------------------
  |  Branch (728:13): [True: 4, False: 370]
  ------------------
  729|      4|            mat->AddProperty(&pCurrentMaterial->textureSpecularity, AI_MATKEY_TEXTURE_SHININESS(0));
  730|      4|            mat->AddProperty(&uvwIndex, 1, AI_MATKEY_UVWSRC_SHININESS(0));
  731|      4|            if (pCurrentMaterial->clamp[ObjFile::Material::TextureSpecularityType]) {
  ------------------
  |  Branch (731:17): [True: 0, False: 4]
  ------------------
  732|      0|                addTextureMappingModeProperty(mat, aiTextureType_SHININESS);
  733|      0|            }
  734|      4|        }
  735|       |
  736|    374|        if (0 != pCurrentMaterial->textureRoughness.length) {
  ------------------
  |  Branch (736:13): [True: 3, False: 371]
  ------------------
  737|      3|            mat->AddProperty(&pCurrentMaterial->textureRoughness, _AI_MATKEY_TEXTURE_BASE, aiTextureType_DIFFUSE_ROUGHNESS, 0);
  738|      3|            mat->AddProperty(&uvwIndex, 1, _AI_MATKEY_UVWSRC_BASE, aiTextureType_DIFFUSE_ROUGHNESS, 0 );
  739|      3|            if (pCurrentMaterial->clamp[ObjFile::Material::TextureRoughnessType]) {
  ------------------
  |  Branch (739:17): [True: 0, False: 3]
  ------------------
  740|      0|                addTextureMappingModeProperty(mat, aiTextureType_DIFFUSE_ROUGHNESS);
  741|      0|            }
  742|      3|        }
  743|       |
  744|    374|        if (0 != pCurrentMaterial->textureMetallic.length) {
  ------------------
  |  Branch (744:13): [True: 23, False: 351]
  ------------------
  745|     23|            mat->AddProperty(&pCurrentMaterial->textureMetallic, _AI_MATKEY_TEXTURE_BASE, aiTextureType_METALNESS, 0);
  746|     23|            mat->AddProperty(&uvwIndex, 1, _AI_MATKEY_UVWSRC_BASE, aiTextureType_METALNESS, 0 );
  747|     23|            if (pCurrentMaterial->clamp[ObjFile::Material::TextureMetallicType]) {
  ------------------
  |  Branch (747:17): [True: 0, False: 23]
  ------------------
  748|      0|                addTextureMappingModeProperty(mat, aiTextureType_METALNESS);
  749|      0|            }
  750|     23|        }
  751|       |
  752|    374|        if (0 != pCurrentMaterial->textureSheen.length) {
  ------------------
  |  Branch (752:13): [True: 0, False: 374]
  ------------------
  753|      0|            mat->AddProperty(&pCurrentMaterial->textureSheen, _AI_MATKEY_TEXTURE_BASE, aiTextureType_SHEEN, 0);
  754|      0|            mat->AddProperty(&uvwIndex, 1, _AI_MATKEY_UVWSRC_BASE, aiTextureType_SHEEN, 0 );
  755|      0|            if (pCurrentMaterial->clamp[ObjFile::Material::TextureSheenType]) {
  ------------------
  |  Branch (755:17): [True: 0, False: 0]
  ------------------
  756|      0|                addTextureMappingModeProperty(mat, aiTextureType_SHEEN);
  757|      0|            }
  758|      0|        }
  759|       |
  760|    374|        if (0 != pCurrentMaterial->textureRMA.length) {
  ------------------
  |  Branch (760:13): [True: 0, False: 374]
  ------------------
  761|       |            // NOTE: glTF importer places Rough/Metal/AO texture in Unknown so doing the same here for consistency.
  762|      0|            mat->AddProperty(&pCurrentMaterial->textureRMA, _AI_MATKEY_TEXTURE_BASE, aiTextureType_UNKNOWN, 0);
  763|      0|            mat->AddProperty(&uvwIndex, 1, _AI_MATKEY_UVWSRC_BASE, aiTextureType_UNKNOWN, 0 );
  764|      0|            if (pCurrentMaterial->clamp[ObjFile::Material::TextureRMAType]) {
  ------------------
  |  Branch (764:17): [True: 0, False: 0]
  ------------------
  765|      0|                addTextureMappingModeProperty(mat, aiTextureType_UNKNOWN);
  766|      0|            }
  767|      0|        }
  768|       |
  769|       |        // Store material property info in material array in scene
  770|    374|        pScene->mMaterials[pScene->mNumMaterials] = mat;
  771|    374|        pScene->mNumMaterials++;
  772|    374|    }
  773|       |
  774|       |    // Test number of created materials.
  775|     53|    ai_assert(pScene->mNumMaterials == numMaterials);
  ------------------
  |  |   67|     53|#   define ai_assert(expression) (void)((!!(expression)) || (Assimp::aiAssertViolation(#expression, __FILE__, __LINE__), 0))
  |  |  ------------------
  |  |  |  Branch (67:41): [True: 53, False: 0]
  |  |  |  Branch (67:61): [True: 0, False: 0]
  |  |  ------------------
  ------------------
  776|     53|}
_ZN6Assimp15ObjFileImporter23appendChildToParentNodeEP6aiNodeS2_:
  780|  10.9k|void ObjFileImporter::appendChildToParentNode(aiNode *pParent, aiNode *pChild) {
  781|       |    // Checking preconditions
  782|  10.9k|    if (pParent == nullptr || pChild == nullptr) {
  ------------------
  |  Branch (782:9): [True: 0, False: 10.9k]
  |  Branch (782:31): [True: 0, False: 10.9k]
  ------------------
  783|      0|        ai_assert(nullptr != pParent);
  ------------------
  |  |   67|      0|#   define ai_assert(expression) (void)((!!(expression)) || (Assimp::aiAssertViolation(#expression, __FILE__, __LINE__), 0))
  |  |  ------------------
  |  |  |  Branch (67:41): [True: 0, False: 0]
  |  |  |  Branch (67:61): [True: 0, False: 0]
  |  |  ------------------
  ------------------
  784|      0|        ai_assert(nullptr != pChild);
  ------------------
  |  |   67|      0|#   define ai_assert(expression) (void)((!!(expression)) || (Assimp::aiAssertViolation(#expression, __FILE__, __LINE__), 0))
  |  |  ------------------
  |  |  |  Branch (67:41): [True: 0, False: 0]
  |  |  |  Branch (67:61): [True: 0, False: 0]
  |  |  ------------------
  ------------------
  785|      0|        return;
  786|      0|    }
  787|       |
  788|       |    // Assign parent to child
  789|  10.9k|    pChild->mParent = pParent;
  790|       |
  791|       |    // Copy node instances into parent node
  792|  10.9k|    pParent->mNumChildren++;
  793|  10.9k|    pParent->mChildren[pParent->mNumChildren - 1] = pChild;
  794|  10.9k|}
ObjFileImporter.cpp:_ZZN6Assimp15ObjFileImporter14InternReadFileERKNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEP7aiScenePNS_8IOSystemEENK3$_0clEPNS_8IOStreamE:
  113|     88|    auto streamCloser = [&](IOStream *pStream) {
  114|     88|        pIOHandler->Close(pStream);
  115|     88|    };

_ZN6Assimp18ObjFileMtlImporterC2ERNSt3__16vectorIcNS1_9allocatorIcEEEERKNS1_12basic_stringIcNS1_11char_traitsIcEES4_EEPNS_7ObjFile5ModelE:
   95|  2.60k|        m_strAbsPath(strAbsPath),
   96|  2.60k|        m_DataIt(buffer.begin()),
   97|  2.60k|        m_DataItEnd(buffer.end()),
   98|  2.60k|        m_pModel(pModel),
   99|  2.60k|        m_uiLine(0),
  100|  2.60k|        m_buffer() {
  101|  2.60k|    ai_assert(nullptr != m_pModel);
  ------------------
  |  |   67|  2.60k|#   define ai_assert(expression) (void)((!!(expression)) || (Assimp::aiAssertViolation(#expression, __FILE__, __LINE__), 0))
  |  |  ------------------
  |  |  |  Branch (67:41): [True: 2.60k, False: 0]
  |  |  |  Branch (67:61): [True: 0, False: 0]
  |  |  ------------------
  ------------------
  102|  2.60k|    m_buffer.resize(BUFFERSIZE);
  103|  2.60k|    std::fill(m_buffer.begin(), m_buffer.end(), '\0');
  104|  2.60k|    if (nullptr == m_pModel->mDefaultMaterial) {
  ------------------
  |  Branch (104:9): [True: 0, False: 2.60k]
  ------------------
  105|      0|        m_pModel->mDefaultMaterial = new ObjFile::Material;
  106|      0|        m_pModel->mDefaultMaterial->MaterialName.Set("default");
  107|      0|    }
  108|       |
  109|       |    // Try with OS folder separator first
  110|  2.60k|    char folderSeparator = DefaultIOSystem().getOsSeparator();
  111|  2.60k|    std::size_t found = m_strAbsPath.find_last_of(folderSeparator);
  112|  2.60k|    if (found == std::string::npos) {
  ------------------
  |  Branch (112:9): [True: 2.60k, False: 0]
  ------------------
  113|       |        // Not found, try alternative folder separator
  114|  2.60k|        folderSeparator = (folderSeparator == '/' ? '\\' : '/');
  ------------------
  |  Branch (114:28): [True: 2.60k, False: 0]
  ------------------
  115|  2.60k|        found = m_strAbsPath.find_last_of(folderSeparator);
  116|  2.60k|    }
  117|  2.60k|    if (found != std::string::npos) {
  ------------------
  |  Branch (117:9): [True: 19, False: 2.58k]
  ------------------
  118|     19|        m_strAbsPath = m_strAbsPath.substr(0, found + 1);
  119|  2.58k|    } else {
  120|  2.58k|        m_strAbsPath = "";
  121|  2.58k|    }
  122|  2.60k|    load();
  123|  2.60k|}
_ZN6Assimp18ObjFileMtlImporter4loadEv:
  127|  2.60k|void ObjFileMtlImporter::load() {
  128|  2.60k|    if (m_DataIt == m_DataItEnd)
  ------------------
  |  Branch (128:9): [True: 0, False: 2.60k]
  ------------------
  129|      0|        return;
  130|       |
  131|  6.57M|    while (m_DataIt != m_DataItEnd) {
  ------------------
  |  Branch (131:12): [True: 6.57M, False: 2.60k]
  ------------------
  132|  6.57M|        switch (*m_DataIt) {
  133|      0|            case 'k':
  ------------------
  |  Branch (133:13): [True: 0, False: 6.57M]
  ------------------
  134|  1.26k|            case 'K': {
  ------------------
  |  Branch (134:13): [True: 1.26k, False: 6.57M]
  ------------------
  135|  1.26k|                ++m_DataIt;
  136|  1.26k|                if (*m_DataIt == 'a') // Ambient color
  ------------------
  |  Branch (136:21): [True: 500, False: 766]
  ------------------
  137|    500|                {
  138|    500|                    ++m_DataIt;
  139|    500|                    if (m_pModel->mCurrentMaterial != nullptr)
  ------------------
  |  Branch (139:25): [True: 500, False: 0]
  ------------------
  140|    500|                        getColorRGBA(&m_pModel->mCurrentMaterial->ambient);
  141|    766|                } else if (*m_DataIt == 'd') {
  ------------------
  |  Branch (141:28): [True: 147, False: 619]
  ------------------
  142|       |                    // Diffuse color
  143|    147|                    ++m_DataIt;
  144|    147|                    if (m_pModel->mCurrentMaterial != nullptr)
  ------------------
  |  Branch (144:25): [True: 3, False: 144]
  ------------------
  145|      3|                        getColorRGBA(&m_pModel->mCurrentMaterial->diffuse);
  146|    619|                } else if (*m_DataIt == 's') {
  ------------------
  |  Branch (146:28): [True: 0, False: 619]
  ------------------
  147|      0|                    ++m_DataIt;
  148|      0|                    if (m_pModel->mCurrentMaterial != nullptr)
  ------------------
  |  Branch (148:25): [True: 0, False: 0]
  ------------------
  149|      0|                        getColorRGBA(&m_pModel->mCurrentMaterial->specular);
  150|    619|                } else if (*m_DataIt == 'e') {
  ------------------
  |  Branch (150:28): [True: 0, False: 619]
  ------------------
  151|      0|                    ++m_DataIt;
  152|      0|                    if (m_pModel->mCurrentMaterial != nullptr)
  ------------------
  |  Branch (152:25): [True: 0, False: 0]
  ------------------
  153|      0|                        getColorRGBA(&m_pModel->mCurrentMaterial->emissive);
  154|      0|                }
  155|  1.26k|                m_DataIt = skipLine<DataArrayIt>(m_DataIt, m_DataItEnd, m_uiLine);
  156|  1.26k|            } break;
  157|  2.67k|            case 'T': {
  ------------------
  |  Branch (157:13): [True: 2.67k, False: 6.57M]
  ------------------
  158|  2.67k|                ++m_DataIt;
  159|       |                // Material transmission color
  160|  2.67k|                if (*m_DataIt == 'f')  {
  ------------------
  |  Branch (160:21): [True: 0, False: 2.67k]
  ------------------
  161|      0|                    ++m_DataIt;
  162|      0|                    if (m_pModel->mCurrentMaterial != nullptr)
  ------------------
  |  Branch (162:25): [True: 0, False: 0]
  ------------------
  163|      0|                        getColorRGBA(&m_pModel->mCurrentMaterial->transparent);
  164|  2.67k|                } else if (*m_DataIt == 'r')  {
  ------------------
  |  Branch (164:28): [True: 139, False: 2.53k]
  ------------------
  165|       |                    // Material transmission alpha value
  166|    139|                    ++m_DataIt;
  167|    139|                    ai_real d;
  168|    139|                    getFloatValue(d);
  169|    139|                    if (m_pModel->mCurrentMaterial != nullptr)
  ------------------
  |  Branch (169:25): [True: 139, False: 0]
  ------------------
  170|    139|                        m_pModel->mCurrentMaterial->alpha = static_cast<ai_real>(1.0) - d;
  171|    139|                }
  172|  2.67k|                m_DataIt = skipLine<DataArrayIt>(m_DataIt, m_DataItEnd, m_uiLine);
  173|  2.67k|            } break;
  174|  2.25k|            case 'd': {
  ------------------
  |  Branch (174:13): [True: 2.25k, False: 6.57M]
  ------------------
  175|  2.25k|                if (*(m_DataIt + 1) == 'i' && *(m_DataIt + 2) == 's' && *(m_DataIt + 3) == 'p') {
  ------------------
  |  Branch (175:21): [True: 126, False: 2.12k]
  |  Branch (175:21): [True: 0, False: 2.25k]
  |  Branch (175:47): [True: 0, False: 126]
  |  Branch (175:73): [True: 0, False: 0]
  ------------------
  176|       |                    // A displacement map
  177|      0|                    getTexture();
  178|  2.25k|                } else {
  179|       |                    // Alpha value
  180|  2.25k|                    ++m_DataIt;
  181|  2.25k|                    if (m_pModel->mCurrentMaterial != nullptr)
  ------------------
  |  Branch (181:25): [True: 2.12k, False: 127]
  ------------------
  182|  2.12k|                        getFloatValue(m_pModel->mCurrentMaterial->alpha);
  183|  2.25k|                    m_DataIt = skipLine<DataArrayIt>(m_DataIt, m_DataItEnd, m_uiLine);
  184|  2.25k|                }
  185|  2.25k|            } break;
  186|       |
  187|    345|            case 'N':
  ------------------
  |  Branch (187:13): [True: 345, False: 6.57M]
  ------------------
  188|  14.9k|            case 'n': {
  ------------------
  |  Branch (188:13): [True: 14.5k, False: 6.56M]
  ------------------
  189|  14.9k|                ++m_DataIt;
  190|  14.9k|                switch (*m_DataIt) {
  ------------------
  |  Branch (190:25): [True: 9.64k, False: 5.26k]
  ------------------
  191|     27|                    case 's': // Specular exponent
  ------------------
  |  Branch (191:21): [True: 27, False: 14.8k]
  ------------------
  192|     27|                        ++m_DataIt;
  193|     27|                        if (m_pModel->mCurrentMaterial != nullptr)
  ------------------
  |  Branch (193:29): [True: 27, False: 0]
  ------------------
  194|     27|                            getFloatValue(m_pModel->mCurrentMaterial->shineness);
  195|     27|                        break;
  196|     60|                    case 'i': // Index Of refraction
  ------------------
  |  Branch (196:21): [True: 60, False: 14.8k]
  ------------------
  197|     60|                        ++m_DataIt;
  198|     60|                        if (m_pModel->mCurrentMaterial != nullptr)
  ------------------
  |  Branch (198:29): [True: 53, False: 7]
  ------------------
  199|     53|                            getFloatValue(m_pModel->mCurrentMaterial->ior);
  200|     60|                        break;
  201|  8.08k|                    case 'e': // New material
  ------------------
  |  Branch (201:21): [True: 8.08k, False: 6.83k]
  ------------------
  202|  8.08k|                        createMaterial();
  203|  8.08k|                        break;
  204|  1.47k|                    case 'o': // Norm texture
  ------------------
  |  Branch (204:21): [True: 1.47k, False: 13.4k]
  ------------------
  205|  1.47k|                        --m_DataIt;
  206|  1.47k|                        getTexture();
  207|  1.47k|                        break;
  208|  14.9k|                }
  209|  14.9k|                m_DataIt = skipLine<DataArrayIt>(m_DataIt, m_DataItEnd, m_uiLine);
  210|  14.9k|            } break;
  211|       |
  212|  4.96k|            case 'P':
  ------------------
  |  Branch (212:13): [True: 4.96k, False: 6.57M]
  ------------------
  213|  4.96k|                {
  214|  4.96k|                    ++m_DataIt;
  215|  4.96k|                    switch(*m_DataIt)
  ------------------
  |  Branch (215:28): [True: 3.03k, False: 1.92k]
  ------------------
  216|  4.96k|                    {
  217|    108|                    case 'r':
  ------------------
  |  Branch (217:21): [True: 108, False: 4.85k]
  ------------------
  218|    108|                        ++m_DataIt;
  219|    108|                        if (m_pModel->mCurrentMaterial != nullptr)
  ------------------
  |  Branch (219:29): [True: 108, False: 0]
  ------------------
  220|    108|                            getFloatValue(m_pModel->mCurrentMaterial->roughness);
  221|    108|                        break;
  222|    161|                    case 'm':
  ------------------
  |  Branch (222:21): [True: 161, False: 4.79k]
  ------------------
  223|    161|                        ++m_DataIt;
  224|    161|                        if (m_pModel->mCurrentMaterial != nullptr)
  ------------------
  |  Branch (224:29): [True: 161, False: 0]
  ------------------
  225|    161|                            getFloatValue(m_pModel->mCurrentMaterial->metallic);
  226|    161|                        break;
  227|     70|                    case 's':
  ------------------
  |  Branch (227:21): [True: 70, False: 4.89k]
  ------------------
  228|     70|                        ++m_DataIt;
  229|     70|                        if (m_pModel->mCurrentMaterial != nullptr)
  ------------------
  |  Branch (229:29): [True: 70, False: 0]
  ------------------
  230|     70|                            getColorRGBA(m_pModel->mCurrentMaterial->sheen);
  231|     70|                        break;
  232|  2.69k|                    case 'c':
  ------------------
  |  Branch (232:21): [True: 2.69k, False: 2.26k]
  ------------------
  233|  2.69k|                        ++m_DataIt;
  234|  2.69k|                        if (*m_DataIt == 'r') {
  ------------------
  |  Branch (234:29): [True: 0, False: 2.69k]
  ------------------
  235|      0|                            ++m_DataIt;
  236|      0|                            if (m_pModel->mCurrentMaterial != nullptr)
  ------------------
  |  Branch (236:33): [True: 0, False: 0]
  ------------------
  237|      0|                                getFloatValue(m_pModel->mCurrentMaterial->clearcoat_roughness);
  238|  2.69k|                        } else if (*m_DataIt == 't') {
  ------------------
  |  Branch (238:36): [True: 0, False: 2.69k]
  ------------------
  239|      0|                            ++m_DataIt;
  240|      0|                            if (m_pModel->mCurrentMaterial != nullptr)
  ------------------
  |  Branch (240:33): [True: 0, False: 0]
  ------------------
  241|      0|                                getFloatValue(m_pModel->mCurrentMaterial->clearcoat_thickness);
  242|  2.69k|                        } else {
  243|  2.69k|                            if (m_pModel->mCurrentMaterial != nullptr)
  ------------------
  |  Branch (243:33): [True: 1.98k, False: 716]
  ------------------
  244|  1.98k|                                getFloatValue(m_pModel->mCurrentMaterial->clearcoat);
  245|  2.69k|                        }
  246|  2.69k|                        break;
  247|  4.96k|                    }
  248|  4.96k|                    m_DataIt = skipLine<DataArrayIt>(m_DataIt, m_DataItEnd, m_uiLine);
  249|  4.96k|                }
  250|      0|                break;
  251|       |            
  252|  3.53M|            case 'm': // Texture or metallic
  ------------------
  |  Branch (252:13): [True: 3.53M, False: 3.04M]
  ------------------
  253|  3.53M|            {
  254|       |                // Save start of token (after 'm')
  255|  3.53M|                auto tokenStart = m_DataIt;  // points to 'm'
  256|  3.53M|                auto tokenEnd = getNextDelimiter(m_DataIt, m_DataItEnd); // move iterator to end of token
  257|       |
  258|  3.53M|                std::string keyword(tokenStart, tokenEnd);
  259|  3.53M|                m_DataIt = getNextWord(tokenEnd, m_DataItEnd); // advance iterator
  260|       |
  261|  3.53M|                if (keyword.compare(0, 3, "map") == 0) {
  ------------------
  |  Branch (261:21): [True: 245k, False: 3.28M]
  ------------------
  262|       |                    // starts with "map", treat as texture map
  263|   245k|                    m_DataIt = tokenStart;
  264|   245k|                    getTexture();
  265|  3.28M|                } else if (keyword == "metallic" || keyword == "metal" || keyword == "metalness") {
  ------------------
  |  Branch (265:28): [True: 0, False: 3.28M]
  |  Branch (265:53): [True: 0, False: 3.28M]
  |  Branch (265:75): [True: 0, False: 3.28M]
  ------------------
  266|       |                    // parse metallic float value instead of texture
  267|      0|                    getFloatIfMaterialValid(&ObjFile::Material::metallic);
  268|      0|                }
  269|       |
  270|  3.53M|                m_DataIt = skipLine<DataArrayIt>(m_DataIt, m_DataItEnd, m_uiLine);
  271|  3.53M|            } break;
  272|       |
  273|  2.97k|            case 'b': // quick'n'dirty - for 'bump' sections
  ------------------
  |  Branch (273:13): [True: 2.97k, False: 6.57M]
  ------------------
  274|  2.97k|            {
  275|  2.97k|                getTexture();
  276|  2.97k|                m_DataIt = skipLine<DataArrayIt>(m_DataIt, m_DataItEnd, m_uiLine);
  277|  2.97k|            } break;
  278|       |
  279|  1.86k|            case 'r': // refl (map) or roughness (float)
  ------------------
  |  Branch (279:13): [True: 1.86k, False: 6.57M]
  ------------------
  280|  1.86k|            {
  281|  1.86k|                auto tokenStart = m_DataIt;  // points to 'r'
  282|  1.86k|                auto tokenEnd = getNextDelimiter(m_DataIt, m_DataItEnd);
  283|  1.86k|                std::string keyword(tokenStart, tokenEnd);
  284|  1.86k|                m_DataIt = getNextWord(tokenEnd, m_DataItEnd);
  285|       |
  286|  1.86k|                if (keyword == "roughness" || keyword == "rough") {
  ------------------
  |  Branch (286:21): [True: 0, False: 1.86k]
  |  Branch (286:47): [True: 0, False: 1.86k]
  ------------------
  287|      0|                    getFloatIfMaterialValid(&ObjFile::Material::roughness);
  288|  1.86k|                } else if (keyword == "refl" || keyword == "reflection") {
  ------------------
  |  Branch (288:28): [True: 0, False: 1.86k]
  |  Branch (288:49): [True: 0, False: 1.86k]
  ------------------
  289|      0|                    m_DataIt = tokenStart;
  290|      0|                    getTexture();
  291|      0|                }
  292|       |
  293|  1.86k|                m_DataIt = skipLine<DataArrayIt>(m_DataIt, m_DataItEnd, m_uiLine);
  294|  1.86k|            } break;
  295|       |
  296|  56.0k|            case 'i': // Illumination model
  ------------------
  |  Branch (296:13): [True: 56.0k, False: 6.52M]
  ------------------
  297|  56.0k|            {
  298|  56.0k|                m_DataIt = getNextToken<DataArrayIt>(m_DataIt, m_DataItEnd);
  299|  56.0k|                if (m_pModel->mCurrentMaterial != nullptr)
  ------------------
  |  Branch (299:21): [True: 7.45k, False: 48.6k]
  ------------------
  300|  7.45k|                    getIlluminationModel(m_pModel->mCurrentMaterial->illumination_model);
  301|  56.0k|                m_DataIt = skipLine<DataArrayIt>(m_DataIt, m_DataItEnd, m_uiLine);
  302|  56.0k|            } break;
  303|       |
  304|  59.2k|            case 'a': {
  ------------------
  |  Branch (304:13): [True: 59.2k, False: 6.51M]
  ------------------
  305|  59.2k|                auto tokenStart = m_DataIt;
  306|  59.2k|                auto tokenEnd = getNextDelimiter(m_DataIt, m_DataItEnd);
  307|  59.2k|                std::string keyword(tokenStart, tokenEnd);
  308|  59.2k|                m_DataIt = getNextWord(tokenEnd, m_DataItEnd);
  309|       |
  310|  59.2k|                if (keyword == "aniso" || keyword == "anisotropy") {
  ------------------
  |  Branch (310:21): [True: 0, False: 59.2k]
  |  Branch (310:43): [True: 0, False: 59.2k]
  ------------------
  311|      0|                    getFloatIfMaterialValid(&ObjFile::Material::anisotropy);
  312|  59.2k|                } else if (keyword == "ao") {
  ------------------
  |  Branch (312:28): [True: 0, False: 59.2k]
  ------------------
  313|      0|                    getFloatIfMaterialValid(&ObjFile::Material::ambient_occlusion);
  314|  59.2k|                } else if (keyword == "anisor" || ai_stdStrToLower(keyword) == "anisotropicrotation") {
  ------------------
  |  Branch (314:28): [True: 348, False: 58.8k]
  |  Branch (314:28): [True: 348, False: 58.8k]
  |  Branch (314:51): [True: 0, False: 58.8k]
  ------------------
  315|    348|                    getFloatIfMaterialValid(&ObjFile::Material::anisotropy_rotation);
  316|  58.8k|                } else {
  317|  58.8k|                    ASSIMP_LOG_WARN("Unhandled keyword: ", keyword );
  318|  58.8k|                }
  319|       |
  320|  59.2k|                m_DataIt = skipLine<DataArrayIt>(m_DataIt, m_DataItEnd, m_uiLine);
  321|  59.2k|            } break;
  322|       |
  323|  3.06k|            case 's': {
  ------------------
  |  Branch (323:13): [True: 3.06k, False: 6.57M]
  ------------------
  324|  3.06k|                auto tokenStart = m_DataIt;
  325|  3.06k|                auto tokenEnd = getNextDelimiter(m_DataIt, m_DataItEnd);
  326|  3.06k|                std::string keyword(tokenStart, tokenEnd);
  327|  3.06k|                m_DataIt = getNextWord(tokenEnd,m_DataItEnd);
  328|       |
  329|  3.06k|                if (keyword == "subsurface" || keyword == "scattering") {
  ------------------
  |  Branch (329:21): [True: 0, False: 3.06k]
  |  Branch (329:48): [True: 0, False: 3.06k]
  ------------------
  330|      0|                    getFloatIfMaterialValid(&ObjFile::Material::subsurface_scattering);
  331|  3.06k|                } else if (ai_stdStrToLower(keyword) == "speculartint") {
  ------------------
  |  Branch (331:28): [True: 0, False: 3.06k]
  ------------------
  332|      0|                    getFloatIfMaterialValid(&ObjFile::Material::specular_tint);
  333|  3.06k|                } else if (keyword == "sheen") {
  ------------------
  |  Branch (333:28): [True: 0, False: 3.06k]
  ------------------
  334|      0|                    getFloatIfMaterialValid(&ObjFile::Material::sheen_grazing);
  335|  3.06k|                } else if (ai_stdStrToLower(keyword) == "sheentint") {
  ------------------
  |  Branch (335:28): [True: 0, False: 3.06k]
  ------------------
  336|      0|                    getFloatIfMaterialValid(&ObjFile::Material::sheen_tint);
  337|  3.06k|                } else {
  338|  3.06k|                    ASSIMP_LOG_WARN("Unhandled keyword: ", keyword );
  339|  3.06k|                }
  340|       |
  341|  3.06k|                m_DataIt = skipLine<DataArrayIt>(m_DataIt, m_DataItEnd, m_uiLine);
  342|  3.06k|            } break;
  343|       |
  344|  61.0k|            case 'c': {
  ------------------
  |  Branch (344:13): [True: 61.0k, False: 6.51M]
  ------------------
  345|  61.0k|                auto tokenStart = m_DataIt;
  346|  61.0k|                auto tokenEnd = getNextDelimiter(m_DataIt, m_DataItEnd);
  347|  61.0k|                std::string keyword(tokenStart, tokenEnd);
  348|  61.0k|                m_DataIt = getNextWord(tokenEnd, m_DataItEnd);
  349|       |
  350|  61.0k|                if (ai_stdStrToLower(keyword) == "clearcoat") {
  ------------------
  |  Branch (350:21): [True: 0, False: 61.0k]
  ------------------
  351|      0|                    getFloatIfMaterialValid(&ObjFile::Material::clearcoat);
  352|  61.0k|                } else if (ai_stdStrToLower(keyword) == "clearcoatgloss") {
  ------------------
  |  Branch (352:28): [True: 0, False: 61.0k]
  ------------------
  353|      0|                    getFloatIfMaterialValid(&ObjFile::Material::clearcoat_gloss);
  354|  61.0k|                } else {
  355|  61.0k|                    ASSIMP_LOG_WARN("Unhandled keyword: ", keyword );
  356|  61.0k|                }
  357|       |
  358|  61.0k|                m_DataIt = skipLine<DataArrayIt>(m_DataIt, m_DataItEnd, m_uiLine);
  359|  61.0k|            } break;
  360|       |
  361|  2.83M|            default: {
  ------------------
  |  Branch (361:13): [True: 2.83M, False: 3.74M]
  ------------------
  362|  2.83M|                m_DataIt = skipLine<DataArrayIt>(m_DataIt, m_DataItEnd, m_uiLine);
  363|  2.83M|            } break;
  364|  6.57M|        }
  365|  6.57M|    }
  366|  2.60k|}
_ZN6Assimp18ObjFileMtlImporter12getColorRGBAEP9aiColor3D:
  370|    573|void ObjFileMtlImporter::getColorRGBA(aiColor3D *pColor) {
  371|    573|    ai_assert(nullptr != pColor);
  ------------------
  |  |   67|    573|#   define ai_assert(expression) (void)((!!(expression)) || (Assimp::aiAssertViolation(#expression, __FILE__, __LINE__), 0))
  |  |  ------------------
  |  |  |  Branch (67:41): [True: 573, False: 0]
  |  |  |  Branch (67:61): [True: 0, False: 0]
  |  |  ------------------
  ------------------
  372|       |
  373|    573|    ai_real r(0.0), g(0.0), b(0.0);
  374|    573|    m_DataIt = getFloat<DataArrayIt>(m_DataIt, m_DataItEnd, r);
  375|    573|    pColor->r = r;
  376|       |
  377|       |    // we have to check if color is default 0 with only one token
  378|    573|    if (!IsLineEnd(*m_DataIt)) {
  ------------------
  |  Branch (378:9): [True: 23, False: 550]
  ------------------
  379|     23|        m_DataIt = getFloat<DataArrayIt>(m_DataIt, m_DataItEnd, g);
  380|     23|        m_DataIt = getFloat<DataArrayIt>(m_DataIt, m_DataItEnd, b);
  381|     23|    }
  382|    573|    pColor->g = g;
  383|    573|    pColor->b = b;
  384|    573|}
_ZN6Assimp18ObjFileMtlImporter12getColorRGBAERNS_5MaybeI9aiColor3DEE:
  387|     70|void ObjFileMtlImporter::getColorRGBA(Maybe<aiColor3D> &value) {
  388|     70|    aiColor3D v;
  389|     70|    getColorRGBA(&v);
  390|     70|    value = Maybe<aiColor3D>(v);
  391|     70|}
_ZN6Assimp18ObjFileMtlImporter20getIlluminationModelERi:
  395|  7.45k|void ObjFileMtlImporter::getIlluminationModel(int &illum_model) {
  396|  7.45k|    m_DataIt = CopyNextWord<DataArrayIt>(m_DataIt, m_DataItEnd, &m_buffer[0], BUFFERSIZE);
  397|  7.45k|    illum_model = atoi(&m_buffer[0]);
  398|  7.45k|}
_ZN6Assimp18ObjFileMtlImporter13getFloatValueERf:
  403|  2.34k|void ObjFileMtlImporter::getFloatValue(ai_real &value) {
  404|  2.34k|    m_DataIt = CopyNextWord<DataArrayIt>(m_DataIt, m_DataItEnd, &m_buffer[0], BUFFERSIZE);
  405|  2.34k|    size_t len = std::strlen(&m_buffer[0]);
  406|  2.34k|    if (0 == len) {
  ------------------
  |  Branch (406:9): [True: 891, False: 1.45k]
  ------------------
  407|    891|        value = 0.0f;
  408|    891|        return;
  409|    891|    }
  410|       |
  411|  1.45k|    value = (ai_real)fast_atof(&m_buffer[0]);
  412|  1.45k|}
_ZN6Assimp18ObjFileMtlImporter13getFloatValueERNS_5MaybeIfEE:
  415|  2.60k|void ObjFileMtlImporter::getFloatValue(Maybe<ai_real> &value) {
  416|  2.60k|    m_DataIt = CopyNextWord<DataArrayIt>(m_DataIt, m_DataItEnd, &m_buffer[0], BUFFERSIZE);
  417|  2.60k|    size_t len = std::strlen(&m_buffer[0]);
  418|  2.60k|    if (len)
  ------------------
  |  Branch (418:9): [True: 1.39k, False: 1.20k]
  ------------------
  419|  1.39k|        value = Maybe<ai_real>(fast_atof(&m_buffer[0]));
  420|  1.20k|    else
  421|  1.20k|        value = Maybe<ai_real>();
  422|  2.60k|}
_ZN6Assimp18ObjFileMtlImporter23getFloatIfMaterialValidEMNS_7ObjFile8MaterialENS_5MaybeIfEE:
  434|    348|void ObjFileMtlImporter::getFloatIfMaterialValid(Maybe<ai_real> ObjFile::Material::*member) {
  435|       |    // It can directly access `m_pModel` because it's part of the class
  436|    348|    if (m_pModel != nullptr && m_pModel->mCurrentMaterial != nullptr) {
  ------------------
  |  Branch (436:9): [True: 348, False: 0]
  |  Branch (436:32): [True: 348, False: 0]
  ------------------
  437|    348|        getFloatValue(m_pModel->mCurrentMaterial->*member);
  438|    348|    }
  439|    348|}
_ZN6Assimp18ObjFileMtlImporter14createMaterialEv:
  443|  8.08k|void ObjFileMtlImporter::createMaterial() {
  444|  8.08k|    std::string line;
  445|   599k|    while (!IsLineEnd(*m_DataIt)) {
  ------------------
  |  Branch (445:12): [True: 590k, False: 8.08k]
  ------------------
  446|   590k|        line += *m_DataIt;
  447|   590k|        ++m_DataIt;
  448|   590k|    }
  449|       |
  450|  8.08k|    std::vector<std::string> token;
  451|  8.08k|    const unsigned int numToken = tokenize<std::string>(line, token, " \t");
  452|  8.08k|    std::string name;
  453|  8.08k|    if (numToken == 1) {
  ------------------
  |  Branch (453:9): [True: 4.91k, False: 3.16k]
  ------------------
  454|  4.91k|        name = AI_DEFAULT_MATERIAL_NAME;
  455|  4.91k|    } else {
  456|       |        // skip newmtl and all following white spaces
  457|  3.16k|        std::size_t first_ws_pos = line.find_first_of(" \t");
  458|  3.16k|        std::size_t first_non_ws_pos = line.find_first_not_of(" \t", first_ws_pos);
  459|  3.16k|        if (first_non_ws_pos != std::string::npos) {
  ------------------
  |  Branch (459:13): [True: 3.16k, False: 0]
  ------------------
  460|  3.16k|            name = line.substr(first_non_ws_pos);
  461|  3.16k|        }
  462|  3.16k|    }
  463|       |
  464|  8.08k|    name = ai_trim(name);
  465|       |
  466|  8.08k|    std::map<std::string, ObjFile::Material *>::iterator it = m_pModel->mMaterialMap.find(name);
  467|  8.08k|    if (m_pModel->mMaterialMap.end() == it) {
  ------------------
  |  Branch (467:9): [True: 92, False: 7.98k]
  ------------------
  468|       |        // New Material created
  469|     92|        m_pModel->mCurrentMaterial = new ObjFile::Material();
  470|     92|        m_pModel->mCurrentMaterial->MaterialName.Set(name);
  471|     92|        m_pModel->mMaterialLib.push_back(name);
  472|     92|        m_pModel->mMaterialMap[name] = m_pModel->mCurrentMaterial;
  473|       |
  474|     92|        if (m_pModel->mCurrentMesh) {
  ------------------
  |  Branch (474:13): [True: 24, False: 68]
  ------------------
  475|     24|            m_pModel->mCurrentMesh->m_uiMaterialIndex = static_cast<unsigned int>(m_pModel->mMaterialLib.size() - 1);
  476|     24|        }
  477|  7.98k|    } else {
  478|       |        // Use older material
  479|  7.98k|        m_pModel->mCurrentMaterial = it->second;
  480|  7.98k|    }
  481|  8.08k|}
_ZN6Assimp18ObjFileMtlImporter10getTextureEv:
  485|   249k|void ObjFileMtlImporter::getTexture() {
  486|   249k|    aiString *out = nullptr;
  487|   249k|    int clampIndex = -1;
  488|       |
  489|   249k|    if (m_pModel->mCurrentMaterial == nullptr) {
  ------------------
  |  Branch (489:9): [True: 24, False: 249k]
  ------------------
  490|     24|        m_pModel->mCurrentMaterial = new ObjFile::Material();
  491|     24|        m_pModel->mCurrentMaterial->MaterialName.Set("Empty_Material");
  492|     24|        m_pModel->mMaterialMap["Empty_Material"] = m_pModel->mCurrentMaterial;
  493|     24|    }
  494|       |
  495|   249k|    const char *pPtr(&(*m_DataIt));
  496|   249k|    if (!ASSIMP_strincmp(pPtr, DiffuseTexture, static_cast<unsigned int>(strlen(DiffuseTexture)))) {
  ------------------
  |  Branch (496:9): [True: 72, False: 249k]
  ------------------
  497|       |        // Diffuse texture
  498|     72|        out = &m_pModel->mCurrentMaterial->texture;
  499|     72|        clampIndex = ObjFile::Material::TextureDiffuseType;
  500|   249k|    } else if (!ASSIMP_strincmp(pPtr, AmbientTexture, static_cast<unsigned int>(strlen(AmbientTexture)))) {
  ------------------
  |  Branch (500:16): [True: 295, False: 249k]
  ------------------
  501|       |        // Ambient texture
  502|    295|        out = &m_pModel->mCurrentMaterial->textureAmbient;
  503|    295|        clampIndex = ObjFile::Material::TextureAmbientType;
  504|   249k|    } else if (!ASSIMP_strincmp(pPtr, SpecularTexture, static_cast<unsigned int>(strlen(SpecularTexture)))) {
  ------------------
  |  Branch (504:16): [True: 2.44k, False: 247k]
  ------------------
  505|       |        // Specular texture
  506|  2.44k|        out = &m_pModel->mCurrentMaterial->textureSpecular;
  507|  2.44k|        clampIndex = ObjFile::Material::TextureSpecularType;
  508|   247k|    } else if (!ASSIMP_strincmp(pPtr, DisplacementTexture1, static_cast<unsigned int>(strlen(DisplacementTexture1))) ||
  ------------------
  |  Branch (508:16): [True: 0, False: 247k]
  ------------------
  509|   247k|               !ASSIMP_strincmp(pPtr, DisplacementTexture2, static_cast<unsigned int>(strlen(DisplacementTexture2)))) {
  ------------------
  |  Branch (509:16): [True: 0, False: 247k]
  ------------------
  510|       |        // Displacement texture
  511|      0|        out = &m_pModel->mCurrentMaterial->textureDisp;
  512|      0|        clampIndex = ObjFile::Material::TextureDispType;
  513|   247k|    } else if (!ASSIMP_strincmp(pPtr, OpacityTexture, static_cast<unsigned int>(strlen(OpacityTexture)))) {
  ------------------
  |  Branch (513:16): [True: 231k, False: 15.6k]
  ------------------
  514|       |        // Opacity texture
  515|   231k|        out = &m_pModel->mCurrentMaterial->textureOpacity;
  516|   231k|        clampIndex = ObjFile::Material::TextureOpacityType;
  517|   231k|    } else if (!ASSIMP_strincmp(pPtr, EmissiveTexture1, static_cast<unsigned int>(strlen(EmissiveTexture1))) ||
  ------------------
  |  Branch (517:16): [True: 813, False: 14.8k]
  ------------------
  518|  14.8k|               !ASSIMP_strincmp(pPtr, EmissiveTexture2, static_cast<unsigned int>(strlen(EmissiveTexture2)))) {
  ------------------
  |  Branch (518:16): [True: 9, False: 14.8k]
  ------------------
  519|       |        // Emissive texture
  520|    822|        out = &m_pModel->mCurrentMaterial->textureEmissive;
  521|    822|        clampIndex = ObjFile::Material::TextureEmissiveType;
  522|  14.8k|    } else if (!ASSIMP_strincmp(pPtr, BumpTexture1, static_cast<unsigned int>(strlen(BumpTexture1))) ||
  ------------------
  |  Branch (522:16): [True: 131, False: 14.6k]
  ------------------
  523|  14.6k|               !ASSIMP_strincmp(pPtr, BumpTexture2, static_cast<unsigned int>(strlen(BumpTexture2)))) {
  ------------------
  |  Branch (523:16): [True: 2.72k, False: 11.9k]
  ------------------
  524|       |        // Bump texture
  525|  2.85k|        out = &m_pModel->mCurrentMaterial->textureBump;
  526|  2.85k|        clampIndex = ObjFile::Material::TextureBumpType;
  527|  11.9k|    } else if (!ASSIMP_strincmp(pPtr, NormalTextureV1, static_cast<unsigned int>(strlen(NormalTextureV1))) || !ASSIMP_strincmp(pPtr, NormalTextureV2, static_cast<unsigned int>(strlen(NormalTextureV2)))) {
  ------------------
  |  Branch (527:16): [True: 6.56k, False: 5.40k]
  |  Branch (527:111): [True: 170, False: 5.23k]
  ------------------
  528|       |        // Normal map
  529|  6.73k|        out = &m_pModel->mCurrentMaterial->textureNormal;
  530|  6.73k|        clampIndex = ObjFile::Material::TextureNormalType;
  531|  6.73k|    } else if (!ASSIMP_strincmp(pPtr, ReflectionTexture, static_cast<unsigned int>(strlen(ReflectionTexture)))) {
  ------------------
  |  Branch (531:16): [True: 0, False: 5.23k]
  ------------------
  532|       |        // Reflection texture(s)
  533|       |        //Do nothing here
  534|      0|        return;
  535|  5.23k|    } else if (!ASSIMP_strincmp(pPtr, SpecularityTexture, static_cast<unsigned int>(strlen(SpecularityTexture)))) {
  ------------------
  |  Branch (535:16): [True: 280, False: 4.95k]
  ------------------
  536|       |        // Specularity scaling (glossiness)
  537|    280|        out = &m_pModel->mCurrentMaterial->textureSpecularity;
  538|    280|        clampIndex = ObjFile::Material::TextureSpecularityType;
  539|  4.95k|    } else if ( !ASSIMP_strincmp( pPtr, RoughnessTexture, static_cast<unsigned int>(strlen(RoughnessTexture)))) {
  ------------------
  |  Branch (539:17): [True: 1.42k, False: 3.52k]
  ------------------
  540|       |        // PBR Roughness texture
  541|  1.42k|        out = & m_pModel->mCurrentMaterial->textureRoughness;
  542|  1.42k|        clampIndex = ObjFile::Material::TextureRoughnessType;
  543|  3.52k|    } else if ( !ASSIMP_strincmp( pPtr, MetallicTexture, static_cast<unsigned int>(strlen(MetallicTexture)))) {
  ------------------
  |  Branch (543:17): [True: 414, False: 3.11k]
  ------------------
  544|       |        // PBR Metallic texture
  545|    414|        out = & m_pModel->mCurrentMaterial->textureMetallic;
  546|    414|        clampIndex = ObjFile::Material::TextureMetallicType;
  547|  3.11k|    } else if (!ASSIMP_strincmp( pPtr, SheenTexture, static_cast<unsigned int>(strlen(SheenTexture)))) {
  ------------------
  |  Branch (547:16): [True: 24, False: 3.08k]
  ------------------
  548|       |        // PBR Sheen (reflectance) texture
  549|     24|        out = & m_pModel->mCurrentMaterial->textureSheen;
  550|     24|        clampIndex = ObjFile::Material::TextureSheenType;
  551|  3.08k|    } else if (!ASSIMP_strincmp( pPtr, RMATexture, static_cast<unsigned int>(strlen(RMATexture)))) {
  ------------------
  |  Branch (551:16): [True: 0, False: 3.08k]
  ------------------
  552|       |        // PBR Rough/Metal/AO texture
  553|      0|        out = & m_pModel->mCurrentMaterial->textureRMA;
  554|      0|        clampIndex = ObjFile::Material::TextureRMAType;
  555|  3.08k|    } else {
  556|  3.08k|        ASSIMP_LOG_ERROR("OBJ/MTL: Encountered unknown texture type");
  557|  3.08k|        return;
  558|  3.08k|    }
  559|       |
  560|   246k|    bool clamp = false;
  561|   246k|    getTextureOption(clamp, clampIndex, out);
  562|   246k|    m_pModel->mCurrentMaterial->clamp[clampIndex] = clamp;
  563|       |
  564|   246k|    std::string texture;
  565|   246k|    m_DataIt = getName<DataArrayIt>(m_DataIt, m_DataItEnd, texture);
  566|   246k|    if (nullptr != out) {
  ------------------
  |  Branch (566:9): [True: 246k, False: 0]
  ------------------
  567|   246k|        out->Set(m_strAbsPath + texture);
  568|   246k|    }
  569|   246k|}
_ZN6Assimp18ObjFileMtlImporter16getTextureOptionERbRiRP8aiString:
  586|   246k|void ObjFileMtlImporter::getTextureOption(bool &clamp, int &clampIndex, aiString *&out) {
  587|   246k|    m_DataIt = getNextToken<DataArrayIt>(m_DataIt, m_DataItEnd);
  588|       |
  589|       |    // If there is any more texture option
  590|   252k|    while (!isEndOfBuffer(m_DataIt, m_DataItEnd) && *m_DataIt == '-') {
  ------------------
  |  Branch (590:12): [True: 250k, False: 1.59k]
  |  Branch (590:53): [True: 5.69k, False: 245k]
  ------------------
  591|  5.69k|        const char *pPtr(&(*m_DataIt));
  592|       |        //skip option key and value
  593|  5.69k|        int skipToken = 1;
  594|       |
  595|  5.69k|        if (!ASSIMP_strincmp(pPtr, ClampOption, static_cast<unsigned int>(strlen(ClampOption)))) {
  ------------------
  |  Branch (595:13): [True: 0, False: 5.69k]
  ------------------
  596|      0|            DataArrayIt it = getNextToken<DataArrayIt>(m_DataIt, m_DataItEnd);
  597|      0|            char value[3];
  598|      0|            CopyNextWord(it, m_DataItEnd, value, sizeof(value) / sizeof(*value));
  599|      0|            if (!ASSIMP_strincmp(value, "on", 2)) {
  ------------------
  |  Branch (599:17): [True: 0, False: 0]
  ------------------
  600|      0|                clamp = true;
  601|      0|            }
  602|       |
  603|      0|            skipToken = 2;
  604|  5.69k|        } else if (!ASSIMP_strincmp(pPtr, TypeOption, static_cast<unsigned int>(strlen(TypeOption)))) {
  ------------------
  |  Branch (604:20): [True: 4.59k, False: 1.09k]
  ------------------
  605|  4.59k|            DataArrayIt it = getNextToken<DataArrayIt>(m_DataIt, m_DataItEnd);
  606|  4.59k|            char value[12];
  607|  4.59k|            CopyNextWord(it, m_DataItEnd, value, sizeof(value) / sizeof(*value));
  608|  4.59k|            if (!ASSIMP_strincmp(value, "cube_top", 8)) {
  ------------------
  |  Branch (608:17): [True: 0, False: 4.59k]
  ------------------
  609|      0|                clampIndex = ObjFile::Material::TextureReflectionCubeTopType;
  610|      0|                out = &m_pModel->mCurrentMaterial->textureReflection[0];
  611|  4.59k|            } else if (!ASSIMP_strincmp(value, "cube_bottom", 11)) {
  ------------------
  |  Branch (611:24): [True: 250, False: 4.34k]
  ------------------
  612|    250|                clampIndex = ObjFile::Material::TextureReflectionCubeBottomType;
  613|    250|                out = &m_pModel->mCurrentMaterial->textureReflection[1];
  614|  4.34k|            } else if (!ASSIMP_strincmp(value, "cube_front", 10)) {
  ------------------
  |  Branch (614:24): [True: 0, False: 4.34k]
  ------------------
  615|      0|                clampIndex = ObjFile::Material::TextureReflectionCubeFrontType;
  616|      0|                out = &m_pModel->mCurrentMaterial->textureReflection[2];
  617|  4.34k|            } else if (!ASSIMP_strincmp(value, "cube_back", 9)) {
  ------------------
  |  Branch (617:24): [True: 0, False: 4.34k]
  ------------------
  618|      0|                clampIndex = ObjFile::Material::TextureReflectionCubeBackType;
  619|      0|                out = &m_pModel->mCurrentMaterial->textureReflection[3];
  620|  4.34k|            } else if (!ASSIMP_strincmp(value, "cube_left", 9)) {
  ------------------
  |  Branch (620:24): [True: 0, False: 4.34k]
  ------------------
  621|      0|                clampIndex = ObjFile::Material::TextureReflectionCubeLeftType;
  622|      0|                out = &m_pModel->mCurrentMaterial->textureReflection[4];
  623|  4.34k|            } else if (!ASSIMP_strincmp(value, "cube_right", 10)) {
  ------------------
  |  Branch (623:24): [True: 0, False: 4.34k]
  ------------------
  624|      0|                clampIndex = ObjFile::Material::TextureReflectionCubeRightType;
  625|      0|                out = &m_pModel->mCurrentMaterial->textureReflection[5];
  626|  4.34k|            } else if (!ASSIMP_strincmp(value, "sphere", 6)) {
  ------------------
  |  Branch (626:24): [True: 230, False: 4.11k]
  ------------------
  627|    230|                clampIndex = ObjFile::Material::TextureReflectionSphereType;
  628|    230|                out = &m_pModel->mCurrentMaterial->textureReflection[0];
  629|    230|            }
  630|       |
  631|  4.59k|            skipToken = 2;
  632|  4.59k|        } else if (!ASSIMP_strincmp(pPtr, BumpOption, static_cast<unsigned int>(strlen(BumpOption)))) {
  ------------------
  |  Branch (632:20): [True: 221, False: 878]
  ------------------
  633|    221|            DataArrayIt it = getNextToken<DataArrayIt>(m_DataIt, m_DataItEnd);
  634|    221|            getFloat(it, m_DataItEnd, m_pModel->mCurrentMaterial->bump_multiplier);
  635|    221|            skipToken = 2;
  636|    878|        } else if (!ASSIMP_strincmp(pPtr, BlendUOption, static_cast<unsigned int>(strlen(BlendUOption))) ||
  ------------------
  |  Branch (636:20): [True: 0, False: 878]
  ------------------
  637|    878|                !ASSIMP_strincmp(pPtr, BlendVOption, static_cast<unsigned int>(strlen(BlendVOption))) ||
  ------------------
  |  Branch (637:17): [True: 0, False: 878]
  ------------------
  638|    878|                !ASSIMP_strincmp(pPtr, BoostOption, static_cast<unsigned int>(strlen(BoostOption))) ||
  ------------------
  |  Branch (638:17): [True: 0, False: 878]
  ------------------
  639|    878|                !ASSIMP_strincmp(pPtr, ResolutionOption, static_cast<unsigned int>(strlen(ResolutionOption))) ||
  ------------------
  |  Branch (639:17): [True: 0, False: 878]
  ------------------
  640|    878|                !ASSIMP_strincmp(pPtr, ChannelOption, static_cast<unsigned int>(strlen(ChannelOption)))) {
  ------------------
  |  Branch (640:17): [True: 0, False: 878]
  ------------------
  641|      0|            skipToken = 2;
  642|    878|        } else if (!ASSIMP_strincmp(pPtr, ModifyMapOption, static_cast<unsigned int>(strlen(ModifyMapOption)))) {
  ------------------
  |  Branch (642:20): [True: 32, False: 846]
  ------------------
  643|     32|            skipToken = 3;
  644|    846|        } else if (!ASSIMP_strincmp(pPtr, OffsetOption, static_cast<unsigned int>(strlen(OffsetOption))) ||
  ------------------
  |  Branch (644:20): [True: 144, False: 702]
  ------------------
  645|    702|                !ASSIMP_strincmp(pPtr, ScaleOption, static_cast<unsigned int>(strlen(ScaleOption))) ||
  ------------------
  |  Branch (645:17): [True: 0, False: 702]
  ------------------
  646|    737|                !ASSIMP_strincmp(pPtr, TurbulenceOption, static_cast<unsigned int>(strlen(TurbulenceOption)))) {
  ------------------
  |  Branch (646:17): [True: 593, False: 109]
  ------------------
  647|    737|            skipToken = 4;
  648|    737|        }
  649|       |
  650|  18.4k|        for (int i = 0; i < skipToken; ++i) {
  ------------------
  |  Branch (650:25): [True: 12.7k, False: 5.69k]
  ------------------
  651|  12.7k|            m_DataIt = getNextToken<DataArrayIt>(m_DataIt, m_DataItEnd);
  652|  12.7k|        }
  653|  5.69k|    }
  654|   246k|}

_ZN6Assimp18ObjFileMtlImporterD2Ev:
   74|  2.60k|    ~ObjFileMtlImporter() = default;

_ZN6Assimp13ObjFileParserC2ERNS_14IOStreamBufferIcEERKNSt3__112basic_stringIcNS4_11char_traitsIcEENS4_9allocatorIcEEEEPNS_8IOSystemEPNS_15ProgressHandlerESC_:
   90|     88|            mIO(io),
   91|     88|            mProgress(progress),
   92|     88|            mOriginalObjFileName(originalObjFileName) { 
   93|     88|    std::fill_n(mBuffer, Buffersize, '\0');
   94|       |
   95|       |    // Create the model instance to store all the data
   96|     88|    mModel.reset(new ObjFile::Model());
   97|     88|    mModel->mModelName = modelName;
   98|       |
   99|       |    // create default material and store it
  100|     88|    mModel->mDefaultMaterial = new ObjFile::Material;
  101|     88|    mModel->mDefaultMaterial->MaterialName.Set(DEFAULT_MATERIAL);
  102|     88|    mModel->mMaterialLib.emplace_back(DEFAULT_MATERIAL);
  103|     88|    mModel->mMaterialMap[DEFAULT_MATERIAL] = mModel->mDefaultMaterial;
  104|       |
  105|       |    // Start parsing the file
  106|     88|    parseFile(streamBuffer);
  107|     88|}
_ZNK6Assimp13ObjFileParser8GetModelEv:
  119|     78|ObjFile::Model *ObjFileParser::GetModel() const {
  120|     78|    return mModel.get();
  121|     78|}
_ZN6Assimp13ObjFileParser9parseFileERNS_14IOStreamBufferIcEE:
  124|     88|void ObjFileParser::parseFile(IOStreamBuffer<char> &streamBuffer) {
  125|       |    // only update every 100KB or it'll be too slow
  126|       |    // const unsigned int updateProgressEveryBytes = 100 * 1024;
  127|     88|    const unsigned int bytesToProcess = static_cast<unsigned int>(streamBuffer.size());
  128|     88|    const unsigned int progressTotal = bytesToProcess;
  129|     88|    unsigned int processed = 0u;
  130|     88|    size_t lastFilePos = 0u;
  131|       |
  132|     88|    bool insideCstype = false;
  133|     88|    std::vector<char> buffer;
  134|   286k|    while (streamBuffer.getNextDataLine(buffer, '\\')) {
  ------------------
  |  Branch (134:12): [True: 286k, False: 78]
  ------------------
  135|   286k|        mDataIt = buffer.begin();
  136|   286k|        mDataItEnd = buffer.end();
  137|   286k|        mEnd = &buffer[buffer.size() - 1] + 1;
  138|       |
  139|   286k|        if (processed == 0 && std::distance(mDataIt, mDataItEnd) >= 3 &&
  ------------------
  |  Branch (139:13): [True: 88, False: 286k]
  |  Branch (139:13): [True: 0, False: 286k]
  |  Branch (139:31): [True: 88, False: 0]
  ------------------
  140|     88|            	static_cast<unsigned char>(*mDataIt) == 0xEF &&
  ------------------
  |  Branch (140:14): [True: 0, False: 88]
  ------------------
  141|      0|            	static_cast<unsigned char>(*(mDataIt + 1)) == 0xBB &&
  ------------------
  |  Branch (141:14): [True: 0, False: 0]
  ------------------
  142|      0|            	static_cast<unsigned char>(*(mDataIt + 2)) == 0xBF) {
  ------------------
  |  Branch (142:14): [True: 0, False: 0]
  ------------------
  143|      0|            mDataIt += 3; // skip BOM
  144|      0|        }
  145|       |
  146|       |        // Handle progress reporting
  147|   286k|        const size_t filePos = streamBuffer.getFilePos();
  148|   286k|        if (lastFilePos < filePos) {
  ------------------
  |  Branch (148:13): [True: 88, False: 286k]
  ------------------
  149|     88|            processed = static_cast<unsigned int>(filePos);
  150|     88|            lastFilePos = filePos;
  151|     88|			if (mProgress != nullptr) {
  ------------------
  |  Branch (151:8): [True: 88, False: 0]
  ------------------
  152|     88|				mProgress->UpdateFileRead(processed, progressTotal);
  153|     88|			}
  154|     88|        }
  155|       |
  156|       |        // handle c-stype section end (http://paulbourke.net/dataformats/obj/)
  157|   286k|        if (insideCstype) {
  ------------------
  |  Branch (157:13): [True: 2.89k, False: 283k]
  ------------------
  158|  2.89k|            switch (*mDataIt) {
  159|      7|	            case 'e': {
  ------------------
  |  Branch (159:14): [True: 7, False: 2.88k]
  ------------------
  160|      7|	                std::string name;
  161|      7|	                getNameNoSpace(mDataIt, mDataItEnd, name);
  162|      7|	                insideCstype = name != "end";
  163|      7|	            } break;
  164|  2.88k|				default:
  ------------------
  |  Branch (164:5): [True: 2.88k, False: 7]
  ------------------
  165|  2.88k|					break;
  166|  2.89k|            }
  167|  2.89k|            goto pf_skip_line;
  168|  2.89k|        }
  169|       |
  170|       |        // parse line
  171|   283k|        switch (*mDataIt) {
  172|  27.2k|        case 'v': // Parse a vertex texture coordinate
  ------------------
  |  Branch (172:9): [True: 27.2k, False: 256k]
  ------------------
  173|  27.2k|        {
  174|  27.2k|            ++mDataIt;
  175|  27.2k|            if (*mDataIt == ' ' || *mDataIt == '\t') {
  ------------------
  |  Branch (175:17): [True: 19.2k, False: 8.02k]
  |  Branch (175:36): [True: 1.65k, False: 6.36k]
  ------------------
  176|  20.8k|                size_t numComponents = getNumComponentsInDataDefinition();
  177|  20.8k|                if (numComponents == 3) {
  ------------------
  |  Branch (177:21): [True: 11.5k, False: 9.31k]
  ------------------
  178|       |                    // read in vertex definition
  179|  11.5k|                    getVector3(mModel->mVertices);
  180|  11.5k|                } else if (numComponents == 4) {
  ------------------
  |  Branch (180:28): [True: 606, False: 8.71k]
  ------------------
  181|       |                    // read in vertex definition (homogeneous coords)
  182|    606|                    getHomogeneousVector3(mModel->mVertices);
  183|  8.71k|                } else if (numComponents == 6) {
  ------------------
  |  Branch (183:28): [True: 42, False: 8.67k]
  ------------------
  184|       |                    // fill previous omitted vertex-colors by default
  185|     42|                    if (mModel->mVertexColors.size() < mModel->mVertices.size()) {
  ------------------
  |  Branch (185:25): [True: 10, False: 32]
  ------------------
  186|     10|                        mModel->mVertexColors.resize(mModel->mVertices.size(), aiVector3D(0, 0, 0));
  187|     10|                    }
  188|       |                    // read vertex and vertex-color
  189|     42|                    getTwoVectors3(mModel->mVertices, mModel->mVertexColors);
  190|     42|                }
  191|       |                // append omitted vertex-colors as default for the end if any vertex-color exists
  192|  20.8k|                if (!mModel->mVertexColors.empty() && mModel->mVertexColors.size() < mModel->mVertices.size()) {
  ------------------
  |  Branch (192:21): [True: 616, False: 20.2k]
  |  Branch (192:55): [True: 363, False: 253]
  ------------------
  193|    363|                    mModel->mVertexColors.resize(mModel->mVertices.size(), aiVector3D(0, 0, 0));
  194|    363|                }
  195|  20.8k|            } else if (*mDataIt == 't') {
  ------------------
  |  Branch (195:24): [True: 1.50k, False: 4.86k]
  ------------------
  196|       |                // read in texture coordinate ( 2D or 3D )
  197|  1.50k|                ++mDataIt;
  198|  1.50k|                size_t dim = getTexCoordVector(mModel->mTextureCoord);
  199|  1.50k|                mModel->mTextureCoordDim = std::max(mModel->mTextureCoordDim, (unsigned int)dim);
  200|  4.86k|            } else if (*mDataIt == 'n') {
  ------------------
  |  Branch (200:24): [True: 3.78k, False: 1.08k]
  ------------------
  201|       |                // Read in normal vector definition
  202|  3.78k|                ++mDataIt;
  203|  3.78k|                getVector3(mModel->mNormals);
  204|  3.78k|            }
  205|  27.2k|        } break;
  206|       |
  207|    628|        case 'p': // Parse a face, line or point statement
  ------------------
  |  Branch (207:9): [True: 628, False: 283k]
  ------------------
  208|  1.97k|        case 'l':
  ------------------
  |  Branch (208:9): [True: 1.34k, False: 282k]
  ------------------
  209|  13.9k|        case 'f': {
  ------------------
  |  Branch (209:9): [True: 11.9k, False: 271k]
  ------------------
  210|  13.9k|            getFace(*mDataIt == 'f' ? aiPrimitiveType_POLYGON : (*mDataIt == 'l' ? aiPrimitiveType_LINE : aiPrimitiveType_POINT));
  ------------------
  |  Branch (210:21): [True: 11.9k, False: 1.97k]
  |  Branch (210:66): [True: 1.34k, False: 628]
  ------------------
  211|  13.9k|        } break;
  212|       |
  213|    633|        case '#': // Parse a comment
  ------------------
  |  Branch (213:9): [True: 633, False: 283k]
  ------------------
  214|    633|        {
  215|    633|            skipComment();
  216|    633|        } break;
  217|       |
  218|  3.44k|        case 'u': // Parse a material desc. setter
  ------------------
  |  Branch (218:9): [True: 3.44k, False: 280k]
  ------------------
  219|  3.44k|        {
  220|  3.44k|            std::string name;
  221|  3.44k|            getNameNoSpace(mDataIt, mDataItEnd, name);
  222|       |
  223|  3.44k|            size_t nextSpace = name.find(' ');
  224|  3.44k|            if (nextSpace != std::string::npos)
  ------------------
  |  Branch (224:17): [True: 0, False: 3.44k]
  ------------------
  225|      0|                name = name.substr(0, nextSpace);
  226|       |
  227|  3.44k|            if (name == "usemtl") {
  ------------------
  |  Branch (227:17): [True: 2.11k, False: 1.33k]
  ------------------
  228|  2.11k|                getMaterialDesc();
  229|  2.11k|            }
  230|  3.44k|        } break;
  231|       |
  232|  8.29k|        case 'm': // Parse a material library or merging group ('mg')
  ------------------
  |  Branch (232:9): [True: 8.29k, False: 275k]
  ------------------
  233|  8.29k|        {
  234|  8.29k|            std::string name;
  235|       |
  236|  8.29k|            getNameNoSpace(mDataIt, mDataItEnd, name);
  237|       |
  238|  8.29k|            size_t nextSpace = name.find(' ');
  239|  8.29k|            if (nextSpace != std::string::npos)
  ------------------
  |  Branch (239:17): [True: 0, False: 8.29k]
  ------------------
  240|      0|                name = name.substr(0, nextSpace);
  241|       |
  242|  8.29k|            if (name == "mg")
  ------------------
  |  Branch (242:17): [True: 0, False: 8.29k]
  ------------------
  243|      0|                skipGroupNumberAndResolution();
  244|  8.29k|            else if (name == "mtllib")
  ------------------
  |  Branch (244:22): [True: 4.62k, False: 3.67k]
  ------------------
  245|  4.62k|                getMaterialLib();
  246|  3.67k|            else
  247|  3.67k|                goto pf_skip_line;
  248|  8.29k|        } break;
  249|       |
  250|  13.6k|        case 'g': // Parse group name
  ------------------
  |  Branch (250:9): [True: 13.6k, False: 270k]
  ------------------
  251|  13.6k|        {
  252|  13.6k|            getGroupName();
  253|  13.6k|        } break;
  254|       |
  255|  1.38k|        case 's': // Parse group number
  ------------------
  |  Branch (255:9): [True: 1.38k, False: 282k]
  ------------------
  256|  1.38k|        {
  257|  1.38k|            skipGroupNumber();
  258|  1.38k|        } break;
  259|       |
  260|  2.68k|        case 'o': // Parse object name
  ------------------
  |  Branch (260:9): [True: 2.68k, False: 281k]
  ------------------
  261|  2.68k|        {
  262|  2.68k|            getObjectName();
  263|  2.68k|        } break;
  264|       |
  265|    956|        case 'c': // handle cstype section start
  ------------------
  |  Branch (265:9): [True: 956, False: 282k]
  ------------------
  266|    956|        {
  267|    956|            std::string name;
  268|    956|            getNameNoSpace(mDataIt, mDataItEnd, name);
  269|    956|            insideCstype = name == "cstype";
  270|    956|            goto pf_skip_line;
  271|  8.29k|        }
  272|       |
  273|   211k|        default: {
  ------------------
  |  Branch (273:9): [True: 211k, False: 72.2k]
  ------------------
  274|   219k|        pf_skip_line:
  275|   219k|            mDataIt = skipLine<DataArrayIt>(mDataIt, mDataItEnd, mLine);
  276|   219k|        } break;
  277|   283k|        }
  278|   283k|    }
  279|     88|}
_ZN6Assimp13ObjFileParser12copyNextWordEPcm:
  282|  52.5k|void ObjFileParser::copyNextWord(char *pBuffer, size_t length) {
  283|  52.5k|    size_t index = 0;
  284|  52.5k|    mDataIt = getNextWord<DataArrayIt>(mDataIt, mDataItEnd);
  285|  52.5k|    if (*mDataIt == '\\') {
  ------------------
  |  Branch (285:9): [True: 0, False: 52.5k]
  ------------------
  286|      0|        ++mDataIt;
  287|      0|        ++mDataIt;
  288|      0|        mDataIt = getNextWord<DataArrayIt>(mDataIt, mDataItEnd);
  289|      0|    }
  290|   477k|    while (mDataIt != mDataItEnd && !IsSpaceOrNewLine(*mDataIt)) {
  ------------------
  |  Branch (290:12): [True: 477k, False: 0]
  |  Branch (290:37): [True: 425k, False: 52.5k]
  ------------------
  291|   425k|        pBuffer[index] = *mDataIt;
  292|   425k|        index++;
  293|   425k|        if (index == length - 1) {
  ------------------
  |  Branch (293:13): [True: 0, False: 425k]
  ------------------
  294|      0|            break;
  295|      0|        }
  296|   425k|        ++mDataIt;
  297|   425k|    }
  298|       |
  299|  52.5k|    ai_assert(index < length);
  ------------------
  |  |   67|  52.5k|#   define ai_assert(expression) (void)((!!(expression)) || (Assimp::aiAssertViolation(#expression, __FILE__, __LINE__), 0))
  |  |  ------------------
  |  |  |  Branch (67:41): [True: 52.5k, False: 0]
  |  |  |  Branch (67:61): [True: 0, False: 0]
  |  |  ------------------
  ------------------
  300|  52.5k|    pBuffer[index] = '\0';
  301|  52.5k|}
_ZN6Assimp13ObjFileParser32getNumComponentsInDataDefinitionEv:
  304|  22.3k|size_t ObjFileParser::getNumComponentsInDataDefinition() {
  305|  22.3k|    size_t numComponents(0);
  306|  22.3k|    const char *tmp = &mDataIt[0];
  307|  22.3k|    bool end_of_definition = false;
  308|  65.3k|    while (!end_of_definition) {
  ------------------
  |  Branch (308:12): [True: 65.3k, False: 0]
  ------------------
  309|  65.3k|        if (isDataDefinitionEnd(tmp)) {
  ------------------
  |  Branch (309:13): [True: 5, False: 65.3k]
  ------------------
  310|      5|            tmp += 2;
  311|  65.3k|        } else if (IsLineEnd(*tmp)) {
  ------------------
  |  Branch (311:20): [True: 0, False: 65.3k]
  ------------------
  312|      0|            end_of_definition = true;
  313|      0|        }
  314|  65.3k|        if (!SkipSpaces(&tmp, mEnd) || *tmp == '#') {
  ------------------
  |  Branch (314:13): [True: 417, False: 64.9k]
  |  Branch (314:40): [True: 508, False: 64.4k]
  ------------------
  315|    925|            break;
  316|    925|        }
  317|  64.4k|        const bool isNum(IsNumeric(*tmp) || isNanOrInf(tmp));
  ------------------
  |  Branch (317:26): [True: 58.8k, False: 5.52k]
  |  Branch (317:45): [True: 0, False: 5.52k]
  ------------------
  318|  64.4k|        SkipToken(tmp, mEnd);
  319|  64.4k|        if (isNum) {
  ------------------
  |  Branch (319:13): [True: 58.8k, False: 5.52k]
  ------------------
  320|  58.8k|            ++numComponents;
  321|  58.8k|        }
  322|  64.4k|        if (!SkipSpaces(&tmp, mEnd) || *tmp == '#') {
  ------------------
  |  Branch (322:13): [True: 21.4k, False: 42.9k]
  |  Branch (322:40): [True: 0, False: 42.9k]
  ------------------
  323|  21.4k|            break;
  324|  21.4k|        }
  325|  64.4k|    }
  326|       |
  327|  22.3k|    return numComponents;
  328|  22.3k|}
_ZN6Assimp13ObjFileParser17getTexCoordVectorERNSt3__16vectorI10aiVector3tIfENS1_9allocatorIS4_EEEE:
  331|  1.50k|size_t ObjFileParser::getTexCoordVector(std::vector<aiVector3D> &point3d_array) {
  332|  1.50k|    size_t numComponents = getNumComponentsInDataDefinition();
  333|  1.50k|    ai_real x, y, z;
  334|  1.50k|    if (2 == numComponents) {
  ------------------
  |  Branch (334:9): [True: 764, False: 738]
  ------------------
  335|    764|        copyNextWord(mBuffer, Buffersize);
  336|    764|        x = fast_atof(mBuffer);
  337|       |
  338|    764|        copyNextWord(mBuffer, Buffersize);
  339|    764|        y = fast_atof(mBuffer);
  340|    764|        z = 0.0;
  341|    764|    } else if (3 == numComponents) {
  ------------------
  |  Branch (341:16): [True: 738, False: 0]
  ------------------
  342|    738|        copyNextWord(mBuffer, Buffersize);
  343|    738|        x = fast_atof(mBuffer);
  344|       |
  345|    738|        copyNextWord(mBuffer, Buffersize);
  346|    738|        y = fast_atof(mBuffer);
  347|       |
  348|    738|        copyNextWord(mBuffer, Buffersize);
  349|    738|        z = fast_atof(mBuffer);
  350|    738|    } else {
  351|      0|        throw DeadlyImportError("OBJ: Invalid number of components");
  352|      0|    }
  353|       |
  354|       |    // Coerce nan and inf to 0 as is the OBJ default value
  355|  1.50k|    if (!std::isfinite(x))
  ------------------
  |  Branch (355:9): [True: 0, False: 1.50k]
  ------------------
  356|      0|        x = 0;
  357|       |
  358|  1.50k|    if (!std::isfinite(y))
  ------------------
  |  Branch (358:9): [True: 0, False: 1.50k]
  ------------------
  359|      0|        y = 0;
  360|       |
  361|  1.50k|    if (!std::isfinite(z))
  ------------------
  |  Branch (361:9): [True: 0, False: 1.50k]
  ------------------
  362|      0|        z = 0;
  363|       |
  364|  1.50k|    point3d_array.emplace_back(x, y, z);
  365|  1.50k|    mDataIt = skipLine<DataArrayIt>(mDataIt, mDataItEnd, mLine);
  366|  1.50k|    return numComponents;
  367|  1.50k|}
_ZN6Assimp13ObjFileParser10getVector3ERNSt3__16vectorI10aiVector3tIfENS1_9allocatorIS4_EEEE:
  370|  15.3k|void ObjFileParser::getVector3(std::vector<aiVector3D> &point3d_array) {
  371|  15.3k|    ai_real x, y, z;
  372|  15.3k|    copyNextWord(mBuffer, Buffersize);
  373|  15.3k|    x = fast_atof(mBuffer);
  374|       |
  375|  15.3k|    copyNextWord(mBuffer, Buffersize);
  376|  15.3k|    y = fast_atof(mBuffer);
  377|       |
  378|  15.3k|    copyNextWord(mBuffer, Buffersize);
  379|  15.3k|    z = fast_atof(mBuffer);
  380|       |
  381|  15.3k|    point3d_array.emplace_back(x, y, z);
  382|  15.3k|    mDataIt = skipLine<DataArrayIt>(mDataIt, mDataItEnd, mLine);
  383|  15.3k|}
_ZN6Assimp13ObjFileParser21getHomogeneousVector3ERNSt3__16vectorI10aiVector3tIfENS1_9allocatorIS4_EEEE:
  386|    606|void ObjFileParser::getHomogeneousVector3(std::vector<aiVector3D> &point3d_array) {
  387|    606|    ai_real x, y, z, w;
  388|    606|    copyNextWord(mBuffer, Buffersize);
  389|    606|    x = fast_atof(mBuffer);
  390|       |
  391|    606|    copyNextWord(mBuffer, Buffersize);
  392|    606|    y = fast_atof(mBuffer);
  393|       |
  394|    606|    copyNextWord(mBuffer, Buffersize);
  395|    606|    z = fast_atof(mBuffer);
  396|       |
  397|    606|    copyNextWord(mBuffer, Buffersize);
  398|    606|    w = fast_atof(mBuffer);
  399|       |
  400|    606|    if (w == 0)
  ------------------
  |  Branch (400:9): [True: 0, False: 606]
  ------------------
  401|      0|        throw DeadlyImportError("OBJ: Invalid component in homogeneous vector (Division by zero)");
  402|       |
  403|    606|    point3d_array.emplace_back(x / w, y / w, z / w);
  404|    606|    mDataIt = skipLine<DataArrayIt>(mDataIt, mDataItEnd, mLine);
  405|    606|}
_ZN6Assimp13ObjFileParser14getTwoVectors3ERNSt3__16vectorI10aiVector3tIfENS1_9allocatorIS4_EEEES8_:
  408|     42|void ObjFileParser::getTwoVectors3(std::vector<aiVector3D> &point3d_array_a, std::vector<aiVector3D> &point3d_array_b) {
  409|     42|    ai_real x, y, z;
  410|     42|    copyNextWord(mBuffer, Buffersize);
  411|     42|    x = fast_atof(mBuffer);
  412|       |
  413|     42|    copyNextWord(mBuffer, Buffersize);
  414|     42|    y = fast_atof(mBuffer);
  415|       |
  416|     42|    copyNextWord(mBuffer, Buffersize);
  417|     42|    z = fast_atof(mBuffer);
  418|       |
  419|     42|    point3d_array_a.emplace_back(x, y, z);
  420|       |
  421|     42|    copyNextWord(mBuffer, Buffersize);
  422|     42|    x = fast_atof(mBuffer);
  423|       |
  424|     42|    copyNextWord(mBuffer, Buffersize);
  425|     42|    y = fast_atof(mBuffer);
  426|       |
  427|     42|    copyNextWord(mBuffer, Buffersize);
  428|     42|    z = fast_atof(mBuffer);
  429|       |
  430|     42|    point3d_array_b.emplace_back(x, y, z);
  431|       |
  432|     42|    mDataIt = skipLine<DataArrayIt>(mDataIt, mDataItEnd, mLine);
  433|     42|}
_ZN6Assimp13ObjFileParser7getFaceE15aiPrimitiveType:
  452|  13.9k|void ObjFileParser::getFace(aiPrimitiveType type) {
  453|  13.9k|    mDataIt = getNextToken<DataArrayIt>(mDataIt, mDataItEnd);
  454|  13.9k|    if (mDataIt == mDataItEnd || *mDataIt == '\0') {
  ------------------
  |  Branch (454:9): [True: 0, False: 13.9k]
  |  Branch (454:34): [True: 0, False: 13.9k]
  ------------------
  455|      0|        return;
  456|      0|    }
  457|       |
  458|  13.9k|    ObjFile::Face *face = new ObjFile::Face(type);
  459|  13.9k|    bool hasNormal = false;
  460|       |
  461|  13.9k|    const int vSize = static_cast<unsigned int>(mModel->mVertices.size());
  462|  13.9k|    const int vtSize = static_cast<unsigned int>(mModel->mTextureCoord.size());
  463|  13.9k|    const int vnSize = static_cast<unsigned int>(mModel->mNormals.size());
  464|       |
  465|  13.9k|    const bool vt = (!mModel->mTextureCoord.empty());
  466|  13.9k|    const bool vn = (!mModel->mNormals.empty());
  467|  13.9k|    int iPos = 0;
  468|   191k|    while (mDataIt < mDataItEnd) {
  ------------------
  |  Branch (468:12): [True: 191k, False: 0]
  ------------------
  469|   191k|        int iStep = 1;
  470|       |
  471|   191k|        if (IsLineEnd(*mDataIt) || *mDataIt == '#') {
  ------------------
  |  Branch (471:13): [True: 13.9k, False: 177k]
  |  Branch (471:36): [True: 0, False: 177k]
  ------------------
  472|  13.9k|            break;
  473|  13.9k|        }
  474|       |
  475|   177k|        if (*mDataIt == '/') {
  ------------------
  |  Branch (475:13): [True: 40.2k, False: 137k]
  ------------------
  476|  40.2k|            if (type == aiPrimitiveType_POINT) {
  ------------------
  |  Branch (476:17): [True: 0, False: 40.2k]
  ------------------
  477|      0|                ASSIMP_LOG_ERROR("Obj: Separator unexpected in point statement");
  478|      0|            }
  479|  40.2k|            ++iPos;
  480|   137k|        } else if (IsSpaceOrNewLine(*mDataIt) || *mDataIt == '\v') {
  ------------------
  |  Branch (480:20): [True: 36.0k, False: 100k]
  |  Branch (480:50): [True: 18.4k, False: 82.4k]
  ------------------
  481|  54.5k|            iPos = 0;
  482|  82.4k|        } else {
  483|       |            //OBJ USES 1 Base ARRAYS!!!!
  484|  82.4k|            const int iVal = ::atoi(&(*mDataIt));
  485|       |
  486|       |            // increment iStep position based off of the sign and # of digits
  487|  82.4k|            int tmp = iVal;
  488|  82.4k|            if (iVal < 0) {
  ------------------
  |  Branch (488:17): [True: 18, False: 82.4k]
  ------------------
  489|     18|                ++iStep;
  490|     18|            }
  491|   204k|            while ((tmp = tmp / 10) != 0) {
  ------------------
  |  Branch (491:20): [True: 121k, False: 82.4k]
  ------------------
  492|   121k|                ++iStep;
  493|   121k|            }
  494|       |
  495|  82.4k|            if (iPos == 1 && !vt && vn) {
  ------------------
  |  Branch (495:17): [True: 20.5k, False: 61.8k]
  |  Branch (495:30): [True: 484, False: 20.0k]
  |  Branch (495:37): [True: 309, False: 175]
  ------------------
  496|    309|                iPos = 2; // skip texture coords for normals if there are no tex coords
  497|    309|            }
  498|       |
  499|  82.4k|            if (iVal > 0) {
  ------------------
  |  Branch (499:17): [True: 82.4k, False: 23]
  ------------------
  500|       |                // Store parsed index
  501|  82.4k|                if (0 == iPos) {
  ------------------
  |  Branch (501:21): [True: 43.2k, False: 39.1k]
  ------------------
  502|  43.2k|                    face->m_vertices.push_back(iVal - 1);
  503|  43.2k|                } else if (1 == iPos) {
  ------------------
  |  Branch (503:28): [True: 20.2k, False: 18.9k]
  ------------------
  504|  20.2k|                    face->m_texturCoords.push_back(iVal - 1);
  505|  20.2k|                } else if (2 == iPos) {
  ------------------
  |  Branch (505:28): [True: 18.9k, False: 0]
  ------------------
  506|  18.9k|                    face->m_normals.push_back(iVal - 1);
  507|  18.9k|                    hasNormal = true;
  508|  18.9k|                } else {
  509|      0|                    reportErrorTokenInFace();
  510|      0|                }
  511|  82.4k|            } else if (iVal < 0) {
  ------------------
  |  Branch (511:24): [True: 18, False: 5]
  ------------------
  512|       |                // Store relatively index
  513|     18|                if (0 == iPos) {
  ------------------
  |  Branch (513:21): [True: 12, False: 6]
  ------------------
  514|     12|                    face->m_vertices.push_back(vSize + iVal);
  515|     12|                } else if (1 == iPos) {
  ------------------
  |  Branch (515:28): [True: 2, False: 4]
  ------------------
  516|      2|                    face->m_texturCoords.push_back(vtSize + iVal);
  517|      4|                } else if (2 == iPos) {
  ------------------
  |  Branch (517:28): [True: 4, False: 0]
  ------------------
  518|      4|                    face->m_normals.push_back(vnSize + iVal);
  519|      4|                    hasNormal = true;
  520|      4|                } else {
  521|      0|                    reportErrorTokenInFace();
  522|      0|                }
  523|     18|            } else {
  524|       |                //On error, std::atoi will return 0 which is not a valid value
  525|      5|                delete face;
  526|      5|                throw DeadlyImportError("OBJ: Invalid face index.");
  527|      5|            }
  528|  82.4k|        }
  529|   177k|        mDataIt += iStep;
  530|   177k|    }
  531|       |
  532|  13.9k|    if (face->m_vertices.empty()) {
  ------------------
  |  Branch (532:9): [True: 1.33k, False: 12.6k]
  ------------------
  533|  1.33k|        ASSIMP_LOG_ERROR("Obj: Ignoring empty face");
  534|       |        // skip line and clean up
  535|  1.33k|        mDataIt = skipLine<DataArrayIt>(mDataIt, mDataItEnd, mLine);
  536|  1.33k|        delete face;
  537|  1.33k|        return;
  538|  1.33k|    }
  539|       |
  540|       |    // Set active material, if one set
  541|  12.6k|    if (nullptr != mModel->mCurrentMaterial) {
  ------------------
  |  Branch (541:9): [True: 8.54k, False: 4.06k]
  ------------------
  542|  8.54k|        face->m_pMaterial = mModel->mCurrentMaterial;
  543|  8.54k|    } else {
  544|  4.06k|        face->m_pMaterial = mModel->mDefaultMaterial;
  545|  4.06k|    }
  546|       |
  547|       |    // Create a default object, if nothing is there
  548|  12.6k|    if (nullptr == mModel->mCurrentObject) {
  ------------------
  |  Branch (548:9): [True: 22, False: 12.5k]
  ------------------
  549|     22|        createObject(DefaultObjName);
  550|     22|    }
  551|       |
  552|       |    // Assign face to mesh
  553|  12.6k|    if (nullptr == mModel->mCurrentMesh) {
  ------------------
  |  Branch (553:9): [True: 0, False: 12.6k]
  ------------------
  554|      0|        createMesh(DefaultObjName);
  555|      0|    }
  556|       |
  557|       |    // Store the face
  558|  12.6k|    mModel->mCurrentMesh->m_Faces.emplace_back(face);
  559|  12.6k|    mModel->mCurrentMesh->m_uiNumIndices += static_cast<unsigned int>(face->m_vertices.size());
  560|  12.6k|    mModel->mCurrentMesh->m_uiUVCoordinates[0] += static_cast<unsigned int>(face->m_texturCoords.size());
  561|  12.6k|    if (!mModel->mCurrentMesh->m_hasNormals && hasNormal) {
  ------------------
  |  Branch (561:9): [True: 6.34k, False: 6.25k]
  |  Branch (561:48): [True: 228, False: 6.12k]
  ------------------
  562|    228|        mModel->mCurrentMesh->m_hasNormals = true;
  563|    228|    }
  564|       |    // Skip the rest of the line
  565|  12.6k|    mDataIt = skipLine<DataArrayIt>(mDataIt, mDataItEnd, mLine);
  566|  12.6k|}
_ZN6Assimp13ObjFileParser15getMaterialDescEv:
  569|  2.11k|void ObjFileParser::getMaterialDesc() {
  570|       |    // Get next data for material data
  571|  2.11k|    mDataIt = getNextToken<DataArrayIt>(mDataIt, mDataItEnd);
  572|  2.11k|    if (mDataIt == mDataItEnd) {
  ------------------
  |  Branch (572:9): [True: 0, False: 2.11k]
  ------------------
  573|      0|        return;
  574|      0|    }
  575|       |
  576|  2.11k|    char *pStart = &(*mDataIt);
  577|  28.4k|    while (mDataIt != mDataItEnd && !IsLineEnd(*mDataIt)) {
  ------------------
  |  Branch (577:12): [True: 28.4k, False: 0]
  |  Branch (577:37): [True: 26.2k, False: 2.11k]
  ------------------
  578|  26.2k|        ++mDataIt;
  579|  26.2k|    }
  580|       |
  581|       |    // In some cases we should ignore this 'usemtl' command, this variable helps us to do so
  582|  2.11k|    bool skip = false;
  583|       |
  584|       |    // Get name
  585|  2.11k|    std::string strName(pStart, &(*mDataIt));
  586|  2.11k|    strName = ai_trim(strName);
  587|  2.11k|    if (strName.empty()) {
  ------------------
  |  Branch (587:9): [True: 4, False: 2.10k]
  ------------------
  588|      4|        skip = true;
  589|      4|    }
  590|       |
  591|       |    // If the current mesh has the same material, we will ignore that 'usemtl' command
  592|       |    // There is no need to create another object or even mesh here
  593|  2.11k|    if (!skip) {
  ------------------
  |  Branch (593:9): [True: 2.10k, False: 4]
  ------------------
  594|  2.10k|        if (mModel->mCurrentMaterial && mModel->mCurrentMaterial->MaterialName == aiString(strName)) {
  ------------------
  |  Branch (594:13): [True: 2.07k, False: 29]
  |  Branch (594:13): [True: 361, False: 1.74k]
  |  Branch (594:41): [True: 361, False: 1.71k]
  ------------------
  595|    361|            skip = true;
  596|    361|        }
  597|  2.10k|    }
  598|       |
  599|  2.11k|    if (!skip) {
  ------------------
  |  Branch (599:9): [True: 1.74k, False: 365]
  ------------------
  600|       |        // Search for material
  601|  1.74k|        std::map<std::string, ObjFile::Material *>::iterator it = mModel->mMaterialMap.find(strName);
  602|  1.74k|        if (it == mModel->mMaterialMap.end()) {
  ------------------
  |  Branch (602:13): [True: 315, False: 1.43k]
  ------------------
  603|       |            // Not found, so we don't know anything about the material except for its name.
  604|       |            // This may be the case if the material library is missing. We don't want to lose all
  605|       |            // materials if that happens, so create a new named material instead of discarding it
  606|       |            // completely.
  607|    315|            ASSIMP_LOG_ERROR("OBJ: failed to locate material ", strName, ", creating new material");
  608|    315|            mModel->mCurrentMaterial = new ObjFile::Material();
  609|    315|            mModel->mCurrentMaterial->MaterialName.Set(strName);
  610|    315|            mModel->mMaterialLib.push_back(strName);
  611|    315|            mModel->mMaterialMap[strName] = mModel->mCurrentMaterial;
  612|  1.43k|        } else {
  613|       |            // Found, using detected material
  614|  1.43k|            mModel->mCurrentMaterial = it->second;
  615|  1.43k|        }
  616|       |
  617|  1.74k|        if (needsNewMesh(strName)) {
  ------------------
  |  Branch (617:13): [True: 691, False: 1.05k]
  ------------------
  618|    691|            auto newMeshName = mModel->mActiveGroup.empty() ? strName : mModel->mActiveGroup;
  ------------------
  |  Branch (618:32): [True: 621, False: 70]
  ------------------
  619|    691|            createMesh(newMeshName);
  620|    691|        }
  621|       |
  622|  1.74k|        mModel->mCurrentMesh->m_uiMaterialIndex = getMaterialIndex(strName);
  623|  1.74k|    }
  624|       |
  625|       |    // Skip rest of line
  626|  2.11k|    mDataIt = skipLine<DataArrayIt>(mDataIt, mDataItEnd, mLine);
  627|  2.11k|}
_ZN6Assimp13ObjFileParser11skipCommentEv:
  631|    633|void ObjFileParser::skipComment() {
  632|    633|    mDataIt = skipLine<DataArrayIt>(mDataIt, mDataItEnd, mLine);
  633|    633|}
_ZN6Assimp13ObjFileParser14getMaterialLibEv:
  636|  4.62k|void ObjFileParser::getMaterialLib() {
  637|       |    // Translate tuple
  638|  4.62k|    mDataIt = getNextToken<DataArrayIt>(mDataIt, mDataItEnd);
  639|  4.62k|    if (mDataIt == mDataItEnd) {
  ------------------
  |  Branch (639:9): [True: 0, False: 4.62k]
  ------------------
  640|      0|        return;
  641|      0|    }
  642|       |
  643|  4.62k|    char *pStart = &(*mDataIt);
  644|   180k|    while (mDataIt != mDataItEnd && !IsLineEnd(*mDataIt)) {
  ------------------
  |  Branch (644:12): [True: 180k, False: 0]
  |  Branch (644:37): [True: 176k, False: 4.62k]
  ------------------
  645|   176k|        ++mDataIt;
  646|   176k|    }
  647|       |
  648|       |    // Check for existence
  649|  4.62k|    const std::string strMatName(pStart, &(*mDataIt));
  650|  4.62k|    std::string absName;
  651|       |
  652|       |    // Check if directive is valid.
  653|  4.62k|    if (0 == strMatName.length()) {
  ------------------
  |  Branch (653:9): [True: 30, False: 4.59k]
  ------------------
  654|     30|        ASSIMP_LOG_WARN("OBJ: no name for material library specified.");
  655|     30|        return;
  656|     30|    }
  657|       |
  658|  4.59k|    if (mIO->StackSize() > 0) {
  ------------------
  |  Branch (658:9): [True: 6, False: 4.58k]
  ------------------
  659|      6|        std::string path = mIO->CurrentDirectory();
  660|      6|        if ('/' != *path.rbegin()) {
  ------------------
  |  Branch (660:13): [True: 6, False: 0]
  ------------------
  661|      6|            path += '/';
  662|      6|        }
  663|      6|        absName += path;
  664|      6|        absName += strMatName;
  665|  4.58k|    } else {
  666|  4.58k|        absName = strMatName;
  667|  4.58k|    }
  668|       |	
  669|  4.59k|	std::unique_ptr<IOStream> pFile(mIO->Open(absName));
  670|  4.59k|    if (nullptr == pFile) {
  ------------------
  |  Branch (670:9): [True: 2.02k, False: 2.56k]
  ------------------
  671|  2.02k|        ASSIMP_LOG_ERROR("OBJ: Unable to locate material file ", strMatName);
  672|  2.02k|        std::string strMatFallbackName = mOriginalObjFileName.substr(0, mOriginalObjFileName.length() - 3) + "mtl";
  673|  2.02k|        ASSIMP_LOG_INFO("OBJ: Opening fallback material file ", strMatFallbackName);
  674|  2.02k|        pFile.reset(mIO->Open(strMatFallbackName));
  675|  2.02k|        if (!pFile) {
  ------------------
  |  Branch (675:13): [True: 1.98k, False: 43]
  ------------------
  676|  1.98k|            ASSIMP_LOG_ERROR("OBJ: Unable to locate fallback material file ", strMatFallbackName);
  677|  1.98k|            mDataIt = skipLine<DataArrayIt>(mDataIt, mDataItEnd, mLine);
  678|  1.98k|            return;
  679|  1.98k|        }
  680|  2.02k|    }
  681|       |
  682|       |    // Import material library data from file.
  683|       |    // Some exporters (e.g. Silo) will happily write out empty
  684|       |    // material files if the model doesn't use any materials, so we
  685|       |    // allow that.
  686|  2.60k|    std::vector<char> buffer;
  687|  2.60k|    BaseImporter::TextFileToBuffer(pFile.get(), buffer, BaseImporter::ALLOW_EMPTY);
  688|       |    //m_pIO->Close(pFile);
  689|       |
  690|       |    // Importing the material library
  691|  2.60k|    ObjFileMtlImporter mtlImporter(buffer, strMatName, mModel.get());
  692|  2.60k|}
_ZN6Assimp13ObjFileParser16getMaterialIndexERKNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEE:
  726|  7.04k|int ObjFileParser::getMaterialIndex(const std::string &strMaterialName) {
  727|  7.04k|    int mat_index = InvalidMaterialIndex;
  728|  7.04k|    if (strMaterialName.empty()) {
  ------------------
  |  Branch (728:9): [True: 0, False: 7.04k]
  ------------------
  729|      0|        return mat_index;
  730|      0|    }
  731|  35.8k|    for (size_t index = 0; index < mModel->mMaterialLib.size(); ++index) {
  ------------------
  |  Branch (731:28): [True: 35.8k, False: 13]
  ------------------
  732|  35.8k|        if (strMaterialName == mModel->mMaterialLib[index]) {
  ------------------
  |  Branch (732:13): [True: 7.03k, False: 28.8k]
  ------------------
  733|  7.03k|            mat_index = (int)index;
  734|  7.03k|            break;
  735|  7.03k|        }
  736|  35.8k|    }
  737|  7.04k|    return mat_index;
  738|  7.04k|}
_ZN6Assimp13ObjFileParser12getGroupNameEv:
  742|  13.6k|void ObjFileParser::getGroupName() {
  743|  13.6k|    std::string groupName;
  744|       |
  745|       |    // here we skip 'g ' from line
  746|  13.6k|    mDataIt = getNextToken<DataArrayIt>(mDataIt, mDataItEnd);
  747|  13.6k|    mDataIt = getName<DataArrayIt>(mDataIt, mDataItEnd, groupName);
  748|  13.6k|    if (isEndOfBuffer(mDataIt, mDataItEnd)) {
  ------------------
  |  Branch (748:9): [True: 0, False: 13.6k]
  ------------------
  749|      0|        return;
  750|      0|    }
  751|       |
  752|       |    // Change active group, if necessary
  753|  13.6k|    if (mModel->mActiveGroup != groupName) {
  ------------------
  |  Branch (753:9): [True: 11.0k, False: 2.57k]
  ------------------
  754|       |        // Search for already existing entry
  755|  11.0k|        ObjFile::Model::ConstGroupMapIt it = mModel->mGroups.find(groupName);
  756|       |
  757|       |        // We are mapping groups into the object structure
  758|  11.0k|        createObject(groupName);
  759|       |
  760|       |        // New group name, creating a new entry
  761|  11.0k|        if (it == mModel->mGroups.end()) {
  ------------------
  |  Branch (761:13): [True: 447, False: 10.6k]
  ------------------
  762|    447|            std::vector<unsigned int> *pFaceIDArray = new std::vector<unsigned int>;
  763|    447|            mModel->mGroups[groupName] = pFaceIDArray;
  764|    447|            mModel->mGroupFaceIDs = (pFaceIDArray);
  765|  10.6k|        } else {
  766|  10.6k|            mModel->mGroupFaceIDs = (*it).second;
  767|  10.6k|        }
  768|  11.0k|        mModel->mActiveGroup = groupName;
  769|  11.0k|    }
  770|  13.6k|    mDataIt = skipLine<DataArrayIt>(mDataIt, mDataItEnd, mLine);
  771|  13.6k|}
_ZN6Assimp13ObjFileParser15skipGroupNumberEv:
  774|  1.38k|void ObjFileParser::skipGroupNumber() {
  775|       |    // Not used
  776|       |
  777|  1.38k|    mDataIt = skipLine<DataArrayIt>(mDataIt, mDataItEnd, mLine);
  778|  1.38k|}
_ZN6Assimp13ObjFileParser13getObjectNameEv:
  790|  2.68k|void ObjFileParser::getObjectName() {
  791|  2.68k|    mDataIt = getNextToken<DataArrayIt>(mDataIt, mDataItEnd);
  792|  2.68k|    if (mDataIt == mDataItEnd) {
  ------------------
  |  Branch (792:9): [True: 0, False: 2.68k]
  ------------------
  793|      0|        return;
  794|      0|    }
  795|  2.68k|    char *pStart = &(*mDataIt);
  796|  26.2k|    while (mDataIt != mDataItEnd && !IsSpaceOrNewLine(*mDataIt)) {
  ------------------
  |  Branch (796:12): [True: 26.2k, False: 0]
  |  Branch (796:37): [True: 23.5k, False: 2.68k]
  ------------------
  797|  23.5k|        ++mDataIt;
  798|  23.5k|    }
  799|       |
  800|  2.68k|    std::string strObjectName(pStart, &(*mDataIt));
  801|  2.68k|    if (!strObjectName.empty()) {
  ------------------
  |  Branch (801:9): [True: 1.42k, False: 1.26k]
  ------------------
  802|       |        // Reset current object
  803|  1.42k|        mModel->mCurrentObject = nullptr;
  804|       |
  805|       |        // Search for actual object
  806|  15.0k|        for (auto it = mModel->mObjects.begin(); it != mModel->mObjects.end(); ++it) {
  ------------------
  |  Branch (806:50): [True: 14.9k, False: 169]
  ------------------
  807|  14.9k|            if ((*it)->m_strObjName == strObjectName) {
  ------------------
  |  Branch (807:17): [True: 1.25k, False: 13.6k]
  ------------------
  808|  1.25k|                mModel->mCurrentObject = *it;
  809|  1.25k|                break;
  810|  1.25k|            }
  811|  14.9k|        }
  812|       |
  813|       |        // Allocate a new object, if current one was not found before
  814|  1.42k|        if (mModel->mCurrentObject == nullptr) {
  ------------------
  |  Branch (814:13): [True: 169, False: 1.25k]
  ------------------
  815|    169|            createObject(strObjectName);
  816|    169|        }
  817|  1.42k|    }
  818|  2.68k|    mDataIt = skipLine<DataArrayIt>(mDataIt, mDataItEnd, mLine);
  819|  2.68k|}
_ZN6Assimp13ObjFileParser12createObjectERKNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEE:
  823|  11.2k|void ObjFileParser::createObject(const std::string &objName) {
  824|  11.2k|    ai_assert(nullptr != mModel);
  ------------------
  |  |   67|  11.2k|#   define ai_assert(expression) (void)((!!(expression)) || (Assimp::aiAssertViolation(#expression, __FILE__, __LINE__), 0))
  |  |  ------------------
  |  |  |  Branch (67:41): [True: 11.2k, False: 0]
  |  |  |  Branch (67:61): [True: 0, False: 0]
  |  |  ------------------
  ------------------
  825|       |
  826|  11.2k|    mModel->mCurrentObject = new ObjFile::Object;
  827|  11.2k|    mModel->mCurrentObject->m_strObjName = objName;
  828|  11.2k|    mModel->mObjects.push_back(mModel->mCurrentObject);
  829|       |
  830|  11.2k|    createMesh(objName);
  831|       |
  832|  11.2k|    if (mModel->mCurrentMaterial) {
  ------------------
  |  Branch (832:9): [True: 3.57k, False: 7.67k]
  ------------------
  833|  3.57k|        mModel->mCurrentMesh->m_uiMaterialIndex =
  834|  3.57k|                getMaterialIndex(mModel->mCurrentMaterial->MaterialName.data);
  835|  3.57k|        mModel->mCurrentMesh->m_pMaterial = mModel->mCurrentMaterial;
  836|  3.57k|    }
  837|  11.2k|}
_ZN6Assimp13ObjFileParser10createMeshERKNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEE:
  840|  11.9k|void ObjFileParser::createMesh(const std::string &meshName) {
  841|  11.9k|    ai_assert(nullptr != mModel);
  ------------------
  |  |   67|  11.9k|#   define ai_assert(expression) (void)((!!(expression)) || (Assimp::aiAssertViolation(#expression, __FILE__, __LINE__), 0))
  |  |  ------------------
  |  |  |  Branch (67:41): [True: 11.9k, False: 0]
  |  |  |  Branch (67:61): [True: 0, False: 0]
  |  |  ------------------
  ------------------
  842|       |
  843|  11.9k|    mModel->mCurrentMesh = new ObjFile::Mesh(meshName);
  844|  11.9k|    mModel->mMeshes.push_back(mModel->mCurrentMesh);
  845|  11.9k|    auto meshId = static_cast<unsigned int>(mModel->mMeshes.size() - 1);
  846|  11.9k|    if (mModel->mCurrentObject != nullptr) {
  ------------------
  |  Branch (846:9): [True: 11.9k, False: 24]
  ------------------
  847|  11.9k|        mModel->mCurrentObject->m_Meshes.push_back(meshId);
  848|  11.9k|    } else {
  849|       |        ASSIMP_LOG_ERROR("OBJ: No object detected to attach a new mesh instance.");
  850|     24|    }
  851|  11.9k|}
_ZN6Assimp13ObjFileParser12needsNewMeshERKNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEE:
  855|  1.74k|bool ObjFileParser::needsNewMesh(const std::string &materialName) {
  856|       |    // If no mesh data yet
  857|  1.74k|    if (mModel->mCurrentMesh == nullptr) {
  ------------------
  |  Branch (857:9): [True: 24, False: 1.72k]
  ------------------
  858|     24|        return true;
  859|     24|    }
  860|  1.72k|    bool newMat = false;
  861|  1.72k|    int matIdx = getMaterialIndex(materialName);
  862|  1.72k|    int curMatIdx = mModel->mCurrentMesh->m_uiMaterialIndex;
  863|  1.72k|    if (curMatIdx != int(ObjFile::Mesh::NoMaterial) && curMatIdx != matIdx
  ------------------
  |  Branch (863:9): [True: 1.70k, False: 15]
  |  Branch (863:56): [True: 1.70k, False: 4]
  ------------------
  864|       |            // no need create a new mesh if no faces in current
  865|       |            // lets say 'usemtl' goes straight after 'g'
  866|  1.70k|            && !mModel->mCurrentMesh->m_Faces.empty()) {
  ------------------
  |  Branch (866:16): [True: 667, False: 1.03k]
  ------------------
  867|       |        // New material -> only one material per mesh, so we need to create a new
  868|       |        // material
  869|    667|        newMat = true;
  870|    667|    }
  871|  1.72k|    return newMat;
  872|  1.74k|}
ObjFileParser.cpp:_ZN6AssimpL19isDataDefinitionEndEPKc:
   61|  65.3k|static bool isDataDefinitionEnd(const char *tmp) {
   62|  65.3k|	ai_assert(tmp != nullptr);
  ------------------
  |  |   67|  65.3k|#   define ai_assert(expression) (void)((!!(expression)) || (Assimp::aiAssertViolation(#expression, __FILE__, __LINE__), 0))
  |  |  ------------------
  |  |  |  Branch (67:41): [True: 65.3k, False: 0]
  |  |  |  Branch (67:61): [True: 0, False: 0]
  |  |  ------------------
  ------------------
   63|       |	
   64|  65.3k|    if (*tmp == '\\') {
  ------------------
  |  Branch (64:9): [True: 18, False: 65.3k]
  ------------------
   65|     18|        ++tmp;
   66|     18|        if (IsLineEnd(*tmp)) {
  ------------------
  |  Branch (66:13): [True: 5, False: 13]
  ------------------
   67|      5|            return true;
   68|      5|        }
   69|     18|    }
   70|  65.3k|    return false;
   71|  65.3k|}
ObjFileParser.cpp:_ZN6AssimpL10isNanOrInfEPKc:
   74|  5.52k|static bool isNanOrInf(const char *in) {
   75|  5.52k|	ai_assert(in != nullptr);
  ------------------
  |  |   67|  5.52k|#   define ai_assert(expression) (void)((!!(expression)) || (Assimp::aiAssertViolation(#expression, __FILE__, __LINE__), 0))
  |  |  ------------------
  |  |  |  Branch (67:41): [True: 5.52k, False: 0]
  |  |  |  Branch (67:61): [True: 0, False: 0]
  |  |  ------------------
  ------------------
   76|       |	
   77|       |    // Look for "nan" or "inf", case insensitive
   78|  5.52k|    return ((in[0] == 'N' || in[0] == 'n') && ASSIMP_strincmp(in, "nan", 3) == 0) ||
  ------------------
  |  Branch (78:14): [True: 148, False: 5.38k]
  |  Branch (78:30): [True: 2, False: 5.37k]
  |  Branch (78:47): [True: 0, False: 150]
  ------------------
   79|  5.52k|           ((in[0] == 'I' || in[0] == 'i') && ASSIMP_strincmp(in, "inf", 3) == 0);
  ------------------
  |  Branch (79:14): [True: 425, False: 5.10k]
  |  Branch (79:30): [True: 20, False: 5.08k]
  |  Branch (79:47): [True: 0, False: 445]
  ------------------
   80|  5.52k|}

_ZN6Assimp13ObjFileParserD2Ev:
   79|     78|    ~ObjFileParser() = default;

_ZN6Assimp14getNameNoSpaceINSt3__111__wrap_iterIPcEEEET_S5_S5_RNS1_12basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEE:
  192|  12.7k|inline char_t getNameNoSpace(char_t it, char_t end, std::string &name) {
  193|  12.7k|    name = "";
  194|  12.7k|    if (isEndOfBuffer(it, end)) {
  ------------------
  |  Branch (194:9): [True: 0, False: 12.7k]
  ------------------
  195|      0|        return end;
  196|      0|    }
  197|       |
  198|  12.7k|    char *pStart = &(*it);
  199|   114k|    while (!isEndOfBuffer(it, end) && !IsLineEnd(*it) && !IsSpaceOrNewLine(*it)) {
  ------------------
  |  Branch (199:12): [True: 114k, False: 0]
  |  Branch (199:39): [True: 110k, False: 3.22k]
  |  Branch (199:58): [True: 101k, False: 9.48k]
  ------------------
  200|   101k|        ++it;
  201|   101k|    }
  202|       |
  203|  25.4k|    while (isEndOfBuffer(it, end) || IsLineEnd(*it) || IsSpaceOrNewLine(*it)) {
  ------------------
  |  Branch (203:12): [True: 0, False: 25.4k]
  |  Branch (203:38): [True: 3.22k, False: 22.1k]
  |  Branch (203:56): [True: 9.48k, False: 12.7k]
  ------------------
  204|  12.7k|        --it;
  205|  12.7k|    }
  206|  12.7k|    ++it;
  207|       |
  208|       |    // Get name
  209|       |    // if there is no name, and the previous char is a separator, come back to start
  210|  12.7k|    while (&(*it) < pStart) {
  ------------------
  |  Branch (210:12): [True: 0, False: 12.7k]
  ------------------
  211|      0|        ++it;
  212|      0|    }
  213|  12.7k|    std::string strName(pStart, &(*it));
  214|  12.7k|    if (!strName.empty()) {
  ------------------
  |  Branch (214:9): [True: 12.7k, False: 0]
  ------------------
  215|  12.7k|        name = strName;
  216|  12.7k|    }
  217|       |
  218|  12.7k|    return it;
  219|  12.7k|}
_ZN6Assimp8skipLineINSt3__111__wrap_iterIPcEEEET_S5_S5_Rj:
  125|  6.84M|inline char_t skipLine(char_t it, char_t end, unsigned int &uiLine) {
  126|  6.84M|    if (it >= end) {
  ------------------
  |  Branch (126:9): [True: 1.59k, False: 6.84M]
  ------------------
  127|  1.59k|        return it;
  128|  1.59k|    }
  129|       |
  130|  87.5M|    while (!isEndOfBuffer(it, end) && !IsLineEnd(*it)) {
  ------------------
  |  Branch (130:12): [True: 87.5M, False: 1.01k]
  |  Branch (130:39): [True: 80.7M, False: 6.84M]
  ------------------
  131|  80.7M|        ++it;
  132|  80.7M|    }
  133|       |
  134|  6.84M|    if (it != end) {
  ------------------
  |  Branch (134:9): [True: 6.84M, False: 0]
  ------------------
  135|  6.84M|        ++it;
  136|  6.84M|        ++uiLine;
  137|  6.84M|    }
  138|       |    // fix .. from time to time there are spaces at the beginning of a material line
  139|  7.38M|    while (it != end && (*it == '\t' || *it == ' ')) {
  ------------------
  |  Branch (139:12): [True: 7.38M, False: 1.01k]
  |  Branch (139:26): [True: 442k, False: 6.94M]
  |  Branch (139:41): [True: 97.1k, False: 6.84M]
  ------------------
  140|   539k|        ++it;
  141|   539k|    }
  142|       |
  143|  6.84M|    return it;
  144|  6.84M|}
_ZN6Assimp11getNextWordINSt3__111__wrap_iterIPcEEEET_S5_S5_:
   77|  4.08M|inline Char_T getNextWord(Char_T pBuffer, Char_T pEnd) {
   78|  11.4M|    while (!isEndOfBuffer(pBuffer, pEnd)) {
  ------------------
  |  Branch (78:12): [True: 11.4M, False: 3.35k]
  ------------------
   79|  11.4M|        if (!IsSpaceOrNewLine(*pBuffer) || IsLineEnd(*pBuffer)) {
  ------------------
  |  Branch (79:13): [True: 3.83M, False: 7.57M]
  |  Branch (79:44): [True: 248k, False: 7.32M]
  ------------------
   80|  4.08M|            break;
   81|  4.08M|        }
   82|  7.32M|        ++pBuffer;
   83|  7.32M|    }
   84|       |
   85|  4.08M|    return pBuffer;
   86|  4.08M|}
_ZN6Assimp12getNextTokenINSt3__111__wrap_iterIPcEEEET_S5_S5_:
  112|   357k|inline Char_T getNextToken(Char_T pBuffer, Char_T pEnd) {
  113|   357k|    pBuffer = getNextDelimiter(pBuffer, pEnd);
  114|   357k|    return getNextWord(pBuffer, pEnd);
  115|   357k|}
_ZN6Assimp16getNextDelimiterINSt3__111__wrap_iterIPcEEEET_S5_S5_:
   95|  4.01M|inline Char_T getNextDelimiter(Char_T pBuffer, Char_T pEnd) {
   96|  34.7M|    while (!isEndOfBuffer(pBuffer, pEnd)) {
  ------------------
  |  Branch (96:12): [True: 34.7M, False: 3.35k]
  ------------------
   97|  34.7M|        if (IsSpaceOrNewLine(*pBuffer)) {
  ------------------
  |  Branch (97:13): [True: 4.01M, False: 30.6M]
  ------------------
   98|  4.01M|            break;
   99|  4.01M|        }
  100|  30.6M|        ++pBuffer;
  101|  30.6M|    }
  102|  4.01M|    return pBuffer;
  103|  4.01M|}
_ZN6Assimp7getNameINSt3__111__wrap_iterIPcEEEET_S5_S5_RNS1_12basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEE:
  155|   260k|inline char_t getName(char_t it, char_t end, std::string &name) {
  156|   260k|    name = "";
  157|   260k|    if (isEndOfBuffer(it, end)) {
  ------------------
  |  Branch (157:9): [True: 1.59k, False: 258k]
  ------------------
  158|  1.59k|        return end;
  159|  1.59k|    }
  160|       |
  161|   258k|    char *pStart = &(*it);
  162|  2.98M|    while (!isEndOfBuffer(it, end) && !IsLineEnd(*it)) {
  ------------------
  |  Branch (162:12): [True: 2.98M, False: 0]
  |  Branch (162:39): [True: 2.72M, False: 258k]
  ------------------
  163|  2.72M|        ++it;
  164|  2.72M|    }
  165|       |
  166|   258k|    while (IsSpace(*it)) {
  ------------------
  |  Branch (166:12): [True: 0, False: 258k]
  ------------------
  167|      0|        --it;
  168|      0|    }
  169|       |    // Get name
  170|       |    // if there is no name, and the previous char is a separator, come back to start
  171|   258k|    while (&(*it) < pStart) {
  ------------------
  |  Branch (171:12): [True: 0, False: 258k]
  ------------------
  172|      0|        ++it;
  173|      0|    }
  174|   258k|    std::string strName(pStart, &(*it));
  175|   258k|    if (!strName.empty()) {
  ------------------
  |  Branch (175:9): [True: 247k, False: 11.8k]
  ------------------
  176|   247k|        name = strName;
  177|   247k|    }
  178|       |
  179|       |
  180|   258k|    return it;
  181|   260k|}
_ZN6Assimp13isEndOfBufferINSt3__111__wrap_iterIPcEEEEbT_S5_:
   61|   137M|inline bool isEndOfBuffer(char_t it, char_t end) {
   62|   137M|    if (it == end) {
  ------------------
  |  Branch (62:9): [True: 0, False: 137M]
  ------------------
   63|      0|        return true;
   64|      0|    }
   65|   137M|    --end;
   66|       |
   67|   137M|    return (it == end);
   68|   137M|}
_ZN6Assimp8getFloatINSt3__111__wrap_iterIPcEEEET_S5_S5_Rf:
  253|    840|inline char_t getFloat(char_t it, char_t end, ai_real &value) {
  254|    840|    static const size_t BUFFERSIZE = 1024;
  255|    840|    char buffer[BUFFERSIZE] = {};
  256|    840|    it = CopyNextWord<char_t>(it, end, buffer, BUFFERSIZE);
  257|    840|    value = (ai_real)fast_atof(buffer);
  258|       |
  259|    840|    return it;
  260|    840|}
_ZN6Assimp12CopyNextWordINSt3__111__wrap_iterIPcEEEET_S5_S5_S3_m:
  230|  17.8k|inline char_t CopyNextWord(char_t it, char_t end, char *pBuffer, size_t length) {
  231|  17.8k|    size_t index = 0;
  232|  17.8k|    it = getNextWord<char_t>(it, end);
  233|   142k|    while (!IsSpaceOrNewLine(*it) && !isEndOfBuffer(it, end)) {
  ------------------
  |  Branch (233:12): [True: 125k, False: 17.2k]
  |  Branch (233:38): [True: 125k, False: 0]
  ------------------
  234|   125k|        pBuffer[index] = *it;
  235|   125k|        ++index;
  236|   125k|        if (index == length - 1) {
  ------------------
  |  Branch (236:13): [True: 542, False: 125k]
  ------------------
  237|    542|            break;
  238|    542|        }
  239|   125k|        ++it;
  240|   125k|    }
  241|  17.8k|    pBuffer[index] = '\0';
  242|  17.8k|    return it;
  243|  17.8k|}

_ZNK6Assimp4Ogre12OgreImporter7GetInfoEv:
   67|    634|const aiImporterDesc *OgreImporter::GetInfo() const {
   68|    634|    return &desc;
   69|    634|}
_ZNK6Assimp4Ogre12OgreImporter7CanReadERKNSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEEPNS_8IOSystemEb:
   76|    140|bool OgreImporter::CanRead(const std::string &pFile, Assimp::IOSystem *pIOHandler, bool /*checkSig*/) const {
   77|    140|    if (EndsWith(pFile, ".mesh.xml", false)) {
  ------------------
  |  Branch (77:9): [True: 0, False: 140]
  ------------------
   78|      0|        static const char *tokens[] = { "<mesh>" };
   79|      0|        return SearchFileHeaderForToken(pIOHandler, pFile, tokens, AI_COUNT_OF(tokens));
   80|      0|    }
   81|       |
   82|       |    /// @todo Read and validate first header chunk?
   83|    140|    return EndsWith(pFile, ".mesh", false);
   84|    140|}

OgreImporter.cpp:_ZN6Assimp4OgreL8EndsWithERKNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEES9_b:
   59|    560|static inline bool EndsWith(const std::string &s, const std::string &suffix, bool caseSensitive = true) {
   60|    560|    if (s.empty() || suffix.empty()) {
  ------------------
  |  Branch (60:9): [True: 0, False: 560]
  |  Branch (60:22): [True: 0, False: 560]
  ------------------
   61|      0|        return false;
   62|    560|    } else if (s.length() < suffix.length()) {
  ------------------
  |  Branch (62:16): [True: 0, False: 560]
  ------------------
   63|      0|        return false;
   64|      0|    }
   65|       |
   66|    560|    if (!caseSensitive) {
  ------------------
  |  Branch (66:9): [True: 280, False: 280]
  ------------------
   67|    280|        return EndsWith(ai_tolower(s), ai_tolower(suffix), true);
   68|    280|    }
   69|       |
   70|    280|    size_t len = suffix.length();
   71|    280|    std::string sSuffix = s.substr(s.length() - len, len);
   72|       |
   73|    280|    return (ASSIMP_stricmp(sSuffix, suffix) == 0);
   74|    560|}

_ZN6Assimp7OpenGEX15OpenGEXImporter15VertexContainerC2Ev:
  239|    624|        m_numColors(0), m_colors(nullptr), m_numUVComps(), m_textureCoords() {
  ------------------
  |  |   59|    624|#define nullptr nullptr
  ------------------
  240|       |    // empty
  241|    624|}
_ZN6Assimp7OpenGEX15OpenGEXImporter15VertexContainerD2Ev:
  244|    624|OpenGEXImporter::VertexContainer::~VertexContainer() {
  245|    624|    delete[] m_colors;
  246|       |
  247|  4.99k|    for (auto &texcoords : m_textureCoords) {
  ------------------
  |  Branch (247:26): [True: 4.99k, False: 624]
  ------------------
  248|  4.99k|        delete[] texcoords;
  249|  4.99k|    }
  250|    624|}
_ZN6Assimp7OpenGEX15OpenGEXImporter7RefInfoC2EP6aiNodeNS2_4TypeERNSt3__16vectorINS6_12basic_stringIcNS6_11char_traitsIcEENS6_9allocatorIcEEEENSB_ISD_EEEE:
  254|     10|        m_node(node),
  255|     10|        m_type(type),
  256|     10|        m_Names(names) {
  257|       |    // empty
  258|     10|}
_ZN6Assimp7OpenGEX15OpenGEXImporterC2Ev:
  262|    624|        m_root(nullptr),
  ------------------
  |  |   59|    624|#define nullptr nullptr
  ------------------
  263|    624|        m_nodeChildMap(),
  264|    624|        m_mesh2refMap(),
  265|    624|        m_material2refMap(),
  266|    624|        m_ctx(nullptr),
  ------------------
  |  |   59|    624|#define nullptr nullptr
  ------------------
  267|    624|        m_metrics(),
  268|    624|        m_currentNode(nullptr),
  ------------------
  |  |   59|    624|#define nullptr nullptr
  ------------------
  269|    624|        m_currentVertices(),
  270|    624|        m_currentMesh(nullptr),
  ------------------
  |  |   59|    624|#define nullptr nullptr
  ------------------
  271|    624|        m_currentMaterial(nullptr),
  ------------------
  |  |   59|    624|#define nullptr nullptr
  ------------------
  272|    624|        m_currentLight(nullptr),
  ------------------
  |  |   59|    624|#define nullptr nullptr
  ------------------
  273|    624|        m_currentCamera(nullptr),
  ------------------
  |  |   59|    624|#define nullptr nullptr
  ------------------
  274|    624|        m_tokenType(Grammar::NoneType),
  275|    624|        m_materialCache(),
  276|    624|        m_cameraCache(),
  277|    624|        m_lightCache(),
  278|    624|        m_nodeStack(),
  279|    624|        m_unresolvedRefStack() {
  280|       |    // empty
  281|    624|}
_ZNK6Assimp7OpenGEX15OpenGEXImporter7CanReadERKNSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEEPNS_8IOSystemEb:
  284|    140|bool OpenGEXImporter::CanRead(const std::string &file, IOSystem *pIOHandler, bool /*checkSig*/) const {
  285|    140|    static const char *tokens[] = { "Metric", "GeometryNode", "VertexArray (attrib", "IndexArray" };
  286|       |    return SearchFileHeaderForToken(pIOHandler, file, tokens, AI_COUNT_OF(tokens));
  287|    140|}
_ZN6Assimp7OpenGEX15OpenGEXImporter14InternReadFileERKNSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEEP7aiScenePNS_8IOSystemE:
  290|     14|void OpenGEXImporter::InternReadFile(const std::string &filename, aiScene *pScene, IOSystem *pIOHandler) {
  291|       |    // open source file
  292|     14|    std::unique_ptr<IOStream> file(pIOHandler->Open(filename, "rb"));
  293|     14|    if (!file) {
  ------------------
  |  Branch (293:9): [True: 0, False: 14]
  ------------------
  294|      0|        throw DeadlyImportError("Failed to open file ", filename);
  295|      0|    }
  296|       |
  297|     14|    std::vector<char> buffer;
  298|     14|    TextFileToBuffer(file.get(), buffer);
  299|       |
  300|     14|    OpenDDLParser myParser;
  301|     14|    myParser.setLogCallback(&logDDLParserMessage);
  302|     14|    myParser.setBuffer(&buffer[0], buffer.size());
  303|     14|    bool success(myParser.parse());
  304|     14|    if (success) {
  ------------------
  |  Branch (304:9): [True: 3, False: 11]
  ------------------
  305|      3|        m_ctx = myParser.getContext();
  306|      3|        pScene->mRootNode = new aiNode;
  307|      3|        pScene->mRootNode->mName.Set(filename);
  308|      3|        handleNodes(m_ctx->m_root, pScene);
  309|      3|    }
  310|       |
  311|     14|    copyMeshes(pScene);
  312|     14|    copyCameras(pScene);
  313|       |    // TODO: lights only partially implemented and breaking model import
  314|       |//    copyLights(pScene);
  315|     14|    copyMaterials(pScene);
  316|     14|    resolveReferences();
  317|     14|    createNodeTree(pScene);
  318|     14|}
_ZNK6Assimp7OpenGEX15OpenGEXImporter7GetInfoEv:
  321|    648|const aiImporterDesc *OpenGEXImporter::GetInfo() const {
  322|    648|    return &desc;
  323|    648|}
_ZN6Assimp7OpenGEX15OpenGEXImporter15SetupPropertiesEPKNS_8ImporterE:
  326|     14|void OpenGEXImporter::SetupProperties(const Importer *pImp) {
  327|     14|    if (nullptr == pImp) {
  ------------------
  |  |   59|     14|#define nullptr nullptr
  ------------------
  |  Branch (327:9): [True: 0, False: 14]
  ------------------
  328|      0|        return;
  329|      0|    }
  330|     14|}
_ZN6Assimp7OpenGEX15OpenGEXImporter11handleNodesEPN10ODDLParser7DDLNodeEP7aiScene:
  333|     34|void OpenGEXImporter::handleNodes(DDLNode *node, aiScene *pScene) {
  334|     34|    if (nullptr == node) {
  ------------------
  |  |   59|     34|#define nullptr nullptr
  ------------------
  |  Branch (334:9): [True: 0, False: 34]
  ------------------
  335|      0|        return;
  336|      0|    }
  337|       |
  338|     34|    DDLNode::DllNodeList children = node->getChildNodeList();
  339|    183|    for (DDLNode::DllNodeList::iterator it = children.begin(); it != children.end(); ++it) {
  ------------------
  |  Branch (339:64): [True: 149, False: 34]
  ------------------
  340|    149|        Grammar::TokenType tokenType(Grammar::matchTokenType((*it)->getType().c_str()));
  341|    149|        switch (tokenType) {
  342|     15|        case Grammar::MetricToken:
  ------------------
  |  Branch (342:9): [True: 15, False: 134]
  ------------------
  343|     15|            handleMetricNode(*it, pScene);
  344|     15|            break;
  345|       |
  346|     12|        case Grammar::NameToken:
  ------------------
  |  Branch (346:9): [True: 12, False: 137]
  ------------------
  347|     12|            handleNameNode(*it, pScene);
  348|     12|            break;
  349|       |
  350|     12|        case Grammar::ObjectRefToken:
  ------------------
  |  Branch (350:9): [True: 12, False: 137]
  ------------------
  351|     12|            handleObjectRefNode(*it, pScene);
  352|     12|            break;
  353|       |
  354|     11|        case Grammar::MaterialRefToken:
  ------------------
  |  Branch (354:9): [True: 11, False: 138]
  ------------------
  355|     11|            handleMaterialRefNode(*it, pScene);
  356|     11|            break;
  357|       |
  358|      0|        case Grammar::MetricKeyToken:
  ------------------
  |  Branch (358:9): [True: 0, False: 149]
  ------------------
  359|      0|            break;
  360|       |
  361|      5|        case Grammar::GeometryNodeToken:
  ------------------
  |  Branch (361:9): [True: 5, False: 144]
  ------------------
  362|      5|            handleGeometryNode(*it, pScene);
  363|      5|            break;
  364|       |
  365|      7|        case Grammar::CameraNodeToken:
  ------------------
  |  Branch (365:9): [True: 7, False: 142]
  ------------------
  366|      7|            handleCameraNode(*it, pScene);
  367|      7|            break;
  368|       |
  369|      7|        case Grammar::LightNodeToken:
  ------------------
  |  Branch (369:9): [True: 7, False: 142]
  ------------------
  370|       |            // TODO: lights only partially implemented and breaking model import
  371|       |//            handleLightNode(*it, pScene);
  372|      7|            break;
  373|       |
  374|      6|        case Grammar::GeometryObjectToken:
  ------------------
  |  Branch (374:9): [True: 6, False: 143]
  ------------------
  375|      6|            handleGeometryObject(*it, pScene);
  376|      6|            break;
  377|       |
  378|      7|        case Grammar::CameraObjectToken:
  ------------------
  |  Branch (378:9): [True: 7, False: 142]
  ------------------
  379|      7|            handleCameraObject(*it, pScene);
  380|      7|            break;
  381|       |
  382|      7|        case Grammar::LightObjectToken:
  ------------------
  |  Branch (382:9): [True: 7, False: 142]
  ------------------
  383|       |            // TODO: lights only partially implemented and breaking model import
  384|       |//            handleLightObject(*it, pScene);
  385|      7|            break;
  386|       |
  387|     12|        case Grammar::TransformToken:
  ------------------
  |  Branch (387:9): [True: 12, False: 137]
  ------------------
  388|     12|            handleTransformNode(*it, pScene);
  389|     12|            break;
  390|       |
  391|      6|        case Grammar::MeshToken:
  ------------------
  |  Branch (391:9): [True: 6, False: 143]
  ------------------
  392|      6|            handleMeshNode(*it, pScene);
  393|      6|            break;
  394|       |
  395|     14|        case Grammar::VertexArrayToken:
  ------------------
  |  Branch (395:9): [True: 14, False: 135]
  ------------------
  396|     14|            handleVertexArrayNode(*it, pScene);
  397|     14|            break;
  398|       |
  399|      5|        case Grammar::IndexArrayToken:
  ------------------
  |  Branch (399:9): [True: 5, False: 144]
  ------------------
  400|      5|            handleIndexArrayNode(*it, pScene);
  401|      5|            break;
  402|       |
  403|      0|        case Grammar::MaterialToken:
  ------------------
  |  Branch (403:9): [True: 0, False: 149]
  ------------------
  404|      0|            handleMaterialNode(*it, pScene);
  405|      0|            break;
  406|       |
  407|      0|        case Grammar::ColorToken:
  ------------------
  |  Branch (407:9): [True: 0, False: 149]
  ------------------
  408|      0|            handleColorNode(*it, pScene);
  409|      0|            break;
  410|       |
  411|     21|        case Grammar::ParamToken:
  ------------------
  |  Branch (411:9): [True: 21, False: 128]
  ------------------
  412|     21|            handleParamNode(*it, pScene);
  413|     21|            break;
  414|       |
  415|      0|        case Grammar::TextureToken:
  ------------------
  |  Branch (415:9): [True: 0, False: 149]
  ------------------
  416|      0|            handleTextureNode(*it, pScene);
  417|      0|            break;
  418|       |
  419|      2|        default:
  ------------------
  |  Branch (419:9): [True: 2, False: 147]
  ------------------
  420|      2|            break;
  421|    149|        }
  422|    149|    }
  423|     34|}
_ZN6Assimp7OpenGEX15OpenGEXImporter16handleMetricNodeEPN10ODDLParser7DDLNodeEP7aiScene:
  426|     15|void OpenGEXImporter::handleMetricNode(DDLNode *node, aiScene * /*pScene*/) {
  427|     15|    if (nullptr == node || nullptr == m_ctx) {
  ------------------
  |  |   59|     15|#define nullptr nullptr
  ------------------
                  if (nullptr == node || nullptr == m_ctx) {
  ------------------
  |  |   59|     15|#define nullptr nullptr
  ------------------
  |  Branch (427:9): [True: 0, False: 15]
  |  Branch (427:28): [True: 0, False: 15]
  ------------------
  428|      0|        return;
  429|      0|    }
  430|       |
  431|     15|    if (m_ctx->m_root != node->getParent()) {
  ------------------
  |  Branch (431:9): [True: 0, False: 15]
  ------------------
  432|      0|        return;
  433|      0|    }
  434|       |
  435|     15|    Property *prop(node->getProperties());
  436|     27|    while (nullptr != prop) {
  ------------------
  |  |   59|     27|#define nullptr nullptr
  ------------------
  |  Branch (436:12): [True: 12, False: 15]
  ------------------
  437|     12|        if (nullptr != prop->m_key) {
  ------------------
  |  |   59|     12|#define nullptr nullptr
  ------------------
  |  Branch (437:13): [True: 12, False: 0]
  ------------------
  438|     12|            if (Value::ValueType::ddl_string == prop->m_value->m_type) {
  ------------------
  |  Branch (438:17): [True: 12, False: 0]
  ------------------
  439|     12|                std::string valName((char *)prop->m_value->m_data);
  440|     12|                int type(Grammar::isValidMetricType(valName.c_str()));
  441|     12|                if (Grammar::NoneType != type) {
  ------------------
  |  Branch (441:21): [True: 12, False: 0]
  ------------------
  442|     12|                    Value *val(node->getValue());
  443|     12|                    if (nullptr != val) {
  ------------------
  |  |   59|     12|#define nullptr nullptr
  ------------------
  |  Branch (443:25): [True: 12, False: 0]
  ------------------
  444|     12|                        if (Value::ValueType::ddl_float == val->m_type) {
  ------------------
  |  Branch (444:29): [True: 9, False: 3]
  ------------------
  445|      9|                            m_metrics[type].m_floatValue = val->getFloat();
  446|      9|                        } else if (Value::ValueType::ddl_int32 == val->m_type) {
  ------------------
  |  Branch (446:36): [True: 0, False: 3]
  ------------------
  447|      0|                            m_metrics[type].m_intValue = val->getInt32();
  448|      3|                        } else if (Value::ValueType::ddl_string == val->m_type) {
  ------------------
  |  Branch (448:36): [True: 3, False: 0]
  ------------------
  449|      3|                            m_metrics[type].m_stringValue = std::string(val->getString());
  450|      3|                        } else {
  451|      0|                            throw DeadlyImportError("OpenGEX: invalid data type for Metric node.");
  452|      0|                        }
  453|     12|                    }
  454|     12|                }
  455|     12|            }
  456|     12|        }
  457|     12|        prop = prop->m_next;
  458|     12|    }
  459|     15|}
_ZN6Assimp7OpenGEX15OpenGEXImporter14handleNameNodeEPN10ODDLParser7DDLNodeEP7aiScene:
  462|     12|void OpenGEXImporter::handleNameNode(DDLNode *node, aiScene * /*pScene*/) {
  463|     12|    if (nullptr == m_currentNode) {
  ------------------
  |  |   59|     12|#define nullptr nullptr
  ------------------
  |  Branch (463:9): [True: 0, False: 12]
  ------------------
  464|      0|        throw DeadlyImportError("No current node for name.");
  465|      0|    }
  466|       |
  467|     12|    Value *val(node->getValue());
  468|     12|    if (nullptr != val) {
  ------------------
  |  |   59|     12|#define nullptr nullptr
  ------------------
  |  Branch (468:9): [True: 12, False: 0]
  ------------------
  469|     12|        if (Value::ValueType::ddl_string != val->m_type) {
  ------------------
  |  Branch (469:13): [True: 0, False: 12]
  ------------------
  470|      0|            throw DeadlyImportError("OpenGEX: invalid data type for value in node name.");
  471|      0|        }
  472|       |
  473|     12|        const std::string name(val->getString());
  474|     12|        if (m_tokenType == Grammar::GeometryNodeToken ||
  ------------------
  |  Branch (474:13): [True: 5, False: 7]
  ------------------
  475|       |                // TODO: lights only partially implemented and breaking model import
  476|       |//                m_tokenType == Grammar::LightNodeToken ||
  477|     12|                m_tokenType == Grammar::CameraNodeToken) {
  ------------------
  |  Branch (477:17): [True: 7, False: 0]
  ------------------
  478|     12|            m_currentNode->mName.Set(name.c_str());
  479|     12|        } else if (m_tokenType == Grammar::MaterialToken) {
  ------------------
  |  Branch (479:20): [True: 0, False: 0]
  ------------------
  480|      0|            aiString aiName;
  481|      0|            aiName.Set(name);
  482|       |            m_currentMaterial->AddProperty(&aiName, AI_MATKEY_NAME);
  483|      0|            m_material2refMap[name] = m_materialCache.size() - 1;
  484|      0|        }
  485|     12|    }
  486|     12|}
_ZN6Assimp7OpenGEX15OpenGEXImporter19handleObjectRefNodeEPN10ODDLParser7DDLNodeEP7aiScene:
  511|     12|void OpenGEXImporter::handleObjectRefNode(DDLNode *node, aiScene * /*pScene*/) {
  512|     12|    if (nullptr == m_currentNode) {
  ------------------
  |  |   59|     12|#define nullptr nullptr
  ------------------
  |  Branch (512:9): [True: 0, False: 12]
  ------------------
  513|      0|        throw DeadlyImportError("No parent node for name.");
  514|      0|    }
  515|       |
  516|     12|    std::vector<std::string> objRefNames;
  517|     12|    getRefNames(node, objRefNames);
  518|       |
  519|       |    // when we are dealing with a geometry node prepare the mesh cache
  520|     12|    if (m_tokenType == Grammar::GeometryNodeToken) {
  ------------------
  |  Branch (520:9): [True: 5, False: 7]
  ------------------
  521|      5|        m_currentNode->mNumMeshes = static_cast<unsigned int>(objRefNames.size());
  522|      5|        m_currentNode->mMeshes = new unsigned int[objRefNames.size()];
  523|      5|        if (!objRefNames.empty()) {
  ------------------
  |  Branch (523:13): [True: 5, False: 0]
  ------------------
  524|      5|            m_unresolvedRefStack.push_back(std::unique_ptr<RefInfo>(new RefInfo(m_currentNode, RefInfo::MeshRef, objRefNames)));
  525|      5|        }
  526|      7|    } else if (m_tokenType == Grammar::LightNodeToken) {
  ------------------
  |  Branch (526:16): [True: 0, False: 7]
  ------------------
  527|       |        // TODO!
  528|      7|    } else if (m_tokenType == Grammar::CameraNodeToken) {
  ------------------
  |  Branch (528:16): [True: 7, False: 0]
  ------------------
  529|       |        // TODO!
  530|      7|    }
  531|     12|}
_ZN6Assimp7OpenGEX15OpenGEXImporter21handleMaterialRefNodeEPN10ODDLParser7DDLNodeEP7aiScene:
  534|     11|void OpenGEXImporter::handleMaterialRefNode(ODDLParser::DDLNode *node, aiScene * /*pScene*/) {
  535|     11|    if (nullptr == m_currentNode) {
  ------------------
  |  |   59|     11|#define nullptr nullptr
  ------------------
  |  Branch (535:9): [True: 0, False: 11]
  ------------------
  536|      0|        throw DeadlyImportError("No parent node for name.");
  537|      0|    }
  538|       |
  539|     11|    std::vector<std::string> matRefNames;
  540|     11|    getRefNames(node, matRefNames);
  541|     11|    if (!matRefNames.empty()) {
  ------------------
  |  Branch (541:9): [True: 5, False: 6]
  ------------------
  542|      5|        m_unresolvedRefStack.push_back(std::unique_ptr<RefInfo>(new RefInfo(m_currentNode, RefInfo::MaterialRef, matRefNames)));
  543|      5|    }
  544|     11|}
_ZN6Assimp7OpenGEX15OpenGEXImporter18handleGeometryNodeEPN10ODDLParser7DDLNodeEP7aiScene:
  547|      5|void OpenGEXImporter::handleGeometryNode(DDLNode *node, aiScene *pScene) {
  548|      5|    aiNode *newNode = new aiNode;
  549|      5|    pushNode(newNode, pScene);
  550|      5|    m_tokenType = Grammar::GeometryNodeToken;
  551|      5|    m_currentNode = newNode;
  552|      5|    handleNodes(node, pScene);
  553|       |
  554|      5|    popNode();
  555|      5|}
_ZN6Assimp7OpenGEX15OpenGEXImporter16handleCameraNodeEPN10ODDLParser7DDLNodeEP7aiScene:
  558|      7|void OpenGEXImporter::handleCameraNode(DDLNode *node, aiScene *pScene) {
  559|      7|    aiCamera *camera(new aiCamera);
  560|      7|    m_cameraCache.push_back(camera);
  561|      7|    m_currentCamera = camera;
  562|       |
  563|      7|    aiNode *newNode = new aiNode;
  564|      7|    pushNode(newNode, pScene);
  565|      7|    m_tokenType = Grammar::CameraNodeToken;
  566|      7|    m_currentNode = newNode;
  567|       |
  568|      7|    handleNodes(node, pScene);
  569|       |
  570|      7|    popNode();
  571|       |
  572|      7|    m_currentCamera->mName.Set(newNode->mName.C_Str());
  573|      7|}
_ZN6Assimp7OpenGEX15OpenGEXImporter20handleGeometryObjectEPN10ODDLParser7DDLNodeEP7aiScene:
  594|      6|void OpenGEXImporter::handleGeometryObject(DDLNode *node, aiScene *pScene) {
  595|       |    // parameters will be parsed normally in the tree, so just go for it
  596|      6|    handleNodes(node, pScene);
  597|      6|}
_ZN6Assimp7OpenGEX15OpenGEXImporter18handleCameraObjectEPN10ODDLParser7DDLNodeEP7aiScene:
  600|      7|void OpenGEXImporter::handleCameraObject(ODDLParser::DDLNode *node, aiScene *pScene) {
  601|       |    // parameters will be parsed normally in the tree, so just go for it
  602|       |
  603|      7|    handleNodes(node, pScene);
  604|      7|}
_ZN6Assimp7OpenGEX15OpenGEXImporter19handleTransformNodeEPN10ODDLParser7DDLNodeEP7aiScene:
  673|     12|void OpenGEXImporter::handleTransformNode(ODDLParser::DDLNode *node, aiScene * /*pScene*/) {
  674|     12|    if (nullptr == m_currentNode) {
  ------------------
  |  |   59|     12|#define nullptr nullptr
  ------------------
  |  Branch (674:9): [True: 0, False: 12]
  ------------------
  675|      0|        throw DeadlyImportError("No parent node for name.");
  676|      0|    }
  677|       |
  678|     12|    DataArrayList *transformData(node->getDataArrayList());
  679|     12|    if (nullptr != transformData) {
  ------------------
  |  |   59|     12|#define nullptr nullptr
  ------------------
  |  Branch (679:9): [True: 12, False: 0]
  ------------------
  680|     12|        if (transformData->m_numItems != 16) {
  ------------------
  |  Branch (680:13): [True: 0, False: 12]
  ------------------
  681|      0|            throw DeadlyImportError("Invalid number of data for transform matrix.");
  682|      0|        }
  683|     12|        setMatrix(m_currentNode, transformData);
  684|     12|    }
  685|     12|}
_ZN6Assimp7OpenGEX15OpenGEXImporter14handleMeshNodeEPN10ODDLParser7DDLNodeEP7aiScene:
  688|      6|void OpenGEXImporter::handleMeshNode(ODDLParser::DDLNode *node, aiScene *pScene) {
  689|      6|    m_currentMesh = new aiMesh;
  690|      6|    const size_t meshidx(m_meshCache.size());
  691|       |    // ownership is transferred but a reference remains in m_currentMesh
  692|      6|    m_meshCache.emplace_back(m_currentMesh);
  693|       |
  694|      6|    Property *prop = node->getProperties();
  695|      6|    if (nullptr != prop) {
  ------------------
  |  |   59|      6|#define nullptr nullptr
  ------------------
  |  Branch (695:9): [True: 6, False: 0]
  ------------------
  696|      6|        std::string propName, propKey;
  697|      6|        propId2StdString(prop, propName, propKey);
  698|      6|        if ("primitive" == propName) {
  ------------------
  |  Branch (698:13): [True: 6, False: 0]
  ------------------
  699|      6|            if ("points" == propKey) {
  ------------------
  |  Branch (699:17): [True: 0, False: 6]
  ------------------
  700|      0|                m_currentMesh->mPrimitiveTypes |= aiPrimitiveType_POINT;
  701|      6|            } else if ("lines" == propKey) {
  ------------------
  |  Branch (701:24): [True: 0, False: 6]
  ------------------
  702|      0|                m_currentMesh->mPrimitiveTypes |= aiPrimitiveType_LINE;
  703|      6|            } else if ("triangles" == propKey) {
  ------------------
  |  Branch (703:24): [True: 6, False: 0]
  ------------------
  704|      6|                m_currentMesh->mPrimitiveTypes |= aiPrimitiveType_TRIANGLE;
  705|      6|            } else if ("quads" == propKey) {
  ------------------
  |  Branch (705:24): [True: 0, False: 0]
  ------------------
  706|      0|                m_currentMesh->mPrimitiveTypes |= aiPrimitiveType_POLYGON;
  707|      0|            } else {
  708|      0|                ASSIMP_LOG_WARN(propKey, " is not supported primitive type.");
  709|      0|            }
  710|      6|        }
  711|      6|    }
  712|       |
  713|      6|    handleNodes(node, pScene);
  714|       |
  715|      6|    DDLNode *parent(node->getParent());
  716|      6|    if (nullptr != parent) {
  ------------------
  |  |   59|      6|#define nullptr nullptr
  ------------------
  |  Branch (716:9): [True: 6, False: 0]
  ------------------
  717|      6|        const std::string &name = parent->getName();
  718|      6|        m_mesh2refMap[name] = meshidx;
  719|      6|    }
  720|      6|}
_ZN6Assimp7OpenGEX15OpenGEXImporter21handleVertexArrayNodeEPN10ODDLParser7DDLNodeEP7aiScene:
  834|     14|void OpenGEXImporter::handleVertexArrayNode(ODDLParser::DDLNode *node, aiScene * /*pScene*/) {
  835|     14|    if (nullptr == node) {
  ------------------
  |  |   59|     14|#define nullptr nullptr
  ------------------
  |  Branch (835:9): [True: 0, False: 14]
  ------------------
  836|      0|        throw DeadlyImportError("No parent node for name.");
  837|      0|    }
  838|       |
  839|     14|    Property *prop = node->getProperties();
  840|     14|    if (nullptr != prop) {
  ------------------
  |  |   59|     14|#define nullptr nullptr
  ------------------
  |  Branch (840:9): [True: 14, False: 0]
  ------------------
  841|     14|        std::string propName, propKey;
  842|     14|        propId2StdString(prop, propName, propKey);
  843|     14|        MeshAttribute attribType(getAttributeByName(propKey.c_str()));
  844|     14|        if (None == attribType) {
  ------------------
  |  Branch (844:13): [True: 0, False: 14]
  ------------------
  845|      0|            return;
  846|      0|        }
  847|       |
  848|     14|        DataArrayList *vaList = node->getDataArrayList();
  849|     14|        if (nullptr == vaList) {
  ------------------
  |  |   59|     14|#define nullptr nullptr
  ------------------
  |  Branch (849:13): [True: 0, False: 14]
  ------------------
  850|      0|            return;
  851|      0|        }
  852|       |
  853|     14|        const size_t numItems(countDataArrayListItems(vaList));
  854|       |
  855|     14|        if (Position == attribType) {
  ------------------
  |  Branch (855:13): [True: 6, False: 8]
  ------------------
  856|      6|            m_currentVertices.m_vertices.resize(numItems);
  857|      6|            copyVectorArray(numItems, vaList, m_currentVertices.m_vertices.data());
  858|      8|        } else if (Color == attribType) {
  ------------------
  |  Branch (858:20): [True: 1, False: 7]
  ------------------
  859|      1|            m_currentVertices.m_numColors = numItems;
  860|      1|            m_currentVertices.m_colors = new aiColor4D[numItems];
  861|      1|            copyColor4DArray(numItems, vaList, m_currentVertices.m_colors);
  862|      7|        } else if (Normal == attribType) {
  ------------------
  |  Branch (862:20): [True: 6, False: 1]
  ------------------
  863|      6|            m_currentVertices.m_normals.resize(numItems);
  864|      6|            copyVectorArray(numItems, vaList, m_currentVertices.m_normals.data());
  865|      6|        } else if (TexCoord == attribType) {
  ------------------
  |  Branch (865:20): [True: 1, False: 0]
  ------------------
  866|      1|            m_currentVertices.m_numUVComps[0] = numItems;
  867|      1|            m_currentVertices.m_textureCoords[0] = new aiVector3D[numItems];
  868|      1|            copyVectorArray(numItems, vaList, m_currentVertices.m_textureCoords[0]);
  869|      1|        }
  870|     14|    }
  871|     14|}
_ZN6Assimp7OpenGEX15OpenGEXImporter20handleIndexArrayNodeEPN10ODDLParser7DDLNodeEP7aiScene:
  874|      5|void OpenGEXImporter::handleIndexArrayNode(ODDLParser::DDLNode *node, aiScene * /*pScene*/) {
  875|      5|    if (nullptr == node) {
  ------------------
  |  |   59|      5|#define nullptr nullptr
  ------------------
  |  Branch (875:9): [True: 0, False: 5]
  ------------------
  876|      0|        throw DeadlyImportError("No parent node for name.");
  877|      0|    }
  878|       |
  879|      5|    if (nullptr == m_currentMesh) {
  ------------------
  |  |   59|      5|#define nullptr nullptr
  ------------------
  |  Branch (879:9): [True: 0, False: 5]
  ------------------
  880|      0|        throw DeadlyImportError("No current mesh for index data found.");
  881|      0|    }
  882|       |
  883|      5|    DataArrayList *vaList = node->getDataArrayList();
  884|      5|    if (nullptr == vaList) {
  ------------------
  |  |   59|      5|#define nullptr nullptr
  ------------------
  |  Branch (884:9): [True: 0, False: 5]
  ------------------
  885|      0|        return;
  886|      0|    }
  887|       |
  888|      5|    const size_t numItems(countDataArrayListItems(vaList));
  889|      5|    m_currentMesh->mNumFaces = static_cast<unsigned int>(numItems);
  890|      5|    m_currentMesh->mFaces = new aiFace[numItems];
  891|      5|    m_currentMesh->mNumVertices = static_cast<unsigned int>(numItems * 3);
  892|      5|    m_currentMesh->mVertices = new aiVector3D[m_currentMesh->mNumVertices];
  893|      5|    bool hasColors(false);
  894|      5|    if (m_currentVertices.m_numColors > 0) {
  ------------------
  |  Branch (894:9): [True: 1, False: 4]
  ------------------
  895|      1|        m_currentMesh->mColors[0] = new aiColor4D[m_currentMesh->mNumVertices];
  896|      1|        hasColors = true;
  897|      1|    }
  898|      5|    bool hasNormalCoords(false);
  899|      5|    if (!m_currentVertices.m_normals.empty()) {
  ------------------
  |  Branch (899:9): [True: 5, False: 0]
  ------------------
  900|      5|        m_currentMesh->mNormals = new aiVector3D[m_currentMesh->mNumVertices];
  901|      5|        hasNormalCoords = true;
  902|      5|    }
  903|      5|    bool hasTexCoords(false);
  904|      5|    if (m_currentVertices.m_numUVComps[0] > 0) {
  ------------------
  |  Branch (904:9): [True: 1, False: 4]
  ------------------
  905|      1|        m_currentMesh->mTextureCoords[0] = new aiVector3D[m_currentMesh->mNumVertices];
  906|      1|        hasTexCoords = true;
  907|      1|    }
  908|       |
  909|      5|    unsigned int index(0);
  910|  6.79k|    for (size_t i = 0; i < m_currentMesh->mNumFaces; i++) {
  ------------------
  |  Branch (910:24): [True: 6.78k, False: 5]
  ------------------
  911|  6.78k|        aiFace &current(m_currentMesh->mFaces[i]);
  912|  6.78k|        current.mNumIndices = 3;
  913|  6.78k|        current.mIndices = new unsigned int[current.mNumIndices];
  914|  6.78k|        Value *next(vaList->m_dataList);
  915|  27.1k|        for (size_t indices = 0; indices < current.mNumIndices; indices++) {
  ------------------
  |  Branch (915:34): [True: 20.3k, False: 6.78k]
  ------------------
  916|  20.3k|            int idx = -1;
  917|  20.3k|            if (next->m_type == Value::ValueType::ddl_unsigned_int16) {
  ------------------
  |  Branch (917:17): [True: 0, False: 20.3k]
  ------------------
  918|      0|                idx = next->getUnsignedInt16();
  919|  20.3k|            } else if (next->m_type == Value::ValueType::ddl_unsigned_int32) {
  ------------------
  |  Branch (919:24): [True: 20.3k, False: 0]
  ------------------
  920|  20.3k|                idx = next->getUnsignedInt32();
  921|  20.3k|            }
  922|       |            
  923|  20.3k|            ai_assert(static_cast<size_t>(idx) <= m_currentVertices.m_vertices.size());
  924|  20.3k|            ai_assert(index < m_currentMesh->mNumVertices);
  925|  20.3k|            aiVector3D &pos = (m_currentVertices.m_vertices[idx]);
  926|  20.3k|            m_currentMesh->mVertices[index].Set(pos.x, pos.y, pos.z);
  927|  20.3k|            if (hasColors && static_cast<size_t>(idx) < m_currentVertices.m_numColors) {
  ------------------
  |  Branch (927:17): [True: 156, False: 20.2k]
  |  Branch (927:30): [True: 156, False: 0]
  ------------------
  928|    156|                aiColor4D &col = m_currentVertices.m_colors[idx];
  929|    156|                m_currentMesh->mColors[0][index] = col;
  930|    156|            }
  931|  20.3k|            if (hasNormalCoords) {
  ------------------
  |  Branch (931:17): [True: 20.3k, False: 0]
  ------------------
  932|  20.3k|                aiVector3D &normal = (m_currentVertices.m_normals[idx]);
  933|  20.3k|                m_currentMesh->mNormals[index].Set(normal.x, normal.y, normal.z);
  934|  20.3k|            }
  935|  20.3k|            if (hasTexCoords) {
  ------------------
  |  Branch (935:17): [True: 156, False: 20.2k]
  ------------------
  936|    156|                aiVector3D &tex = (m_currentVertices.m_textureCoords[0][idx]);
  937|    156|                m_currentMesh->mTextureCoords[0][index].Set(tex.x, tex.y, tex.z);
  938|    156|            }
  939|  20.3k|            current.mIndices[indices] = index;
  940|  20.3k|            index++;
  941|       |
  942|  20.3k|            next = next->m_next;
  943|  20.3k|        }
  944|  6.78k|        vaList = vaList->m_next;
  945|  6.78k|    }
  946|      5|}
_ZN6Assimp7OpenGEX15OpenGEXImporter15handleParamNodeEPN10ODDLParser7DDLNodeEP7aiScene:
 1096|     21|void OpenGEXImporter::handleParamNode(ODDLParser::DDLNode *node, aiScene * /*pScene*/) {
 1097|     21|    if (nullptr == node) {
  ------------------
  |  |   59|     21|#define nullptr nullptr
  ------------------
  |  Branch (1097:9): [True: 0, False: 21]
  ------------------
 1098|      0|        return;
 1099|      0|    }
 1100|       |
 1101|     21|    Property *prop = node->findPropertyByName("attrib");
 1102|     21|    if (nullptr == prop) {
  ------------------
  |  |   59|     21|#define nullptr nullptr
  ------------------
  |  Branch (1102:9): [True: 0, False: 21]
  ------------------
 1103|      0|        return;
 1104|      0|    }
 1105|       |
 1106|     21|    if (nullptr != prop->m_value) {
  ------------------
  |  |   59|     21|#define nullptr nullptr
  ------------------
  |  Branch (1106:9): [True: 21, False: 0]
  ------------------
 1107|     21|        Value *val(node->getValue());
 1108|     21|        if (nullptr == val) {
  ------------------
  |  |   59|     21|#define nullptr nullptr
  ------------------
  |  Branch (1108:13): [True: 0, False: 21]
  ------------------
 1109|      0|            return;
 1110|      0|        }
 1111|     21|        const float floatVal(val->getFloat());
 1112|     21|        if (0 == ASSIMP_strincmp("fov", prop->m_value->getString(), 3)) {
  ------------------
  |  Branch (1112:13): [True: 7, False: 14]
  ------------------
 1113|      7|            m_currentCamera->mHorizontalFOV = floatVal;
 1114|     14|        } else if (0 == ASSIMP_strincmp("near", prop->m_value->getString(), 4)) {
  ------------------
  |  Branch (1114:20): [True: 7, False: 7]
  ------------------
 1115|      7|            m_currentCamera->mClipPlaneNear = floatVal;
 1116|      7|        } else if (0 == ASSIMP_strincmp("far", prop->m_value->getString(), 3)) {
  ------------------
  |  Branch (1116:20): [True: 7, False: 0]
  ------------------
 1117|      7|            m_currentCamera->mClipPlaneFar = floatVal;
 1118|      7|        }
 1119|     21|    }
 1120|     21|}
_ZN6Assimp7OpenGEX15OpenGEXImporter10copyMeshesEP7aiScene:
 1141|     14|void OpenGEXImporter::copyMeshes(aiScene *pScene) {
 1142|     14|    ai_assert(nullptr != pScene);
 1143|       |
 1144|     14|    if (m_meshCache.empty()) {
  ------------------
  |  Branch (1144:9): [True: 11, False: 3]
  ------------------
 1145|     11|        return;
 1146|     11|    }
 1147|       |
 1148|      3|    pScene->mNumMeshes = static_cast<unsigned int>(m_meshCache.size());
 1149|      3|    pScene->mMeshes = new aiMesh *[pScene->mNumMeshes];
 1150|      9|    for (unsigned int i = 0; i < pScene->mNumMeshes; i++) {
  ------------------
  |  Branch (1150:30): [True: 6, False: 3]
  ------------------
 1151|      6|        pScene->mMeshes[i] = m_meshCache[i].release();
 1152|      6|    }
 1153|      3|}
_ZN6Assimp7OpenGEX15OpenGEXImporter11copyCamerasEP7aiScene:
 1156|     14|void OpenGEXImporter::copyCameras(aiScene *pScene) {
 1157|     14|    ai_assert(nullptr != pScene);
 1158|       |
 1159|     14|    if (m_cameraCache.empty()) {
  ------------------
  |  Branch (1159:9): [True: 11, False: 3]
  ------------------
 1160|     11|        return;
 1161|     11|    }
 1162|       |
 1163|      3|    pScene->mNumCameras = static_cast<unsigned int>(m_cameraCache.size());
 1164|      3|    pScene->mCameras = new aiCamera *[pScene->mNumCameras];
 1165|      3|    std::copy(m_cameraCache.begin(), m_cameraCache.end(), pScene->mCameras);
 1166|      3|}
_ZN6Assimp7OpenGEX15OpenGEXImporter13copyMaterialsEP7aiScene:
 1182|     14|void OpenGEXImporter::copyMaterials(aiScene *pScene) {
 1183|     14|    ai_assert(nullptr != pScene);
 1184|       |
 1185|     14|    if (m_materialCache.empty()) {
  ------------------
  |  Branch (1185:9): [True: 14, False: 0]
  ------------------
 1186|     14|        return;
 1187|     14|    }
 1188|       |
 1189|      0|    pScene->mNumMaterials = static_cast<unsigned int>(m_materialCache.size());
 1190|      0|    pScene->mMaterials = new aiMaterial *[pScene->mNumMaterials];
 1191|      0|    std::copy(m_materialCache.begin(), m_materialCache.end(), pScene->mMaterials);
 1192|      0|}
_ZN6Assimp7OpenGEX15OpenGEXImporter17resolveReferencesEv:
 1195|     14|void OpenGEXImporter::resolveReferences() {
 1196|     14|    if (m_unresolvedRefStack.empty()) {
  ------------------
  |  Branch (1196:9): [True: 11, False: 3]
  ------------------
 1197|     11|        return;
 1198|     11|    }
 1199|       |
 1200|      3|    RefInfo *currentRefInfo(nullptr);
  ------------------
  |  |   59|      3|#define nullptr nullptr
  ------------------
 1201|     13|    for (auto it = m_unresolvedRefStack.begin(); it != m_unresolvedRefStack.end(); ++it) {
  ------------------
  |  Branch (1201:50): [True: 10, False: 3]
  ------------------
 1202|     10|        currentRefInfo = it->get();
 1203|     10|        if (nullptr != currentRefInfo) {
  ------------------
  |  |   59|     10|#define nullptr nullptr
  ------------------
  |  Branch (1203:13): [True: 10, False: 0]
  ------------------
 1204|     10|            aiNode *node(currentRefInfo->m_node);
 1205|     10|            if (RefInfo::MeshRef == currentRefInfo->m_type) {
  ------------------
  |  Branch (1205:17): [True: 5, False: 5]
  ------------------
 1206|     10|                for (size_t i = 0; i < currentRefInfo->m_Names.size(); ++i) {
  ------------------
  |  Branch (1206:36): [True: 5, False: 5]
  ------------------
 1207|      5|                    const std::string &name(currentRefInfo->m_Names[i]);
 1208|      5|                    ReferenceMap::const_iterator curIt(m_mesh2refMap.find(name));
 1209|      5|                    if (m_mesh2refMap.end() != curIt) {
  ------------------
  |  Branch (1209:25): [True: 5, False: 0]
  ------------------
 1210|      5|                        unsigned int meshIdx = static_cast<unsigned int>(m_mesh2refMap[name]);
 1211|      5|                        node->mMeshes[i] = meshIdx;
 1212|      5|                    }
 1213|      5|                }
 1214|      5|            } else if (RefInfo::MaterialRef == currentRefInfo->m_type) {
  ------------------
  |  Branch (1214:24): [True: 5, False: 0]
  ------------------
 1215|     10|                for (size_t i = 0; i < currentRefInfo->m_Names.size(); ++i) {
  ------------------
  |  Branch (1215:36): [True: 5, False: 5]
  ------------------
 1216|      5|                    const std::string name(currentRefInfo->m_Names[i]);
 1217|      5|                    ReferenceMap::const_iterator curIt(m_material2refMap.find(name));
 1218|      5|                    if (m_material2refMap.end() != curIt) {
  ------------------
  |  Branch (1218:25): [True: 0, False: 5]
  ------------------
 1219|      0|                        if (nullptr != m_currentMesh) {
  ------------------
  |  |   59|      0|#define nullptr nullptr
  ------------------
  |  Branch (1219:29): [True: 0, False: 0]
  ------------------
 1220|      0|                            unsigned int matIdx = static_cast<unsigned int>(m_material2refMap[name]);
 1221|      0|                            if (m_currentMesh->mMaterialIndex != 0) {
  ------------------
  |  Branch (1221:33): [True: 0, False: 0]
  ------------------
 1222|      0|                                ASSIMP_LOG_WARN("Override of material reference in current mesh by material reference.");
 1223|      0|                            }
 1224|      0|                            m_currentMesh->mMaterialIndex = matIdx;
 1225|      0|                        } else {
 1226|      0|                            ASSIMP_LOG_WARN("Cannot resolve material reference, because no current mesh is there.");
 1227|      0|                        }
 1228|      0|                    }
 1229|      5|                }
 1230|      5|            } else {
 1231|      0|                throw DeadlyImportError("Unknown reference info to resolve.");
 1232|      0|            }
 1233|     10|        }
 1234|     10|    }
 1235|      3|}
_ZN6Assimp7OpenGEX15OpenGEXImporter14createNodeTreeEP7aiScene:
 1238|     14|void OpenGEXImporter::createNodeTree(aiScene *pScene) {
 1239|     14|    if (nullptr == m_root) {
  ------------------
  |  |   59|     14|#define nullptr nullptr
  ------------------
  |  Branch (1239:9): [True: 11, False: 3]
  ------------------
 1240|     11|        return;
 1241|     11|    }
 1242|       |
 1243|      3|    if (m_root->m_children.empty()) {
  ------------------
  |  Branch (1243:9): [True: 0, False: 3]
  ------------------
 1244|      0|        return;
 1245|      0|    }
 1246|       |
 1247|      3|    pScene->mRootNode->mNumChildren = static_cast<unsigned int>(m_root->m_children.size());
 1248|      3|    pScene->mRootNode->mChildren = new aiNode *[pScene->mRootNode->mNumChildren];
 1249|      3|    std::copy(m_root->m_children.begin(), m_root->m_children.end(), pScene->mRootNode->mChildren);
 1250|      3|}
_ZN6Assimp7OpenGEX15OpenGEXImporter8pushNodeEP6aiNodeP7aiScene:
 1253|     12|void OpenGEXImporter::pushNode(aiNode *node, aiScene *pScene) {
 1254|     12|    ai_assert(nullptr != pScene);
 1255|       |
 1256|     12|    if (nullptr == node) {
  ------------------
  |  |   59|     12|#define nullptr nullptr
  ------------------
  |  Branch (1256:9): [True: 0, False: 12]
  ------------------
 1257|      0|        return;
 1258|      0|    }
 1259|       |
 1260|     12|    ChildInfo *info(nullptr);
  ------------------
  |  |   59|     12|#define nullptr nullptr
  ------------------
 1261|     12|    if (m_nodeStack.empty()) {
  ------------------
  |  Branch (1261:9): [True: 12, False: 0]
  ------------------
 1262|     12|        node->mParent = pScene->mRootNode;
 1263|     12|        NodeChildMap::iterator it(m_nodeChildMap.find(node->mParent));
 1264|     12|        if (m_nodeChildMap.end() == it) {
  ------------------
  |  Branch (1264:13): [True: 3, False: 9]
  ------------------
 1265|      3|            info = new ChildInfo;
 1266|      3|            m_root = info;
 1267|      3|            m_nodeChildMap[node->mParent] = std::unique_ptr<ChildInfo>(info);
 1268|      9|        } else {
 1269|      9|            info = it->second.get();
 1270|      9|        }
 1271|     12|        info->m_children.push_back(node);
 1272|     12|    } else {
 1273|      0|        aiNode *parent(m_nodeStack.back());
 1274|      0|        ai_assert(nullptr != parent);
 1275|      0|        node->mParent = parent;
 1276|      0|        NodeChildMap::iterator it(m_nodeChildMap.find(node->mParent));
 1277|      0|        if (m_nodeChildMap.end() == it) {
  ------------------
  |  Branch (1277:13): [True: 0, False: 0]
  ------------------
 1278|      0|            info = new ChildInfo;
 1279|      0|            m_nodeChildMap[node->mParent] = std::unique_ptr<ChildInfo>(info);
 1280|      0|        } else {
 1281|      0|            info = it->second.get();
 1282|      0|        }
 1283|      0|        info->m_children.push_back(node);
 1284|      0|    }
 1285|     12|    m_nodeStack.push_back(node);
 1286|     12|}
_ZN6Assimp7OpenGEX15OpenGEXImporter7popNodeEv:
 1289|     12|aiNode *OpenGEXImporter::popNode() {
 1290|     12|    if (m_nodeStack.empty()) {
  ------------------
  |  Branch (1290:9): [True: 0, False: 12]
  ------------------
 1291|      0|        return nullptr;
  ------------------
  |  |   59|      0|#define nullptr nullptr
  ------------------
 1292|      0|    }
 1293|       |
 1294|     12|    aiNode *node(top());
 1295|     12|    m_nodeStack.pop_back();
 1296|       |
 1297|     12|    return node;
 1298|     12|}
_ZNK6Assimp7OpenGEX15OpenGEXImporter3topEv:
 1301|     12|aiNode *OpenGEXImporter::top() const {
 1302|     12|    if (m_nodeStack.empty()) {
  ------------------
  |  Branch (1302:9): [True: 0, False: 12]
  ------------------
 1303|      0|        return nullptr;
  ------------------
  |  |   59|      0|#define nullptr nullptr
  ------------------
 1304|      0|    }
 1305|       |
 1306|     12|    return m_nodeStack.back();
 1307|     12|}
OpenGEXImporter.cpp:_ZN6Assimp7OpenGEXL19logDDLParserMessageEN10ODDLParser11LogSeverityERKNSt3__112basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEE:
  226|      7|static void logDDLParserMessage (LogSeverity severity, const std::string &rawmsg) {
  227|      7|    std::string msg = ai_str_toprintable(rawmsg);
  228|      7|    switch (severity) {
  229|      0|    case ddl_debug_msg: ASSIMP_LOG_DEBUG(msg);         break;
  ------------------
  |  Branch (229:5): [True: 0, False: 7]
  ------------------
  230|      0|    case ddl_info_msg:  ASSIMP_LOG_INFO(msg);          break;
  ------------------
  |  Branch (230:5): [True: 0, False: 7]
  ------------------
  231|      0|    case ddl_warn_msg:  ASSIMP_LOG_WARN(msg);          break;
  ------------------
  |  Branch (231:5): [True: 0, False: 7]
  ------------------
  232|      7|    case ddl_error_msg: ASSIMP_LOG_ERROR(msg);         break;
  ------------------
  |  Branch (232:5): [True: 7, False: 0]
  ------------------
  233|      0|    default:            ASSIMP_LOG_VERBOSE_DEBUG(msg); break;
  ------------------
  |  Branch (233:5): [True: 0, False: 7]
  ------------------
  234|      7|    }
  235|      7|}
OpenGEXImporter.cpp:_ZN7GrammarL14matchTokenTypeEPKc:
  153|    149|    static TokenType matchTokenType(const char *tokenType) {
  154|    149|        const size_t len = std::strlen(tokenType);
  155|    149|        if (0 == strncmp(MetricType, tokenType, len)) {
  ------------------
  |  Branch (155:13): [True: 15, False: 134]
  ------------------
  156|     15|            return MetricToken;
  157|    134|        } else if (0 == strncmp(NameType, tokenType, len)) {
  ------------------
  |  Branch (157:20): [True: 12, False: 122]
  ------------------
  158|     12|            return NameToken;
  159|    122|        } else if (0 == strncmp(ObjectRefType, tokenType, len)) {
  ------------------
  |  Branch (159:20): [True: 12, False: 110]
  ------------------
  160|     12|            return ObjectRefToken;
  161|    110|        } else if (0 == strncmp(MaterialRefType, tokenType, len)) {
  ------------------
  |  Branch (161:20): [True: 11, False: 99]
  ------------------
  162|     11|            return MaterialRefToken;
  163|     99|        } else if (0 == strncmp(MetricKeyType, tokenType, len)) {
  ------------------
  |  Branch (163:20): [True: 0, False: 99]
  ------------------
  164|      0|            return MetricKeyToken;
  165|     99|        } else if (0 == strncmp(GeometryNodeType, tokenType, len)) {
  ------------------
  |  Branch (165:20): [True: 5, False: 94]
  ------------------
  166|      5|            return GeometryNodeToken;
  167|     94|        } else if (0 == strncmp(CameraNodeType, tokenType, len)) {
  ------------------
  |  Branch (167:20): [True: 7, False: 87]
  ------------------
  168|      7|            return CameraNodeToken;
  169|     87|        } else if (0 == strncmp(LightNodeType, tokenType, len)) {
  ------------------
  |  Branch (169:20): [True: 7, False: 80]
  ------------------
  170|      7|            return LightNodeToken;
  171|     80|        } else if (0 == strncmp(GeometryObjectType, tokenType, len)) {
  ------------------
  |  Branch (171:20): [True: 6, False: 74]
  ------------------
  172|      6|            return GeometryObjectToken;
  173|     74|        } else if (0 == strncmp(CameraObjectType, tokenType, len)) {
  ------------------
  |  Branch (173:20): [True: 7, False: 67]
  ------------------
  174|      7|            return CameraObjectToken;
  175|     67|        } else if (0 == strncmp(LightObjectType, tokenType, len)) {
  ------------------
  |  Branch (175:20): [True: 7, False: 60]
  ------------------
  176|      7|            return LightObjectToken;
  177|     60|        } else if (0 == strncmp(TransformType, tokenType, len)) {
  ------------------
  |  Branch (177:20): [True: 12, False: 48]
  ------------------
  178|     12|            return TransformToken;
  179|     48|        } else if (0 == strncmp(MeshType, tokenType, len)) {
  ------------------
  |  Branch (179:20): [True: 6, False: 42]
  ------------------
  180|      6|            return MeshToken;
  181|     42|        } else if (0 == strncmp(VertexArrayType, tokenType, len)) {
  ------------------
  |  Branch (181:20): [True: 14, False: 28]
  ------------------
  182|     14|            return VertexArrayToken;
  183|     28|        } else if (0 == strncmp(IndexArrayType, tokenType, len)) {
  ------------------
  |  Branch (183:20): [True: 5, False: 23]
  ------------------
  184|      5|            return IndexArrayToken;
  185|     23|        } else if (0 == strncmp(MaterialType, tokenType, len)) {
  ------------------
  |  Branch (185:20): [True: 0, False: 23]
  ------------------
  186|      0|            return MaterialToken;
  187|     23|        } else if (0 == strncmp(ColorType, tokenType, len)) {
  ------------------
  |  Branch (187:20): [True: 0, False: 23]
  ------------------
  188|      0|            return ColorToken;
  189|     23|        } else if (0 == strncmp(ParamType, tokenType, len)) {
  ------------------
  |  Branch (189:20): [True: 21, False: 2]
  ------------------
  190|     21|            return ParamToken;
  191|     21|        } else if (0 == strncmp(TextureType, tokenType, len)) {
  ------------------
  |  Branch (191:20): [True: 0, False: 2]
  ------------------
  192|      0|            return TextureToken;
  193|      2|        } else if (0 == strncmp(AttenType, tokenType, len)) {
  ------------------
  |  Branch (193:20): [True: 0, False: 2]
  ------------------
  194|      0|            return AttenToken;
  195|      0|        }
  196|       |
  197|      2|        return NoneType;
  198|    149|    }
OpenGEXImporter.cpp:_ZN7GrammarL17isValidMetricTypeEPKc:
  137|     12|    static int isValidMetricType(const char *token) {
  138|     12|        if (nullptr == token) {
  ------------------
  |  |   59|     12|#define nullptr nullptr
  ------------------
  |  Branch (138:13): [True: 0, False: 12]
  ------------------
  139|      0|            return false;
  140|      0|        }
  141|       |
  142|     12|        int idx = -1;
  143|     30|        for (size_t i = 0; i < 4; i++) {
  ------------------
  |  Branch (143:28): [True: 30, False: 0]
  ------------------
  144|     30|            if (ValidMetricToken[i] == token) {
  ------------------
  |  Branch (144:17): [True: 12, False: 18]
  ------------------
  145|     12|                idx = (int)i;
  146|     12|                break;
  147|     12|            }
  148|     30|        }
  149|       |
  150|     12|        return idx;
  151|     12|    }
OpenGEXImporter.cpp:_ZN6Assimp7OpenGEXL11getRefNamesEPN10ODDLParser7DDLNodeERNSt3__16vectorINS4_12basic_stringIcNS4_11char_traitsIcEENS4_9allocatorIcEEEENS9_ISB_EEEE:
  489|     23|static void getRefNames(DDLNode *node, std::vector<std::string> &names) {
  490|     23|    ai_assert(nullptr != node);
  491|       |
  492|     23|    Reference *ref = node->getReferences();
  493|     23|    if (nullptr != ref) {
  ------------------
  |  |   59|     23|#define nullptr nullptr
  ------------------
  |  Branch (493:9): [True: 17, False: 6]
  ------------------
  494|     34|        for (size_t i = 0; i < ref->m_numRefs; i++) {
  ------------------
  |  Branch (494:28): [True: 17, False: 17]
  ------------------
  495|     17|            Name *currentName(ref->m_referencedName[i]);
  496|     17|            if (nullptr != currentName && nullptr != currentName->m_id) {
  ------------------
  |  |   59|     17|#define nullptr nullptr
  ------------------
                          if (nullptr != currentName && nullptr != currentName->m_id) {
  ------------------
  |  |   59|     17|#define nullptr nullptr
  ------------------
  |  Branch (496:17): [True: 17, False: 0]
  |  Branch (496:43): [True: 17, False: 0]
  ------------------
  497|       |#ifdef ASSIMP_USE_HUNTER
  498|       |                const std::string name(currentName->m_id->m_text.m_buffer);
  499|       |#else
  500|     17|                const std::string name(currentName->m_id->m_buffer);
  501|     17|#endif
  502|     17|                if (!name.empty()) {
  ------------------
  |  Branch (502:21): [True: 17, False: 0]
  ------------------
  503|     17|                    names.push_back(name);
  504|     17|                }
  505|     17|            }
  506|     17|        }
  507|     17|    }
  508|     23|}
OpenGEXImporter.cpp:_ZN6Assimp7OpenGEXL9setMatrixEP6aiNodePN10ODDLParser13DataArrayListE:
  635|     12|static void setMatrix(aiNode *node, DataArrayList *transformData) {
  636|     12|    ai_assert(nullptr != node);
  637|     12|    ai_assert(nullptr != transformData);
  638|       |
  639|     12|    float m[16];
  640|     12|    size_t i(1);
  641|     12|    Value *next(transformData->m_dataList->m_next);
  642|     12|    m[0] = transformData->m_dataList->getFloat();
  643|    192|    while (next != nullptr) {
  ------------------
  |  |   59|    192|#define nullptr nullptr
  ------------------
  |  Branch (643:12): [True: 180, False: 12]
  ------------------
  644|    180|        m[i] = next->getFloat();
  645|    180|        next = next->m_next;
  646|    180|        i++;
  647|    180|    }
  648|       |
  649|     12|    ai_assert(i == 16);
  650|       |
  651|     12|    node->mTransformation.a1 = m[0];
  652|     12|    node->mTransformation.a2 = m[4];
  653|     12|    node->mTransformation.a3 = m[8];
  654|     12|    node->mTransformation.a4 = m[12];
  655|       |
  656|     12|    node->mTransformation.b1 = m[1];
  657|     12|    node->mTransformation.b2 = m[5];
  658|     12|    node->mTransformation.b3 = m[9];
  659|     12|    node->mTransformation.b4 = m[13];
  660|       |
  661|     12|    node->mTransformation.c1 = m[2];
  662|     12|    node->mTransformation.c2 = m[6];
  663|     12|    node->mTransformation.c3 = m[10];
  664|     12|    node->mTransformation.c4 = m[14];
  665|       |
  666|     12|    node->mTransformation.d1 = m[3];
  667|     12|    node->mTransformation.d2 = m[7];
  668|     12|    node->mTransformation.d3 = m[11];
  669|     12|    node->mTransformation.d4 = m[15];
  670|     12|}
OpenGEXImporter.cpp:_ZN6Assimp7OpenGEXL16propId2StdStringEPN10ODDLParser8PropertyERNSt3__112basic_stringIcNS4_11char_traitsIcEENS4_9allocatorIcEEEESB_:
  207|     20|static void propId2StdString(Property *prop, std::string &name, std::string &key) {
  208|     20|    name = key = std::string();
  209|     20|    if (nullptr == prop) {
  ------------------
  |  |   59|     20|#define nullptr nullptr
  ------------------
  |  Branch (209:9): [True: 0, False: 20]
  ------------------
  210|      0|        return;
  211|      0|    }
  212|       |
  213|     20|    if (nullptr != prop->m_key) {
  ------------------
  |  |   59|     20|#define nullptr nullptr
  ------------------
  |  Branch (213:9): [True: 20, False: 0]
  ------------------
  214|       |#ifdef ASSIMP_USE_HUNTER
  215|       |        name = prop->m_key->m_text.m_buffer;
  216|       |#else
  217|     20|        name = prop->m_key->m_buffer;
  218|     20|#endif
  219|     20|        if (Value::ValueType::ddl_string == prop->m_value->m_type) {
  ------------------
  |  Branch (219:13): [True: 20, False: 0]
  ------------------
  220|     20|            key = prop->m_value->getString();
  221|     20|        }
  222|     20|    }
  223|     20|}
OpenGEXImporter.cpp:_ZN6Assimp7OpenGEXL18getAttributeByNameEPKc:
  737|     14|static MeshAttribute getAttributeByName(const char *attribName) {
  738|     14|    ai_assert(nullptr != attribName);
  739|       |
  740|     14|    if (0 == strcmp(PosToken, attribName)) {
  ------------------
  |  Branch (740:9): [True: 6, False: 8]
  ------------------
  741|      6|        return Position;
  742|      8|    } else if (0 == strcmp(ColToken, attribName)) {
  ------------------
  |  Branch (742:16): [True: 1, False: 7]
  ------------------
  743|      1|        return Color;
  744|      7|    } else if (0 == strcmp(NormalToken, attribName)) {
  ------------------
  |  Branch (744:16): [True: 6, False: 1]
  ------------------
  745|      6|        return Normal;
  746|      6|    } else if (0 == strcmp(TexCoordToken, attribName)) {
  ------------------
  |  Branch (746:16): [True: 1, False: 0]
  ------------------
  747|      1|        return TexCoord;
  748|      1|    }
  749|       |
  750|      0|    return None;
  751|     14|}
OpenGEXImporter.cpp:_ZN6Assimp7OpenGEXL23countDataArrayListItemsEPN10ODDLParser13DataArrayListE:
  799|     19|static size_t countDataArrayListItems(DataArrayList *vaList) {
  800|     19|    size_t numItems(0);
  801|     19|    if (nullptr == vaList) {
  ------------------
  |  |   59|     19|#define nullptr nullptr
  ------------------
  |  Branch (801:9): [True: 0, False: 19]
  ------------------
  802|      0|        return numItems;
  803|      0|    }
  804|       |
  805|     19|    DataArrayList *next(vaList);
  806|  19.4k|    while (nullptr != next) {
  ------------------
  |  |   59|  19.4k|#define nullptr nullptr
  ------------------
  |  Branch (806:12): [True: 19.4k, False: 19]
  ------------------
  807|  19.4k|        if (nullptr != vaList->m_dataList) {
  ------------------
  |  |   59|  19.4k|#define nullptr nullptr
  ------------------
  |  Branch (807:13): [True: 19.4k, False: 0]
  ------------------
  808|  19.4k|            numItems++;
  809|  19.4k|        }
  810|  19.4k|        next = next->m_next;
  811|  19.4k|    }
  812|       |
  813|     19|    return numItems;
  814|     19|}
OpenGEXImporter.cpp:_ZN6Assimp7OpenGEXL15copyVectorArrayEmPN10ODDLParser13DataArrayListEP10aiVector3tIfE:
  817|     13|static void copyVectorArray(size_t numItems, DataArrayList *vaList, aiVector3D *vectorArray) {
  818|  12.6k|    for (size_t i = 0; i < numItems; i++) {
  ------------------
  |  Branch (818:24): [True: 12.6k, False: 13]
  ------------------
  819|  12.6k|        Value *next(vaList->m_dataList);
  820|  12.6k|        fillVector3(&vectorArray[i], next);
  821|  12.6k|        vaList = vaList->m_next;
  822|  12.6k|    }
  823|     13|}
OpenGEXImporter.cpp:_ZN6Assimp7OpenGEXL11fillVector3EP10aiVector3tIfEPN10ODDLParser5ValueE:
  754|  12.6k|static void fillVector3(aiVector3D *vec3, Value *vals) {
  755|  12.6k|    ai_assert(nullptr != vec3);
  756|  12.6k|    ai_assert(nullptr != vals);
  757|       |
  758|  12.6k|    float x(0.0f), y(0.0f), z(0.0f);
  759|  12.6k|    Value *next(vals);
  760|  12.6k|    x = next->getFloat();
  761|  12.6k|    next = next->m_next;
  762|  12.6k|    y = next->getFloat();
  763|  12.6k|    next = next->m_next;
  764|  12.6k|    if (nullptr != next) {
  ------------------
  |  |   59|  12.6k|#define nullptr nullptr
  ------------------
  |  Branch (764:9): [True: 12.5k, False: 80]
  ------------------
  765|  12.5k|        z = next->getFloat();
  766|  12.5k|    }
  767|       |
  768|  12.6k|    vec3->Set(x, y, z);
  769|  12.6k|}
OpenGEXImporter.cpp:_ZN6Assimp7OpenGEXL16copyColor4DArrayEmPN10ODDLParser13DataArrayListEP9aiColor4tIfE:
  826|      1|static void copyColor4DArray(size_t numItems, DataArrayList *vaList, aiColor4D *colArray) {
  827|     81|    for (size_t i = 0; i < numItems; i++) {
  ------------------
  |  Branch (827:24): [True: 80, False: 1]
  ------------------
  828|     80|        Value *next(vaList->m_dataList);
  829|     80|        fillColor4(&colArray[i], next);
  830|     80|    }
  831|      1|}
OpenGEXImporter.cpp:_ZN6Assimp7OpenGEXL10fillColor4EP9aiColor4tIfEPN10ODDLParser5ValueE:
  772|     80|static void fillColor4(aiColor4D *col4, Value *vals) {
  773|     80|    ai_assert(nullptr != col4);
  774|     80|    ai_assert(nullptr != vals);
  775|       |
  776|     80|    Value *next(vals);
  777|     80|    col4->r = next->getFloat();
  778|     80|    next = next->m_next;
  779|     80|    if (!next) {
  ------------------
  |  Branch (779:9): [True: 0, False: 80]
  ------------------
  780|      0|        throw DeadlyImportError("OpenGEX: Not enough values to fill 4-element color, only 1");
  781|      0|    }
  782|       |
  783|     80|    col4->g = next->getFloat();
  784|     80|    next = next->m_next;
  785|     80|    if (!next) {
  ------------------
  |  Branch (785:9): [True: 0, False: 80]
  ------------------
  786|      0|        throw DeadlyImportError("OpenGEX: Not enough values to fill 4-element color, only 2");
  787|      0|    }
  788|       |
  789|     80|    col4->b = next->getFloat();
  790|     80|    next = next->m_next;
  791|     80|    if (!next) {
  ------------------
  |  Branch (791:9): [True: 80, False: 0]
  ------------------
  792|     80|        col4->a = 1.0f;
  793|     80|    } else {
  794|      0|        col4->a = next->getFloat();
  795|      0|    }
  796|     80|}

_ZN6Assimp7OpenGEX10MetricInfoC2Ev:
   81|  2.49k|    MetricInfo(): m_stringValue( ), m_floatValue( 0.0f ), m_intValue( -1 ) {}
_ZN6Assimp7OpenGEX15OpenGEXImporterD2Ev:
   94|    624|    ~OpenGEXImporter() override = default;
_ZN6Assimp7OpenGEX15OpenGEXImporter7RefInfoD2Ev:
  167|     10|        ~RefInfo() = default;

_ZN6Assimp11PLYImporterD2Ev:
  172|    624|    PLYImporter::~PLYImporter() {
  173|    624|        delete mGeneratedMesh;
  174|    624|    }
_ZNK6Assimp11PLYImporter7CanReadERKNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEPNS_8IOSystemEb:
  178|    467|    bool PLYImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool) const {
  179|    467|        static const char *tokens[] = { "ply" };
  180|       |        return SearchFileHeaderForToken(pIOHandler, pFile, tokens, AI_COUNT_OF(tokens));
  181|    467|    }
_ZNK6Assimp11PLYImporter7GetInfoEv:
  184|    637|    const aiImporterDesc *PLYImporter::GetInfo() const {
  185|    637|        return &desc;
  186|    637|    }
_ZN6Assimp11PLYImporter14InternReadFileERKNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEP7aiScenePNS_8IOSystemE:
  190|      3|    void PLYImporter::InternReadFile(const std::string &pFile, aiScene *pScene, IOSystem *pIOHandler) {
  191|      3|        const std::string mode = "rb";
  192|      3|        std::unique_ptr<IOStream> fileStream(pIOHandler->Open(pFile, mode));
  193|      3|        if (!fileStream) {
  ------------------
  |  Branch (193:13): [True: 0, False: 3]
  ------------------
  194|      0|            throw DeadlyImportError("Failed to open file ", pFile, ".");
  195|      0|        }
  196|       |
  197|       |        // Get the file-size
  198|      3|        const size_t fileSize = fileStream->FileSize();
  199|      3|        if (0 == fileSize) {
  ------------------
  |  Branch (199:13): [True: 0, False: 3]
  ------------------
  200|      0|            throw DeadlyImportError("File ", pFile, " is empty.");
  201|      0|        }
  202|       |
  203|      3|        IOStreamBuffer<char> streamedBuffer(1024 * 1024);
  204|      3|        streamedBuffer.open(fileStream.get());
  205|       |
  206|       |        // the beginning of the file must be PLY - magic, magic
  207|      3|        std::vector<char> headerCheck;
  208|      3|        streamedBuffer.getNextLine(headerCheck);
  209|       |
  210|      3|        if ((headerCheck.size() < 3) ||
  ------------------
  |  Branch (210:13): [True: 0, False: 3]
  ------------------
  211|      3|                (headerCheck[0] != 'P' && headerCheck[0] != 'p') ||
  ------------------
  |  Branch (211:18): [True: 3, False: 0]
  |  Branch (211:43): [True: 0, False: 3]
  ------------------
  212|      3|                (headerCheck[1] != 'L' && headerCheck[1] != 'l') ||
  ------------------
  |  Branch (212:18): [True: 3, False: 0]
  |  Branch (212:43): [True: 0, False: 3]
  ------------------
  213|      3|                (headerCheck[2] != 'Y' && headerCheck[2] != 'y')) {
  ------------------
  |  Branch (213:18): [True: 3, False: 0]
  |  Branch (213:43): [True: 0, False: 3]
  ------------------
  214|      0|            streamedBuffer.close();
  215|      0|            throw DeadlyImportError("Invalid .ply file: Incorrect magic number (expected 'ply' or 'PLY').");
  216|      0|        }
  217|       |
  218|      3|        std::vector<char> mBuffer2;
  219|      3|        streamedBuffer.getNextLine(mBuffer2);
  220|      3|        mBuffer = (unsigned char *)&mBuffer2[0];
  221|       |
  222|      3|        auto szMe = (char *)&this->mBuffer[0];
  223|      3|        const char *end = &mBuffer2[0] + mBuffer2.size();
  224|      3|        SkipSpacesAndLineEnd(szMe, (const char **)&szMe, end);
  225|       |
  226|       |        // determine the format of the file data and construct the aiMesh
  227|      3|        DOM sPlyDom;
  228|      3|        this->pcDOM = &sPlyDom;
  229|       |
  230|      3|        if (TokenMatch(szMe, "format", 6)) {
  ------------------
  |  Branch (230:13): [True: 3, False: 0]
  ------------------
  231|      3|            if (TokenMatch(szMe, "ascii", 5)) {
  ------------------
  |  Branch (231:17): [True: 3, False: 0]
  ------------------
  232|      3|                SkipLine(szMe, (const char **)&szMe, end);
  233|      3|                if (!DOM::ParseInstance(streamedBuffer, &sPlyDom, this)) {
  ------------------
  |  Branch (233:21): [True: 0, False: 3]
  ------------------
  234|      0|                    if (mGeneratedMesh != nullptr) {
  ------------------
  |  Branch (234:25): [True: 0, False: 0]
  ------------------
  235|      0|                        delete (mGeneratedMesh);
  236|      0|                        mGeneratedMesh = nullptr;
  237|      0|                    }
  238|       |
  239|      0|                    streamedBuffer.close();
  240|      0|                    throw DeadlyImportError("Invalid .ply file: Unable to build DOM (#1)");
  241|      0|                }
  242|      3|            } else if (!strncmp(szMe, "binary_", 7)) {
  ------------------
  |  Branch (242:24): [True: 0, False: 0]
  ------------------
  243|      0|                szMe += 7;
  244|       |
  245|       |                // skip the line, parse the rest of the header and build the DOM
  246|      0|                if (const bool bIsBE = isBigEndian(szMe); !PLY::DOM::ParseInstanceBinary(streamedBuffer, &sPlyDom, this, bIsBE)) {
  ------------------
  |  Branch (246:59): [True: 0, False: 0]
  ------------------
  247|      0|                    if (mGeneratedMesh != nullptr) {
  ------------------
  |  Branch (247:25): [True: 0, False: 0]
  ------------------
  248|      0|                        delete (mGeneratedMesh);
  249|      0|                        mGeneratedMesh = nullptr;
  250|      0|                    }
  251|       |
  252|      0|                    streamedBuffer.close();
  253|      0|                    throw DeadlyImportError("Invalid .ply file: Unable to build DOM (#2)");
  254|      0|                }
  255|      0|            } else {
  256|      0|                if (mGeneratedMesh != nullptr) {
  ------------------
  |  Branch (256:21): [True: 0, False: 0]
  ------------------
  257|      0|                    delete mGeneratedMesh;
  258|      0|                    mGeneratedMesh = nullptr;
  259|      0|                }
  260|       |
  261|      0|                streamedBuffer.close();
  262|      0|                throw DeadlyImportError("Invalid .ply file: Unknown file format");
  263|      0|            }
  264|      3|        } else {
  265|      0|            AI_DEBUG_INVALIDATE_PTR(this->mBuffer);
  266|      0|            if (mGeneratedMesh != nullptr) {
  ------------------
  |  Branch (266:17): [True: 0, False: 0]
  ------------------
  267|      0|                delete (mGeneratedMesh);
  268|      0|                mGeneratedMesh = nullptr;
  269|      0|            }
  270|       |
  271|      0|            streamedBuffer.close();
  272|      0|            throw DeadlyImportError("Invalid .ply file: Missing format specification");
  273|      0|        }
  274|       |
  275|       |        // free the file buffer
  276|      3|        streamedBuffer.close();
  277|       |
  278|      3|        if (mGeneratedMesh == nullptr) {
  ------------------
  |  Branch (278:13): [True: 1, False: 2]
  ------------------
  279|      1|            throw DeadlyImportError("Invalid .ply file: Unable to extract mesh data ");
  280|      1|        }
  281|       |
  282|       |        // if no face list is existing we assume that the vertex
  283|       |        // list is containing a list of points
  284|      2|        bool pointsOnly = mGeneratedMesh->mFaces == nullptr ? true : false;
  ------------------
  |  Branch (284:27): [True: 0, False: 2]
  ------------------
  285|      2|        if (pointsOnly) {
  ------------------
  |  Branch (285:13): [True: 0, False: 2]
  ------------------
  286|      0|            mGeneratedMesh->mPrimitiveTypes = aiPrimitiveType::aiPrimitiveType_POINT;
  287|      0|        }
  288|       |
  289|       |        // now load a list of all materials
  290|      2|        std::vector<aiMaterial *> avMaterials;
  291|      2|        std::string defaultTexture;
  292|      2|        LoadMaterial(&avMaterials, defaultTexture, pointsOnly);
  293|       |
  294|       |        // now generate the output scene object. Fill the material list
  295|      2|        pScene->mNumMaterials = static_cast<unsigned int>(avMaterials.size());
  296|      2|        pScene->mMaterials = new aiMaterial *[pScene->mNumMaterials];
  297|      3|        for (unsigned int i = 0; i < pScene->mNumMaterials; ++i) {
  ------------------
  |  Branch (297:34): [True: 1, False: 2]
  ------------------
  298|      1|            pScene->mMaterials[i] = avMaterials[i];
  299|      1|        }
  300|       |
  301|       |        // fill the mesh list
  302|      2|        pScene->mNumMeshes = 1;
  303|      2|        pScene->mMeshes = new aiMesh *[pScene->mNumMeshes];
  304|      2|        pScene->mMeshes[0] = mGeneratedMesh;
  305|       |
  306|       |        // Move the mesh ownership into the scene instance
  307|      2|        mGeneratedMesh = nullptr;
  308|       |
  309|       |        // generate a simple node structure
  310|      2|        pScene->mRootNode = new aiNode();
  311|      2|        pScene->mRootNode->mNumMeshes = pScene->mNumMeshes;
  312|      2|        pScene->mRootNode->mMeshes = new unsigned int[pScene->mNumMeshes];
  313|       |
  314|      3|        for (unsigned int i = 0; i < pScene->mRootNode->mNumMeshes; ++i) {
  ------------------
  |  Branch (314:34): [True: 1, False: 2]
  ------------------
  315|      1|            pScene->mRootNode->mMeshes[i] = i;
  316|      1|        }
  317|      2|    }
_ZN6Assimp11PLYImporter10LoadVertexEPKNS_3PLY7ElementEPKNS1_15ElementInstanceEj:
  319|  11.4k|    void PLYImporter::LoadVertex(const Element *pcElement, const ElementInstance *instElement, unsigned int pos) {
  320|  11.4k|        ai_assert(nullptr != pcElement);
  321|  11.4k|        ai_assert(nullptr != instElement);
  322|       |
  323|  11.4k|        ai_uint aiPositions[3] = { NotSet, NotSet, NotSet };
  324|  11.4k|        EDataType aiTypes[3] = { EDT_Char, EDT_Char, EDT_Char };
  325|       |
  326|  11.4k|        ai_uint aiNormal[3] = { NotSet, NotSet, NotSet };
  327|  11.4k|        EDataType aiNormalTypes[3] = { EDT_Char, EDT_Char, EDT_Char };
  328|       |
  329|  11.4k|        unsigned int aiColors[4] = { NotSet, NotSet, NotSet, NotSet };
  330|  11.4k|        EDataType aiColorsTypes[4] = { EDT_Char, EDT_Char, EDT_Char, EDT_Char };
  331|       |
  332|  11.4k|        unsigned int aiTexcoord[2] = { NotSet, NotSet };
  333|  11.4k|        EDataType aiTexcoordTypes[2] = { EDT_Char, EDT_Char };
  334|       |
  335|       |        // now check whether which normal components are available
  336|  11.4k|        unsigned int _a(0), cnt(0);
  337|   101k|        for (auto a = pcElement->alProperties.begin(); a != pcElement->alProperties.end(); ++a, ++_a) {
  ------------------
  |  Branch (337:56): [True: 89.7k, False: 11.4k]
  ------------------
  338|  89.7k|            if (a->bIsList) {
  ------------------
  |  Branch (338:17): [True: 255, False: 89.4k]
  ------------------
  339|    255|                continue;
  340|    255|            }
  341|       |
  342|       |            // Positions
  343|  89.4k|            if (EST_XCoord == a->Semantic) {
  ------------------
  |  Branch (343:17): [True: 11.1k, False: 78.2k]
  ------------------
  344|  11.1k|                ++cnt;
  345|  11.1k|                aiPositions[0] = _a;
  346|  11.1k|                aiTypes[0] = a->eType;
  347|  78.2k|            } else if (EST_YCoord == a->Semantic) {
  ------------------
  |  Branch (347:24): [True: 11.1k, False: 67.1k]
  ------------------
  348|  11.1k|                ++cnt;
  349|  11.1k|                aiPositions[1] = _a;
  350|  11.1k|                aiTypes[1] = a->eType;
  351|  67.1k|            } else if (EST_ZCoord == a->Semantic) {
  ------------------
  |  Branch (351:24): [True: 11.1k, False: 55.9k]
  ------------------
  352|  11.1k|                ++cnt;
  353|  11.1k|                aiPositions[2] = _a;
  354|  11.1k|                aiTypes[2] = a->eType;
  355|  55.9k|            } else if (EST_XNormal == a->Semantic) {
  ------------------
  |  Branch (355:24): [True: 11.1k, False: 44.7k]
  ------------------
  356|       |                // Normals
  357|  11.1k|                ++cnt;
  358|  11.1k|                aiNormal[0] = _a;
  359|  11.1k|                aiNormalTypes[0] = a->eType;
  360|  44.7k|            } else if (EST_YNormal == a->Semantic) {
  ------------------
  |  Branch (360:24): [True: 11.1k, False: 33.5k]
  ------------------
  361|  11.1k|                ++cnt;
  362|  11.1k|                aiNormal[1] = _a;
  363|  11.1k|                aiNormalTypes[1] = a->eType;
  364|  33.5k|            } else if (EST_ZNormal == a->Semantic) {
  ------------------
  |  Branch (364:24): [True: 11.1k, False: 22.3k]
  ------------------
  365|  11.1k|                ++cnt;
  366|  11.1k|                aiNormal[2] = _a;
  367|  11.1k|                aiNormalTypes[2] = a->eType;
  368|  22.3k|            } else if (EST_Red == a->Semantic) {
  ------------------
  |  Branch (368:24): [True: 0, False: 22.3k]
  ------------------
  369|       |                // Colors
  370|      0|                ++cnt;
  371|      0|                aiColors[0] = _a;
  372|      0|                aiColorsTypes[0] = a->eType;
  373|  22.3k|            } else if (EST_Green == a->Semantic) {
  ------------------
  |  Branch (373:24): [True: 0, False: 22.3k]
  ------------------
  374|      0|                ++cnt;
  375|      0|                aiColors[1] = _a;
  376|      0|                aiColorsTypes[1] = a->eType;
  377|  22.3k|            } else if (EST_Blue == a->Semantic) {
  ------------------
  |  Branch (377:24): [True: 0, False: 22.3k]
  ------------------
  378|      0|                ++cnt;
  379|      0|                aiColors[2] = _a;
  380|      0|                aiColorsTypes[2] = a->eType;
  381|  22.3k|            } else if (EST_Alpha == a->Semantic) {
  ------------------
  |  Branch (381:24): [True: 0, False: 22.3k]
  ------------------
  382|      0|                ++cnt;
  383|      0|                aiColors[3] = _a;
  384|      0|                aiColorsTypes[3] = a->eType;
  385|  22.3k|            } else if (EST_UTextureCoord == a->Semantic) {
  ------------------
  |  Branch (385:24): [True: 11.1k, False: 11.1k]
  ------------------
  386|       |                // Texture coordinates
  387|  11.1k|                ++cnt;
  388|  11.1k|                aiTexcoord[0] = _a;
  389|  11.1k|                aiTexcoordTypes[0] = a->eType;
  390|  11.1k|            } else if (EST_VTextureCoord == a->Semantic) {
  ------------------
  |  Branch (390:24): [True: 11.1k, False: 0]
  ------------------
  391|  11.1k|                ++cnt;
  392|  11.1k|                aiTexcoord[1] = _a;
  393|  11.1k|                aiTexcoordTypes[1] = a->eType;
  394|  11.1k|            }
  395|  89.4k|        }
  396|       |
  397|       |        // check whether we have a valid source for the vertex data
  398|  11.4k|        if (0 != cnt) {
  ------------------
  |  Branch (398:13): [True: 11.1k, False: 255]
  ------------------
  399|       |            // Position
  400|  11.1k|            aiVector3D vOut;
  401|  11.1k|            if (NotSet != aiPositions[0]) {
  ------------------
  |  Branch (401:17): [True: 11.1k, False: 0]
  ------------------
  402|  11.1k|                vOut.x = PropertyInstance::ConvertTo<ai_real>(
  403|  11.1k|                        GetProperty(instElement->alProperties, aiPositions[0]).avList.front(), aiTypes[0]);
  404|  11.1k|            }
  405|       |
  406|  11.1k|            if (NotSet != aiPositions[1]) {
  ------------------
  |  Branch (406:17): [True: 11.1k, False: 0]
  ------------------
  407|  11.1k|                vOut.y = PropertyInstance::ConvertTo<ai_real>(
  408|  11.1k|                        GetProperty(instElement->alProperties, aiPositions[1]).avList.front(), aiTypes[1]);
  409|  11.1k|            }
  410|       |
  411|  11.1k|            if (NotSet != aiPositions[2]) {
  ------------------
  |  Branch (411:17): [True: 11.1k, False: 0]
  ------------------
  412|  11.1k|                vOut.z = PropertyInstance::ConvertTo<ai_real>(
  413|  11.1k|                        GetProperty(instElement->alProperties, aiPositions[2]).avList.front(), aiTypes[2]);
  414|  11.1k|            }
  415|       |
  416|       |            // Normals
  417|  11.1k|            aiVector3D nOut;
  418|  11.1k|            bool haveNormal = false;
  419|  11.1k|            if (NotSet != aiNormal[0]) {
  ------------------
  |  Branch (419:17): [True: 11.1k, False: 0]
  ------------------
  420|  11.1k|                nOut.x = PropertyInstance::ConvertTo<ai_real>(
  421|  11.1k|                        GetProperty(instElement->alProperties, aiNormal[0]).avList.front(), aiNormalTypes[0]);
  422|  11.1k|                haveNormal = true;
  423|  11.1k|            }
  424|       |
  425|  11.1k|            if (NotSet != aiNormal[1]) {
  ------------------
  |  Branch (425:17): [True: 11.1k, False: 0]
  ------------------
  426|  11.1k|                nOut.y = PropertyInstance::ConvertTo<ai_real>(
  427|  11.1k|                        GetProperty(instElement->alProperties, aiNormal[1]).avList.front(), aiNormalTypes[1]);
  428|  11.1k|                haveNormal = true;
  429|  11.1k|            }
  430|       |
  431|  11.1k|            if (NotSet != aiNormal[2]) {
  ------------------
  |  Branch (431:17): [True: 11.1k, False: 0]
  ------------------
  432|  11.1k|                nOut.z = PropertyInstance::ConvertTo<ai_real>(
  433|  11.1k|                        GetProperty(instElement->alProperties, aiNormal[2]).avList.front(), aiNormalTypes[2]);
  434|  11.1k|                haveNormal = true;
  435|  11.1k|            }
  436|       |
  437|       |            // Colors
  438|  11.1k|            aiColor4D cOut;
  439|  11.1k|            bool haveColor = false;
  440|  11.1k|            if (NotSet != aiColors[0]) {
  ------------------
  |  Branch (440:17): [True: 0, False: 11.1k]
  ------------------
  441|      0|                cOut.r = NormalizeColorValue(GetProperty(instElement->alProperties,
  442|      0|                                                    aiColors[0])
  443|      0|                                                    .avList.front(),
  444|      0|                        aiColorsTypes[0]);
  445|      0|                haveColor = true;
  446|      0|            }
  447|       |
  448|  11.1k|            if (NotSet != aiColors[1]) {
  ------------------
  |  Branch (448:17): [True: 0, False: 11.1k]
  ------------------
  449|      0|                cOut.g = NormalizeColorValue(GetProperty(instElement->alProperties,
  450|      0|                                                    aiColors[1])
  451|      0|                                                    .avList.front(),
  452|      0|                        aiColorsTypes[1]);
  453|      0|                haveColor = true;
  454|      0|            }
  455|       |
  456|  11.1k|            if (NotSet != aiColors[2]) {
  ------------------
  |  Branch (456:17): [True: 0, False: 11.1k]
  ------------------
  457|      0|                cOut.b = NormalizeColorValue(GetProperty(instElement->alProperties,
  458|      0|                                                    aiColors[2])
  459|      0|                                                    .avList.front(),
  460|      0|                        aiColorsTypes[2]);
  461|      0|                haveColor = true;
  462|      0|            }
  463|       |
  464|       |            // assume 1.0 for the alpha channel if it is not set
  465|  11.1k|            if (NotSet == aiColors[3]) {
  ------------------
  |  Branch (465:17): [True: 11.1k, False: 0]
  ------------------
  466|  11.1k|                cOut.a = 1.0;
  467|  11.1k|            } else {
  468|      0|                cOut.a = NormalizeColorValue(GetProperty(instElement->alProperties,
  469|      0|                                                    aiColors[3])
  470|      0|                                                    .avList.front(),
  471|      0|                        aiColorsTypes[3]);
  472|       |
  473|      0|                haveColor = true;
  474|      0|            }
  475|       |
  476|       |            // Texture coordinates
  477|  11.1k|            aiVector3D tOut;
  478|  11.1k|            tOut.z = 0;
  479|  11.1k|            bool haveTextureCoords = false;
  480|  11.1k|            if (NotSet != aiTexcoord[0]) {
  ------------------
  |  Branch (480:17): [True: 11.1k, False: 0]
  ------------------
  481|  11.1k|                tOut.x = PropertyInstance::ConvertTo<ai_real>(
  482|  11.1k|                        GetProperty(instElement->alProperties, aiTexcoord[0]).avList.front(), aiTexcoordTypes[0]);
  483|  11.1k|                haveTextureCoords = true;
  484|  11.1k|            }
  485|       |
  486|  11.1k|            if (NotSet != aiTexcoord[1]) {
  ------------------
  |  Branch (486:17): [True: 11.1k, False: 0]
  ------------------
  487|  11.1k|                tOut.y = PropertyInstance::ConvertTo<ai_real>(
  488|  11.1k|                        GetProperty(instElement->alProperties, aiTexcoord[1]).avList.front(), aiTexcoordTypes[1]);
  489|  11.1k|                haveTextureCoords = true;
  490|  11.1k|            }
  491|       |
  492|       |            // create aiMesh if needed
  493|  11.1k|            if (nullptr == mGeneratedMesh) {
  ------------------
  |  Branch (493:17): [True: 1, False: 11.1k]
  ------------------
  494|      1|                mGeneratedMesh = new aiMesh();
  495|      1|                mGeneratedMesh->mMaterialIndex = 0;
  496|      1|            }
  497|       |
  498|  11.1k|            if (nullptr == mGeneratedMesh->mVertices) {
  ------------------
  |  Branch (498:17): [True: 1, False: 11.1k]
  ------------------
  499|      1|                mGeneratedMesh->mNumVertices = pcElement->NumOccur;
  500|      1|                mGeneratedMesh->mVertices = new aiVector3D[mGeneratedMesh->mNumVertices];
  501|      1|            }
  502|  11.1k|            if (pos >= mGeneratedMesh->mNumVertices) {
  ------------------
  |  Branch (502:17): [True: 0, False: 11.1k]
  ------------------
  503|      0|                throw DeadlyImportError("Invalid .ply file: Too many vertices");
  504|      0|            }
  505|       |
  506|  11.1k|            mGeneratedMesh->mVertices[pos] = vOut;
  507|       |
  508|  11.1k|            if (haveNormal) {
  ------------------
  |  Branch (508:17): [True: 11.1k, False: 0]
  ------------------
  509|  11.1k|                if (nullptr == mGeneratedMesh->mNormals)
  ------------------
  |  Branch (509:21): [True: 1, False: 11.1k]
  ------------------
  510|      1|                    mGeneratedMesh->mNormals = new aiVector3D[mGeneratedMesh->mNumVertices];
  511|  11.1k|                mGeneratedMesh->mNormals[pos] = nOut;
  512|  11.1k|            }
  513|       |
  514|  11.1k|            if (haveColor) {
  ------------------
  |  Branch (514:17): [True: 0, False: 11.1k]
  ------------------
  515|      0|                if (nullptr == mGeneratedMesh->mColors[0])
  ------------------
  |  Branch (515:21): [True: 0, False: 0]
  ------------------
  516|      0|                    mGeneratedMesh->mColors[0] = new aiColor4D[mGeneratedMesh->mNumVertices];
  517|      0|                mGeneratedMesh->mColors[0][pos] = cOut;
  518|      0|            }
  519|       |
  520|  11.1k|            if (haveTextureCoords) {
  ------------------
  |  Branch (520:17): [True: 11.1k, False: 0]
  ------------------
  521|  11.1k|                if (nullptr == mGeneratedMesh->mTextureCoords[0]) {
  ------------------
  |  Branch (521:21): [True: 1, False: 11.1k]
  ------------------
  522|      1|                    mGeneratedMesh->mNumUVComponents[0] = 2;
  523|      1|                    mGeneratedMesh->mTextureCoords[0] = new aiVector3D[mGeneratedMesh->mNumVertices];
  524|      1|                }
  525|  11.1k|                mGeneratedMesh->mTextureCoords[0][pos] = tOut;
  526|  11.1k|            }
  527|  11.1k|        }
  528|  11.4k|    }
_ZN6Assimp11PLYImporter8LoadFaceEPKNS_3PLY7ElementEPKNS1_15ElementInstanceEj:
  533|  3.73k|            unsigned int pos) {
  534|  3.73k|        ai_assert(nullptr != pcElement);
  535|  3.73k|        ai_assert(nullptr != instElement);
  536|       |
  537|  3.73k|        if (mGeneratedMesh == nullptr) {
  ------------------
  |  Branch (537:13): [True: 0, False: 3.73k]
  ------------------
  538|      0|            throw DeadlyImportError("Invalid .ply file: Vertices should be declared before faces");
  539|      0|        }
  540|       |
  541|  3.73k|        bool bOne = false;
  542|       |
  543|       |        // index of the vertex index list
  544|  3.73k|        unsigned int iProperty = NotSet;
  545|  3.73k|        EDataType eType = EDT_Char;
  546|  3.73k|        bool bIsTriStrip = false;
  547|       |
  548|       |        // texture coordinates
  549|  3.73k|        unsigned int iTextureCoord = NotSet;
  550|  3.73k|        EDataType eType3 = EDT_Char;
  551|       |
  552|       |        // face = unique number of vertex indices
  553|  3.73k|        if (EEST_Face == pcElement->eSemantic) {
  ------------------
  |  Branch (553:13): [True: 3.73k, False: 0]
  ------------------
  554|  3.73k|            unsigned int _a = 0;
  555|  3.73k|            for (std::vector<Property>::const_iterator a = pcElement->alProperties.begin();
  556|  7.46k|                    a != pcElement->alProperties.end(); ++a, ++_a) {
  ------------------
  |  Branch (556:21): [True: 3.73k, False: 3.73k]
  ------------------
  557|  3.73k|                if (EST_VertexIndex == a->Semantic) {
  ------------------
  |  Branch (557:21): [True: 3.73k, False: 0]
  ------------------
  558|       |                    // must be a dynamic list!
  559|  3.73k|                    if (!a->bIsList) {
  ------------------
  |  Branch (559:25): [True: 0, False: 3.73k]
  ------------------
  560|      0|                        continue;
  561|      0|                    }
  562|       |
  563|  3.73k|                    iProperty = _a;
  564|  3.73k|                    bOne = true;
  565|  3.73k|                    eType = a->eType;
  566|  3.73k|                } else if (EST_TextureCoordinates == a->Semantic) {
  ------------------
  |  Branch (566:28): [True: 0, False: 0]
  ------------------
  567|       |                    // must be a dynamic list!
  568|      0|                    if (!a->bIsList) {
  ------------------
  |  Branch (568:25): [True: 0, False: 0]
  ------------------
  569|      0|                        continue;
  570|      0|                    }
  571|      0|                    iTextureCoord = _a;
  572|      0|                    bOne = true;
  573|      0|                    eType3 = a->eType;
  574|      0|                }
  575|  3.73k|            }
  576|  3.73k|        }
  577|       |        // triangle strip
  578|       |        // TODO: material index support???
  579|      0|        else if (EEST_TriStrip == pcElement->eSemantic) {
  ------------------
  |  Branch (579:18): [True: 0, False: 0]
  ------------------
  580|      0|            unsigned int _a = 0;
  581|      0|            for (auto a = pcElement->alProperties.begin(); a != pcElement->alProperties.end(); ++a, ++_a) {
  ------------------
  |  Branch (581:60): [True: 0, False: 0]
  ------------------
  582|       |                // must be a dynamic list!
  583|      0|                if (!a->bIsList) {
  ------------------
  |  Branch (583:21): [True: 0, False: 0]
  ------------------
  584|      0|                    continue;
  585|      0|                }
  586|      0|                iProperty = _a;
  587|      0|                bOne = true;
  588|      0|                bIsTriStrip = true;
  589|      0|                eType = a->eType;
  590|      0|                break;
  591|      0|            }
  592|      0|        }
  593|       |
  594|       |        // check whether we have at least one per-face information set
  595|  3.73k|        if (bOne) {
  ------------------
  |  Branch (595:13): [True: 3.73k, False: 0]
  ------------------
  596|  3.73k|            if (mGeneratedMesh->mFaces == nullptr) {
  ------------------
  |  Branch (596:17): [True: 1, False: 3.73k]
  ------------------
  597|      1|                mGeneratedMesh->mNumFaces = pcElement->NumOccur;
  598|      1|                mGeneratedMesh->mFaces = new aiFace[mGeneratedMesh->mNumFaces];
  599|  3.73k|            } else {
  600|  3.73k|                if (mGeneratedMesh->mNumFaces < pcElement->NumOccur) {
  ------------------
  |  Branch (600:21): [True: 0, False: 3.73k]
  ------------------
  601|      0|                    throw DeadlyImportError("Invalid .ply file: Too many faces");
  602|      0|                }
  603|  3.73k|            }
  604|       |
  605|  3.73k|            if (!bIsTriStrip) {
  ------------------
  |  Branch (605:17): [True: 3.73k, False: 0]
  ------------------
  606|       |                // parse the list of vertex indices
  607|  3.73k|                if (NotSet != iProperty) {
  ------------------
  |  Branch (607:21): [True: 3.73k, False: 0]
  ------------------
  608|  3.73k|                    const unsigned int iNum = static_cast<unsigned int>(GetProperty(instElement->alProperties, iProperty).avList.size());
  609|  3.73k|                    mGeneratedMesh->mFaces[pos].mNumIndices = iNum;
  610|  3.73k|                    mGeneratedMesh->mFaces[pos].mIndices = new unsigned int[iNum];
  611|       |
  612|  3.73k|                    std::vector<PropertyInstance::ValueUnion>::const_iterator p =
  613|  3.73k|                            GetProperty(instElement->alProperties, iProperty).avList.begin();
  614|       |
  615|  14.9k|                    for (unsigned int a = 0; a < iNum; ++a, ++p) {
  ------------------
  |  Branch (615:46): [True: 11.1k, False: 3.73k]
  ------------------
  616|  11.1k|                        mGeneratedMesh->mFaces[pos].mIndices[a] = PropertyInstance::ConvertTo<unsigned int>(*p, eType);
  617|  11.1k|                    }
  618|  3.73k|                }
  619|       |
  620|  3.73k|                if (NotSet != iTextureCoord) {
  ------------------
  |  Branch (620:21): [True: 0, False: 3.73k]
  ------------------
  621|      0|                    const auto iNum = static_cast<unsigned int>(GetProperty(instElement->alProperties, iTextureCoord).avList.size());
  622|       |
  623|       |                    // should be 6 coords
  624|      0|                    auto p = GetProperty(instElement->alProperties, iTextureCoord).avList.begin();
  625|      0|                    if ((iNum / 3) == 2) { // X Y coord
  ------------------
  |  Branch (625:25): [True: 0, False: 0]
  ------------------
  626|      0|                        for (unsigned int a = 0; a < iNum; ++a, ++p) {
  ------------------
  |  Branch (626:50): [True: 0, False: 0]
  ------------------
  627|      0|                            unsigned int vindex = mGeneratedMesh->mFaces[pos].mIndices[a / 2];
  628|      0|                            if (vindex < mGeneratedMesh->mNumVertices) {
  ------------------
  |  Branch (628:33): [True: 0, False: 0]
  ------------------
  629|      0|                                if (mGeneratedMesh->mTextureCoords[0] == nullptr) {
  ------------------
  |  Branch (629:37): [True: 0, False: 0]
  ------------------
  630|      0|                                    mGeneratedMesh->mNumUVComponents[0] = 2;
  631|      0|                                    mGeneratedMesh->mTextureCoords[0] = new aiVector3D[mGeneratedMesh->mNumVertices];
  632|      0|                                }
  633|       |
  634|      0|                                if (a % 2 == 0) {
  ------------------
  |  Branch (634:37): [True: 0, False: 0]
  ------------------
  635|      0|                                    mGeneratedMesh->mTextureCoords[0][vindex].x = PLY::PropertyInstance::ConvertTo<ai_real>(*p, eType3);
  636|      0|                                } else {
  637|      0|                                    mGeneratedMesh->mTextureCoords[0][vindex].y = PLY::PropertyInstance::ConvertTo<ai_real>(*p, eType3);
  638|      0|                                }
  639|       |
  640|      0|                                mGeneratedMesh->mTextureCoords[0][vindex].z = 0;
  641|      0|                            }
  642|      0|                        }
  643|      0|                    }
  644|      0|                }
  645|  3.73k|            } else { // triangle strips
  646|       |                // normally we have only one triangle strip instance where
  647|       |                // a value of -1 indicates a restart of the strip
  648|      0|                createFromeTriStrip(instElement, iProperty, eType);
  649|      0|            }
  650|  3.73k|        }
  651|  3.73k|    }
_ZN6Assimp11PLYImporter12LoadMaterialEPNSt3__16vectorIP10aiMaterialNS1_9allocatorIS4_EEEERNS1_12basic_stringIcNS1_11char_traitsIcEENS5_IcEEEEb:
  705|      1|    void PLYImporter::LoadMaterial(std::vector<aiMaterial *> *pvOut, std::string &defaultTexture, const bool pointsOnly) {
  706|      1|        ai_assert(nullptr != pvOut);
  707|       |
  708|       |        // diffuse[4], specular[4], ambient[4]
  709|       |        // rgba order
  710|      1|        unsigned int aaiPositions[3][4] = {
  711|      1|            { 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF },
  712|      1|            { 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF },
  713|      1|            { 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF },
  714|      1|        };
  715|       |
  716|      1|        EDataType aaiTypes[3][4] = {
  717|      1|            { EDT_Char, EDT_Char, EDT_Char, EDT_Char },
  718|      1|            { EDT_Char, EDT_Char, EDT_Char, EDT_Char },
  719|      1|            { EDT_Char, EDT_Char, EDT_Char, EDT_Char }
  720|      1|        };
  721|      1|        ElementInstanceList *pcList = nullptr;
  722|       |
  723|      1|        unsigned int iPhong = 0xFFFFFFFF;
  724|      1|        EDataType ePhong = EDT_Char;
  725|       |
  726|      1|        unsigned int iOpacity = 0xFFFFFFFF;
  727|      1|        EDataType eOpacity = EDT_Char;
  728|       |
  729|       |        // search in the DOM for a vertex entry
  730|      1|        unsigned int _i = 0;
  731|      1|        for (std::vector<Element>::const_iterator i = this->pcDOM->alElements.begin();
  732|      3|                i != this->pcDOM->alElements.end(); ++i, ++_i) {
  ------------------
  |  Branch (732:17): [True: 2, False: 1]
  ------------------
  733|      2|            if (EEST_Material == i->eSemantic) {
  ------------------
  |  Branch (733:17): [True: 0, False: 2]
  ------------------
  734|      0|                pcList = &this->pcDOM->alElementData[_i];
  735|       |
  736|       |                // now check whether which coordinate sets are available
  737|      0|                unsigned int _a = 0;
  738|      0|                for (std::vector<Property>::const_iterator a = i->alProperties.begin(); a != i->alProperties.end(); ++a, ++_a) {
  ------------------
  |  Branch (738:89): [True: 0, False: 0]
  ------------------
  739|      0|                    if (a->bIsList) {
  ------------------
  |  Branch (739:25): [True: 0, False: 0]
  ------------------
  740|      0|                        continue;
  741|      0|                    }
  742|       |
  743|       |                    // pohng specularity      -----------------------------------
  744|      0|                    if (EST_PhongPower == (*a).Semantic) {
  ------------------
  |  Branch (744:25): [True: 0, False: 0]
  ------------------
  745|      0|                        iPhong = _a;
  746|      0|                        ePhong = (*a).eType;
  747|      0|                    }
  748|       |
  749|       |                    // general opacity        -----------------------------------
  750|      0|                    if (EST_Opacity == (*a).Semantic) {
  ------------------
  |  Branch (750:25): [True: 0, False: 0]
  ------------------
  751|      0|                        iOpacity = _a;
  752|      0|                        eOpacity = (*a).eType;
  753|      0|                    }
  754|       |
  755|       |                    // diffuse color channels -----------------------------------
  756|      0|                    if (EST_DiffuseRed == (*a).Semantic) {
  ------------------
  |  Branch (756:25): [True: 0, False: 0]
  ------------------
  757|      0|                        aaiPositions[0][0] = _a;
  758|      0|                        aaiTypes[0][0] = (*a).eType;
  759|      0|                    } else if (EST_DiffuseGreen == (*a).Semantic) {
  ------------------
  |  Branch (759:32): [True: 0, False: 0]
  ------------------
  760|      0|                        aaiPositions[0][1] = _a;
  761|      0|                        aaiTypes[0][1] = (*a).eType;
  762|      0|                    } else if (EST_DiffuseBlue == (*a).Semantic) {
  ------------------
  |  Branch (762:32): [True: 0, False: 0]
  ------------------
  763|      0|                        aaiPositions[0][2] = _a;
  764|      0|                        aaiTypes[0][2] = (*a).eType;
  765|      0|                    } else if (EST_DiffuseAlpha == (*a).Semantic) {
  ------------------
  |  Branch (765:32): [True: 0, False: 0]
  ------------------
  766|      0|                        aaiPositions[0][3] = _a;
  767|      0|                        aaiTypes[0][3] = (*a).eType;
  768|      0|                    }
  769|       |                    // specular color channels -----------------------------------
  770|      0|                    else if (EST_SpecularRed == (*a).Semantic) {
  ------------------
  |  Branch (770:30): [True: 0, False: 0]
  ------------------
  771|      0|                        aaiPositions[1][0] = _a;
  772|      0|                        aaiTypes[1][0] = (*a).eType;
  773|      0|                    } else if (EST_SpecularGreen == (*a).Semantic) {
  ------------------
  |  Branch (773:32): [True: 0, False: 0]
  ------------------
  774|      0|                        aaiPositions[1][1] = _a;
  775|      0|                        aaiTypes[1][1] = (*a).eType;
  776|      0|                    } else if (EST_SpecularBlue == (*a).Semantic) {
  ------------------
  |  Branch (776:32): [True: 0, False: 0]
  ------------------
  777|      0|                        aaiPositions[1][2] = _a;
  778|      0|                        aaiTypes[1][2] = (*a).eType;
  779|      0|                    } else if (EST_SpecularAlpha == (*a).Semantic) {
  ------------------
  |  Branch (779:32): [True: 0, False: 0]
  ------------------
  780|      0|                        aaiPositions[1][3] = _a;
  781|      0|                        aaiTypes[1][3] = (*a).eType;
  782|      0|                    }
  783|       |                    // ambient color channels -----------------------------------
  784|      0|                    else if (EST_AmbientRed == (*a).Semantic) {
  ------------------
  |  Branch (784:30): [True: 0, False: 0]
  ------------------
  785|      0|                        aaiPositions[2][0] = _a;
  786|      0|                        aaiTypes[2][0] = (*a).eType;
  787|      0|                    } else if (EST_AmbientGreen == (*a).Semantic) {
  ------------------
  |  Branch (787:32): [True: 0, False: 0]
  ------------------
  788|      0|                        aaiPositions[2][1] = _a;
  789|      0|                        aaiTypes[2][1] = (*a).eType;
  790|      0|                    } else if (EST_AmbientBlue == (*a).Semantic) {
  ------------------
  |  Branch (790:32): [True: 0, False: 0]
  ------------------
  791|      0|                        aaiPositions[2][2] = _a;
  792|      0|                        aaiTypes[2][2] = (*a).eType;
  793|      0|                    } else if (EST_AmbientAlpha == (*a).Semantic) {
  ------------------
  |  Branch (793:32): [True: 0, False: 0]
  ------------------
  794|      0|                        aaiPositions[2][3] = _a;
  795|      0|                        aaiTypes[2][3] = (*a).eType;
  796|      0|                    }
  797|      0|                }
  798|      0|                break;
  799|      2|            } else if (EEST_TextureFile == i->eSemantic) {
  ------------------
  |  Branch (799:24): [True: 0, False: 2]
  ------------------
  800|      0|                defaultTexture = i->szName;
  801|      0|            }
  802|      2|        }
  803|       |        // check whether we have a valid source for the material data
  804|      1|        if (nullptr != pcList) {
  ------------------
  |  Branch (804:13): [True: 0, False: 1]
  ------------------
  805|      0|            for (std::vector<ElementInstance>::const_iterator i = pcList->alInstances.begin(); i != pcList->alInstances.end(); ++i) {
  ------------------
  |  Branch (805:96): [True: 0, False: 0]
  ------------------
  806|      0|                aiColor4D clrOut;
  807|      0|                aiMaterial *pcHelper = new aiMaterial();
  808|       |
  809|       |                // build the diffuse material color
  810|      0|                GetMaterialColor((*i).alProperties, aaiPositions[0], aaiTypes[0], &clrOut);
  811|      0|                pcHelper->AddProperty<aiColor4D>(&clrOut, 1, AI_MATKEY_COLOR_DIFFUSE);
  812|       |
  813|       |                // build the specular material color
  814|      0|                GetMaterialColor((*i).alProperties, aaiPositions[1], aaiTypes[1], &clrOut);
  815|      0|                pcHelper->AddProperty<aiColor4D>(&clrOut, 1, AI_MATKEY_COLOR_SPECULAR);
  816|       |
  817|       |                // build the ambient material color
  818|      0|                GetMaterialColor((*i).alProperties, aaiPositions[2], aaiTypes[2], &clrOut);
  819|      0|                pcHelper->AddProperty<aiColor4D>(&clrOut, 1, AI_MATKEY_COLOR_AMBIENT);
  820|       |
  821|       |                // handle phong power and shading mode
  822|      0|                int iMode = aiShadingMode_Gouraud;
  823|      0|                if (0xFFFFFFFF != iPhong) {
  ------------------
  |  Branch (823:21): [True: 0, False: 0]
  ------------------
  824|      0|                    ai_real fSpec = PropertyInstance::ConvertTo<ai_real>(GetProperty((*i).alProperties, iPhong).avList.front(), ePhong);
  825|       |
  826|       |                    // if shininess is 0 (and the pow() calculation would therefore always
  827|       |                    // become 1, not depending on the angle), use gouraud lighting
  828|      0|                    if (fSpec) {
  ------------------
  |  Branch (828:25): [True: 0, False: 0]
  ------------------
  829|       |                        // scale this with 15 ... hopefully this is correct
  830|      0|                        fSpec *= 15;
  831|      0|                        pcHelper->AddProperty<ai_real>(&fSpec, 1, AI_MATKEY_SHININESS);
  832|       |
  833|      0|                        iMode = static_cast<int>(aiShadingMode_Phong);
  834|      0|                    }
  835|      0|                }
  836|      0|                pcHelper->AddProperty<int>(&iMode, 1, AI_MATKEY_SHADING_MODEL);
  837|       |
  838|       |                // handle opacity
  839|      0|                if (0xFFFFFFFF != iOpacity) {
  ------------------
  |  Branch (839:21): [True: 0, False: 0]
  ------------------
  840|      0|                    ai_real fOpacity = PropertyInstance::ConvertTo<ai_real>(GetProperty((*i).alProperties, iPhong).avList.front(), eOpacity);
  841|      0|                    pcHelper->AddProperty<ai_real>(&fOpacity, 1, AI_MATKEY_OPACITY);
  842|      0|                }
  843|       |
  844|       |                // The face order is absolutely undefined for PLY, so we have to
  845|       |                // use two-sided rendering to be sure it's ok.
  846|      0|                const int two_sided = 1;
  847|      0|                pcHelper->AddProperty(&two_sided, 1, AI_MATKEY_TWOSIDED);
  848|       |
  849|       |                // default texture
  850|      0|                if (!defaultTexture.empty()) {
  ------------------
  |  Branch (850:21): [True: 0, False: 0]
  ------------------
  851|      0|                    const aiString name(defaultTexture.c_str());
  852|      0|                    pcHelper->AddProperty(&name, _AI_MATKEY_TEXTURE_BASE, aiTextureType_DIFFUSE, 0);
  853|      0|                }
  854|       |
  855|      0|                if (!pointsOnly) {
  ------------------
  |  Branch (855:21): [True: 0, False: 0]
  ------------------
  856|      0|                    pcHelper->AddProperty(&two_sided, 1, AI_MATKEY_TWOSIDED);
  857|      0|                }
  858|       |
  859|       |                // set to wireframe, so when using this material info we can switch to points rendering
  860|      0|                if (pointsOnly) {
  ------------------
  |  Branch (860:21): [True: 0, False: 0]
  ------------------
  861|      0|                    constexpr int wireframe = 1;
  862|      0|                    pcHelper->AddProperty(&wireframe, 1, AI_MATKEY_ENABLE_WIREFRAME);
  863|      0|                }
  864|       |
  865|       |                // add the newly created material instance to the list
  866|      0|                pvOut->push_back(pcHelper);
  867|      0|            }
  868|      1|        } else {
  869|       |            // generate a default material
  870|      1|            aiMaterial *pcHelper = new aiMaterial();
  871|       |
  872|       |            // fill in a default material
  873|      1|            int iMode = aiShadingMode_Gouraud;
  874|      1|            pcHelper->AddProperty<int>(&iMode, 1, AI_MATKEY_SHADING_MODEL);
  875|       |
  876|       |            // generate white material most 3D engine just multiply ambient / diffuse color with actual ambient / light color
  877|      1|            aiColor3D clr;
  878|      1|            clr.b = clr.g = clr.r = 1.0f;
  879|      1|            pcHelper->AddProperty<aiColor3D>(&clr, 1, AI_MATKEY_COLOR_DIFFUSE);
  880|      1|            pcHelper->AddProperty<aiColor3D>(&clr, 1, AI_MATKEY_COLOR_SPECULAR);
  881|       |
  882|      1|            clr.b = clr.g = clr.r = 1.0f;
  883|      1|            pcHelper->AddProperty<aiColor3D>(&clr, 1, AI_MATKEY_COLOR_AMBIENT);
  884|       |
  885|       |            // The face order is absolutely undefined for PLY, so we have to
  886|       |            // use two-sided rendering to be sure it's ok.
  887|      1|            if (!pointsOnly) {
  ------------------
  |  Branch (887:17): [True: 1, False: 0]
  ------------------
  888|      1|                const int two_sided = 1;
  889|      1|                pcHelper->AddProperty(&two_sided, 1, AI_MATKEY_TWOSIDED);
  890|      1|            }
  891|       |
  892|       |            // default texture
  893|      1|            if (!defaultTexture.empty()) {
  ------------------
  |  Branch (893:17): [True: 0, False: 1]
  ------------------
  894|      0|                const aiString name(defaultTexture.c_str());
  895|      0|                pcHelper->AddProperty(&name, _AI_MATKEY_TEXTURE_BASE, aiTextureType_DIFFUSE, 0);
  896|      0|            }
  897|       |
  898|       |            // set to wireframe, so when using this material info we can switch to points rendering
  899|      1|            if (pointsOnly) {
  ------------------
  |  Branch (899:17): [True: 0, False: 1]
  ------------------
  900|      0|                constexpr int wireframe = 1;
  901|      0|                pcHelper->AddProperty(&wireframe, 1, AI_MATKEY_ENABLE_WIREFRAME);
  902|      0|            }
  903|       |
  904|      1|            pvOut->push_back(pcHelper);
  905|      1|        }
  906|      1|    }
PlyLoader.cpp:_ZN6Assimp12_GLOBAL__N_111GetPropertyINS_3PLY16PropertyInstanceEEERKT_RKNSt3__16vectorIS4_NS7_9allocatorIS4_EEEEi:
   82|  96.9k|        const T &GetProperty(const std::vector<T> &props, int idx) {
   83|  96.9k|            if (static_cast<size_t>(idx) >= props.size()) {
  ------------------
  |  Branch (83:17): [True: 0, False: 96.9k]
  ------------------
   84|      0|                throw DeadlyImportError("Invalid .ply file: Property index is out of range.");
   85|      0|            }
   86|       |
   87|  96.9k|            return props[idx];
   88|  96.9k|        }

_ZN6Assimp11PLYImporterC2Ev:
   68|    624|    PLYImporter() = default;

_ZN6Assimp3PLY8Property13ParseDataTypeERNSt3__16vectorIcNS2_9allocatorIcEEEE:
   74|     17|EDataType Property::ParseDataType(std::vector<char> &buffer) {
   75|     17|    ai_assert(!buffer.empty());
   76|       |
   77|     17|    EDataType eOut = EDT_INVALID;
   78|       |
   79|     17|    if (DOM::TokenMatch(buffer, "char", 4) ||
  ------------------
  |  Branch (79:9): [True: 0, False: 17]
  ------------------
   80|     17|               DOM::TokenMatch(buffer, "int8", 4)) {
  ------------------
  |  Branch (80:16): [True: 0, False: 17]
  ------------------
   81|      0|        eOut = EDT_Char;
   82|     17|    } else if (DOM::TokenMatch(buffer, "uchar", 5) ||
  ------------------
  |  Branch (82:16): [True: 1, False: 16]
  ------------------
   83|     16|               DOM::TokenMatch(buffer, "uint8", 5)) {
  ------------------
  |  Branch (83:16): [True: 0, False: 16]
  ------------------
   84|      1|        eOut = EDT_UChar;
   85|     16|    } else if (DOM::TokenMatch(buffer, "short", 5) ||
  ------------------
  |  Branch (85:16): [True: 0, False: 16]
  ------------------
   86|     16|               DOM::TokenMatch(buffer, "int16", 5)) {
  ------------------
  |  Branch (86:16): [True: 0, False: 16]
  ------------------
   87|      0|        eOut = EDT_Short;
   88|     16|    } else if (DOM::TokenMatch(buffer, "ushort", 6) ||
  ------------------
  |  Branch (88:16): [True: 0, False: 16]
  ------------------
   89|     16|               DOM::TokenMatch(buffer, "uint16", 6)) {
  ------------------
  |  Branch (89:16): [True: 0, False: 16]
  ------------------
   90|      0|        eOut = EDT_UShort;
   91|     16|    } else if (DOM::TokenMatch(buffer, "int32", 5) || DOM::TokenMatch(buffer, "int", 3)) {
  ------------------
  |  Branch (91:16): [True: 0, False: 16]
  |  Branch (91:55): [True: 3, False: 13]
  ------------------
   92|      3|        eOut = EDT_Int;
   93|     13|    } else if (DOM::TokenMatch(buffer, "uint32", 6) || DOM::TokenMatch(buffer, "uint", 4)) {
  ------------------
  |  Branch (93:16): [True: 0, False: 13]
  |  Branch (93:56): [True: 2, False: 11]
  ------------------
   94|      2|        eOut = EDT_UInt;
   95|     11|    } else if (DOM::TokenMatch(buffer, "float", 5) || DOM::TokenMatch(buffer, "float32", 7)) {
  ------------------
  |  Branch (95:16): [True: 11, False: 0]
  |  Branch (95:55): [True: 0, False: 0]
  ------------------
   96|     11|        eOut = EDT_Float;
   97|     11|    } else if (DOM::TokenMatch(buffer, "double64", 8) || DOM::TokenMatch(buffer, "double", 6) ||
  ------------------
  |  Branch (97:16): [True: 0, False: 0]
  |  Branch (97:58): [True: 0, False: 0]
  ------------------
   98|      0|               DOM::TokenMatch(buffer, "float64", 7)) {
  ------------------
  |  Branch (98:16): [True: 0, False: 0]
  ------------------
   99|      0|        eOut = EDT_Double;
  100|      0|    }
  101|     17|    if (EDT_INVALID == eOut) {
  ------------------
  |  Branch (101:9): [True: 0, False: 17]
  ------------------
  102|      0|        ASSIMP_LOG_INFO("Found unknown data type in PLY file. This is OK");
  103|      0|    }
  104|       |
  105|     17|    return eOut;
  106|     17|}
_ZN6Assimp3PLY8Property13ParseSemanticERNSt3__16vectorIcNS2_9allocatorIcEEEE:
  109|     15|ESemantic Property::ParseSemantic(std::vector<char> &buffer) {
  110|     15|    ai_assert(!buffer.empty());
  111|       |
  112|     15|    ESemantic eOut = PLY::EST_INVALID;
  113|     15|    if (DOM::TokenMatch(buffer, "red", 3)) {
  ------------------
  |  Branch (113:9): [True: 0, False: 15]
  ------------------
  114|      0|        eOut = EST_Red;
  115|     15|    } else if (DOM::TokenMatch(buffer, "green", 5)) {
  ------------------
  |  Branch (115:16): [True: 0, False: 15]
  ------------------
  116|      0|        eOut = EST_Green;
  117|     15|    } else if (DOM::TokenMatch(buffer, "blue", 4)) {
  ------------------
  |  Branch (117:16): [True: 0, False: 15]
  ------------------
  118|      0|        eOut = EST_Blue;
  119|     15|    } else if (DOM::TokenMatch(buffer, "alpha", 5)) {
  ------------------
  |  Branch (119:16): [True: 0, False: 15]
  ------------------
  120|      0|        eOut = EST_Alpha;
  121|     15|    } else if (DOM::TokenMatch(buffer, "vertex_index", 12) || PLY::DOM::TokenMatch(buffer, "vertex_indices", 14)) {
  ------------------
  |  Branch (121:16): [True: 0, False: 15]
  |  Branch (121:63): [True: 1, False: 14]
  ------------------
  122|      1|        eOut = EST_VertexIndex;
  123|     14|    } else if (DOM::TokenMatch(buffer, "texcoord", 8)) // Manage uv coords on faces
  ------------------
  |  Branch (123:16): [True: 0, False: 14]
  ------------------
  124|      0|    {
  125|      0|        eOut = EST_TextureCoordinates;
  126|     14|    } else if (DOM::TokenMatch(buffer, "material_index", 14)) {
  ------------------
  |  Branch (126:16): [True: 0, False: 14]
  ------------------
  127|      0|        eOut = EST_MaterialIndex;
  128|     14|    } else if (DOM::TokenMatch(buffer, "ambient_red", 11)) {
  ------------------
  |  Branch (128:16): [True: 0, False: 14]
  ------------------
  129|      0|        eOut = EST_AmbientRed;
  130|     14|    } else if (DOM::TokenMatch(buffer, "ambient_green", 13)) {
  ------------------
  |  Branch (130:16): [True: 0, False: 14]
  ------------------
  131|      0|        eOut = EST_AmbientGreen;
  132|     14|    } else if (DOM::TokenMatch(buffer, "ambient_blue", 12)) {
  ------------------
  |  Branch (132:16): [True: 0, False: 14]
  ------------------
  133|      0|        eOut = EST_AmbientBlue;
  134|     14|    } else if (DOM::TokenMatch(buffer, "ambient_alpha", 13)) {
  ------------------
  |  Branch (134:16): [True: 0, False: 14]
  ------------------
  135|      0|        eOut = EST_AmbientAlpha;
  136|     14|    } else if (DOM::TokenMatch(buffer, "diffuse_red", 11)) {
  ------------------
  |  Branch (136:16): [True: 0, False: 14]
  ------------------
  137|      0|        eOut = EST_DiffuseRed;
  138|     14|    } else if (DOM::TokenMatch(buffer, "diffuse_green", 13)) {
  ------------------
  |  Branch (138:16): [True: 0, False: 14]
  ------------------
  139|      0|        eOut = EST_DiffuseGreen;
  140|     14|    } else if (DOM::TokenMatch(buffer, "diffuse_blue", 12)) {
  ------------------
  |  Branch (140:16): [True: 0, False: 14]
  ------------------
  141|      0|        eOut = EST_DiffuseBlue;
  142|     14|    } else if (DOM::TokenMatch(buffer, "diffuse_alpha", 13)) {
  ------------------
  |  Branch (142:16): [True: 0, False: 14]
  ------------------
  143|      0|        eOut = EST_DiffuseAlpha;
  144|     14|    } else if (DOM::TokenMatch(buffer, "specular_red", 12)) {
  ------------------
  |  Branch (144:16): [True: 0, False: 14]
  ------------------
  145|      0|        eOut = EST_SpecularRed;
  146|     14|    } else if (DOM::TokenMatch(buffer, "specular_green", 14)) {
  ------------------
  |  Branch (146:16): [True: 0, False: 14]
  ------------------
  147|      0|        eOut = EST_SpecularGreen;
  148|     14|    } else if (DOM::TokenMatch(buffer, "specular_blue", 13)) {
  ------------------
  |  Branch (148:16): [True: 0, False: 14]
  ------------------
  149|      0|        eOut = EST_SpecularBlue;
  150|     14|    } else if (DOM::TokenMatch(buffer, "specular_alpha", 14)) {
  ------------------
  |  Branch (150:16): [True: 0, False: 14]
  ------------------
  151|      0|        eOut = EST_SpecularAlpha;
  152|     14|    } else if (DOM::TokenMatch(buffer, "opacity", 7)) {
  ------------------
  |  Branch (152:16): [True: 0, False: 14]
  ------------------
  153|      0|        eOut = EST_Opacity;
  154|     14|    } else if (DOM::TokenMatch(buffer, "specular_power", 14)) {
  ------------------
  |  Branch (154:16): [True: 0, False: 14]
  ------------------
  155|      0|        eOut = EST_PhongPower;
  156|     14|    } else if (DOM::TokenMatch(buffer, "r", 1)) {
  ------------------
  |  Branch (156:16): [True: 0, False: 14]
  ------------------
  157|      0|        eOut = EST_Red;
  158|     14|    } else if (DOM::TokenMatch(buffer, "g", 1)) {
  ------------------
  |  Branch (158:16): [True: 0, False: 14]
  ------------------
  159|      0|        eOut = EST_Green;
  160|     14|    } else if (DOM::TokenMatch(buffer, "b", 1)) {
  ------------------
  |  Branch (160:16): [True: 0, False: 14]
  ------------------
  161|      0|        eOut = EST_Blue;
  162|      0|    }
  163|       |
  164|       |    // NOTE: Blender3D exports texture coordinates as s,t tuples
  165|     14|    else if (DOM::TokenMatch(buffer, "u", 1) || PLY::DOM::TokenMatch(buffer, "s", 1) || PLY::DOM::TokenMatch(buffer, "tx", 2) || PLY::DOM::TokenMatch(buffer, "texture_u", 9)) {
  ------------------
  |  Branch (165:14): [True: 0, False: 14]
  |  Branch (165:49): [True: 1, False: 13]
  |  Branch (165:89): [True: 0, False: 13]
  |  Branch (165:130): [True: 0, False: 13]
  ------------------
  166|      1|        eOut = EST_UTextureCoord;
  167|     13|    } else if (DOM::TokenMatch(buffer, "v", 1) || PLY::DOM::TokenMatch(buffer, "t", 1) || PLY::DOM::TokenMatch(buffer, "ty", 2) || PLY::DOM::TokenMatch(buffer, "texture_v", 9)) {
  ------------------
  |  Branch (167:16): [True: 0, False: 13]
  |  Branch (167:51): [True: 1, False: 12]
  |  Branch (167:91): [True: 0, False: 12]
  |  Branch (167:132): [True: 0, False: 12]
  ------------------
  168|      1|        eOut = EST_VTextureCoord;
  169|     12|    } else if (DOM::TokenMatch(buffer, "x", 1)) {
  ------------------
  |  Branch (169:16): [True: 3, False: 9]
  ------------------
  170|      3|        eOut = EST_XCoord;
  171|      9|    } else if (DOM::TokenMatch(buffer, "y", 1)) {
  ------------------
  |  Branch (171:16): [True: 2, False: 7]
  ------------------
  172|      2|        eOut = EST_YCoord;
  173|      7|    } else if (DOM::TokenMatch(buffer, "z", 1)) {
  ------------------
  |  Branch (173:16): [True: 2, False: 5]
  ------------------
  174|      2|        eOut = EST_ZCoord;
  175|      5|    } else if (DOM::TokenMatch(buffer, "nx", 2)) {
  ------------------
  |  Branch (175:16): [True: 2, False: 3]
  ------------------
  176|      2|        eOut = EST_XNormal;
  177|      3|    } else if (DOM::TokenMatch(buffer, "ny", 2)) {
  ------------------
  |  Branch (177:16): [True: 1, False: 2]
  ------------------
  178|      1|        eOut = EST_YNormal;
  179|      2|    } else if (DOM::TokenMatch(buffer, "nz", 2)) {
  ------------------
  |  Branch (179:16): [True: 1, False: 1]
  ------------------
  180|      1|        eOut = EST_ZNormal;
  181|      1|    } else {
  182|       |        ASSIMP_LOG_INFO("Found unknown property semantic in file. This is ok");
  183|      1|        DOM::SkipLine(buffer);
  184|      1|    }
  185|     15|    return eOut;
  186|     15|}
_ZN6Assimp3PLY8Property13ParsePropertyERNSt3__16vectorIcNS2_9allocatorIcEEEEPS1_:
  189|     20|bool PLY::Property::ParseProperty(std::vector<char> &buffer, PLY::Property *pOut) {
  190|     20|    ai_assert(!buffer.empty());
  191|       |
  192|       |    // Forms supported:
  193|       |    // "property float x"
  194|       |    // "property list uchar int vertex_index"
  195|       |
  196|       |    // skip leading spaces
  197|     20|    if (!DOM::SkipSpaces(buffer)) {
  ------------------
  |  Branch (197:9): [True: 0, False: 20]
  ------------------
  198|      0|        return false;
  199|      0|    }
  200|       |
  201|       |    // skip the "property" string at the beginning
  202|     20|    if (!DOM::TokenMatch(buffer, "property", 8)) {
  ------------------
  |  Branch (202:9): [True: 5, False: 15]
  ------------------
  203|       |        // seems not to be a valid property entry
  204|      5|        return false;
  205|      5|    }
  206|       |    // get next word
  207|     15|    if (!PLY::DOM::SkipSpaces(buffer)) {
  ------------------
  |  Branch (207:9): [True: 0, False: 15]
  ------------------
  208|      0|        return false;
  209|      0|    }
  210|     15|    if (PLY::DOM::TokenMatch(buffer, "list", 4)) {
  ------------------
  |  Branch (210:9): [True: 2, False: 13]
  ------------------
  211|      2|        pOut->bIsList = true;
  212|       |
  213|       |        // seems to be a list.
  214|      2|        if (EDT_INVALID == (pOut->eFirstType = PLY::Property::ParseDataType(buffer))) {
  ------------------
  |  Branch (214:13): [True: 0, False: 2]
  ------------------
  215|       |            // unable to parse list size data type
  216|      0|            PLY::DOM::SkipLine(buffer);
  217|      0|            return false;
  218|      0|        }
  219|      2|        if (!PLY::DOM::SkipSpaces(buffer)) return false;
  ------------------
  |  Branch (219:13): [True: 0, False: 2]
  ------------------
  220|      2|        if (EDT_INVALID == (pOut->eType = PLY::Property::ParseDataType(buffer))) {
  ------------------
  |  Branch (220:13): [True: 0, False: 2]
  ------------------
  221|       |            // unable to parse list data type
  222|      0|            PLY::DOM::SkipLine(buffer);
  223|      0|            return false;
  224|      0|        }
  225|     13|    } else {
  226|     13|        if (EDT_INVALID == (pOut->eType = PLY::Property::ParseDataType(buffer))) {
  ------------------
  |  Branch (226:13): [True: 0, False: 13]
  ------------------
  227|       |            // unable to parse data type. Skip the property
  228|      0|            PLY::DOM::SkipLine(buffer);
  229|      0|            return false;
  230|      0|        }
  231|     13|    }
  232|       |
  233|     15|    if (!PLY::DOM::SkipSpaces(buffer))
  ------------------
  |  Branch (233:9): [True: 0, False: 15]
  ------------------
  234|      0|        return false;
  235|       |
  236|     15|    pOut->Semantic = PLY::Property::ParseSemantic(buffer);
  237|       |
  238|     15|    if (PLY::EST_INVALID == pOut->Semantic) {
  ------------------
  |  Branch (238:9): [True: 1, False: 14]
  ------------------
  239|      1|        ASSIMP_LOG_INFO("Found unknown semantic in PLY file. This is OK");
  240|      1|        std::string(&buffer[0], &buffer[0] + strlen(&buffer[0]));
  241|      1|    }
  242|       |
  243|     15|    PLY::DOM::SkipSpacesAndLineEnd(buffer);
  244|     15|    return true;
  245|     15|}
_ZN6Assimp3PLY7Element13ParseSemanticERNSt3__16vectorIcNS2_9allocatorIcEEEE:
  248|      5|PLY::EElementSemantic PLY::Element::ParseSemantic(std::vector<char> &buffer) {
  249|      5|    ai_assert(!buffer.empty());
  250|       |
  251|      5|    PLY::EElementSemantic eOut = PLY::EEST_INVALID;
  252|      5|    if (PLY::DOM::TokenMatch(buffer, "vertex", 6)) {
  ------------------
  |  Branch (252:9): [True: 4, False: 1]
  ------------------
  253|      4|        eOut = PLY::EEST_Vertex;
  254|      4|    } else if (PLY::DOM::TokenMatch(buffer, "face", 4)) {
  ------------------
  |  Branch (254:16): [True: 1, False: 0]
  ------------------
  255|      1|        eOut = PLY::EEST_Face;
  256|      1|    } else if (PLY::DOM::TokenMatch(buffer, "tristrips", 9)) {
  ------------------
  |  Branch (256:16): [True: 0, False: 0]
  ------------------
  257|      0|        eOut = PLY::EEST_TriStrip;
  258|      0|    }
  259|       |#if 0
  260|       |  // TODO: maybe implement this?
  261|       |  else if (PLY::DOM::TokenMatch(buffer,"range_grid",10))
  262|       |  {
  263|       |    eOut = PLY::EEST_Face;
  264|       |  }
  265|       |#endif
  266|      0|    else if (PLY::DOM::TokenMatch(buffer, "edge", 4)) {
  ------------------
  |  Branch (266:14): [True: 0, False: 0]
  ------------------
  267|      0|        eOut = PLY::EEST_Edge;
  268|      0|    } else if (PLY::DOM::TokenMatch(buffer, "material", 8)) {
  ------------------
  |  Branch (268:16): [True: 0, False: 0]
  ------------------
  269|      0|        eOut = PLY::EEST_Material;
  270|      0|    } else if (PLY::DOM::TokenMatch(buffer, "TextureFile", 11)) {
  ------------------
  |  Branch (270:16): [True: 0, False: 0]
  ------------------
  271|      0|        eOut = PLY::EEST_TextureFile;
  272|      0|    }
  273|       |
  274|      5|    return eOut;
  275|      5|}
_ZN6Assimp3PLY7Element12ParseElementERNS_14IOStreamBufferIcEERNSt3__16vectorIcNS5_9allocatorIcEEEEPS1_:
  278|      8|bool PLY::Element::ParseElement(IOStreamBuffer<char> &streamBuffer, std::vector<char> &buffer, PLY::Element *pOut) {
  279|      8|    ai_assert(nullptr != pOut);
  280|       |    // Example format: "element vertex 8"
  281|       |
  282|       |    // skip leading spaces
  283|      8|    if (!PLY::DOM::SkipSpaces(buffer)) {
  ------------------
  |  Branch (283:9): [True: 0, False: 8]
  ------------------
  284|      0|        return false;
  285|      0|    }
  286|       |
  287|       |    // skip the "element" string at the beginning
  288|      8|    if (!PLY::DOM::TokenMatch(buffer, "element", 7) && !PLY::DOM::TokenMatch(buffer, "comment", 7)) {
  ------------------
  |  Branch (288:9): [True: 3, False: 5]
  |  Branch (288:56): [True: 3, False: 0]
  ------------------
  289|       |        // seems not to be a valid property entry
  290|      3|        return false;
  291|      3|    }
  292|       |    // get next word
  293|      5|    if (!PLY::DOM::SkipSpaces(buffer))
  ------------------
  |  Branch (293:9): [True: 0, False: 5]
  ------------------
  294|      0|        return false;
  295|       |
  296|       |    // parse the semantic of the element
  297|      5|    pOut->eSemantic = PLY::Element::ParseSemantic(buffer);
  298|      5|    if (PLY::EEST_INVALID == pOut->eSemantic) {
  ------------------
  |  Branch (298:9): [True: 0, False: 5]
  ------------------
  299|       |        // if the exact semantic can't be determined, just store
  300|       |        // the original string identifier
  301|      0|        pOut->szName = std::string(&buffer[0], &buffer[0] + strlen(&buffer[0]));
  302|      0|        auto pos = pOut->szName.find_last_of(' ');
  303|      0|        if (pos != std::string::npos) {
  ------------------
  |  Branch (303:13): [True: 0, False: 0]
  ------------------
  304|      0|            pOut->szName.erase(pos, pOut->szName.size());
  305|      0|        }
  306|      0|    }
  307|       |
  308|      5|    if (!PLY::DOM::SkipSpaces(buffer))
  ------------------
  |  Branch (308:9): [True: 0, False: 5]
  ------------------
  309|      0|        return false;
  310|       |
  311|      5|    if (PLY::EEST_TextureFile == pOut->eSemantic) {
  ------------------
  |  Branch (311:9): [True: 0, False: 5]
  ------------------
  312|      0|        char *endPos = &buffer[0] + (strlen(&buffer[0]) - 1);
  313|      0|        pOut->szName = std::string(&buffer[0], endPos);
  314|       |
  315|       |        // go to the next line
  316|      0|        PLY::DOM::SkipSpacesAndLineEnd(buffer);
  317|       |
  318|      0|        return true;
  319|      0|    }
  320|       |
  321|       |    // parse the number of occurrences of this element
  322|      5|    const char *pCur = (char *)&buffer[0];
  323|      5|    pOut->NumOccur = strtoul10(pCur, &pCur);
  324|       |
  325|       |    // go to the next line
  326|      5|    PLY::DOM::SkipSpacesAndLineEnd(buffer);
  327|       |
  328|       |    // now parse all properties of the element
  329|     20|    while (true) {
  ------------------
  |  Branch (329:12): [True: 20, Folded]
  ------------------
  330|     20|        streamBuffer.getNextLine(buffer);
  331|     20|        pCur = (char *)&buffer[0];
  332|       |
  333|       |        // skip all comments and go to next line
  334|     20|        if (PLY::DOM::SkipComments(buffer)) continue;
  ------------------
  |  Branch (334:13): [True: 0, False: 20]
  ------------------
  335|       |
  336|     20|        PLY::Property prop;
  337|     20|        if (!PLY::Property::ParseProperty(buffer, &prop))
  ------------------
  |  Branch (337:13): [True: 5, False: 15]
  ------------------
  338|      5|            break;
  339|       |
  340|     15|        pOut->alProperties.push_back(prop);
  341|     15|    }
  342|       |
  343|      5|    return true;
  344|      5|}
_ZN6Assimp3PLY3DOM10SkipSpacesERNSt3__16vectorIcNS2_9allocatorIcEEEE:
  347|     98|bool PLY::DOM::SkipSpaces(std::vector<char> &buffer) {
  348|     98|    const char *pCur = buffer.empty() ? nullptr : (char *)&buffer[0];
  ------------------
  |  Branch (348:24): [True: 0, False: 98]
  ------------------
  349|     98|    const char *end = pCur + buffer.size();
  350|     98|    bool ret = false;
  351|     98|    if (pCur) {
  ------------------
  |  Branch (351:9): [True: 98, False: 0]
  ------------------
  352|     98|        const char *szCur = pCur;
  353|     98|        ret = Assimp::SkipSpaces(pCur, &pCur, end);
  354|       |
  355|     98|        uintptr_t iDiff = (uintptr_t)pCur - (uintptr_t)szCur;
  356|     98|        buffer.erase(buffer.begin(), buffer.begin() + iDiff);
  357|     98|        return ret;
  358|     98|    }
  359|       |
  360|      0|    return ret;
  361|     98|}
_ZN6Assimp3PLY3DOM8SkipLineERNSt3__16vectorIcNS2_9allocatorIcEEEE:
  364|      1|bool PLY::DOM::SkipLine(std::vector<char> &buffer) {
  365|      1|    const char *pCur = buffer.empty() ? nullptr : (char *)&buffer[0];
  ------------------
  |  Branch (365:24): [True: 0, False: 1]
  ------------------
  366|      1|    const char *end = pCur + buffer.size();
  367|      1|    bool ret = false;
  368|      1|    if (pCur) {
  ------------------
  |  Branch (368:9): [True: 1, False: 0]
  ------------------
  369|      1|        const char *szCur = pCur;
  370|      1|        ret = Assimp::SkipLine(pCur, &pCur, end);
  371|       |
  372|      1|        uintptr_t iDiff = (uintptr_t)pCur - (uintptr_t)szCur;
  373|      1|        buffer.erase(buffer.begin(), buffer.begin() + iDiff);
  374|      1|        return ret;
  375|      1|    }
  376|       |
  377|      0|    return ret;
  378|      1|}
_ZN6Assimp3PLY3DOM10TokenMatchERNSt3__16vectorIcNS2_9allocatorIcEEEEPKcj:
  381|    781|bool PLY::DOM::TokenMatch(std::vector<char> &buffer, const char *token, unsigned int len) {
  382|    781|    const char *pCur = buffer.empty() ? nullptr : (char *)&buffer[0];
  ------------------
  |  Branch (382:24): [True: 0, False: 781]
  ------------------
  383|    781|    bool ret = false;
  384|    781|    if (pCur) {
  ------------------
  |  Branch (384:9): [True: 781, False: 0]
  ------------------
  385|    781|        const char *szCur = pCur;
  386|    781|        ret = Assimp::TokenMatch(pCur, token, len);
  387|       |
  388|    781|        uintptr_t iDiff = (uintptr_t)pCur - (uintptr_t)szCur;
  389|    781|        buffer.erase(buffer.begin(), buffer.begin() + iDiff);
  390|    781|        return ret;
  391|    781|    }
  392|       |
  393|      0|    return ret;
  394|    781|}
_ZN6Assimp3PLY3DOM20SkipSpacesAndLineEndERNSt3__16vectorIcNS2_9allocatorIcEEEE:
  397|     22|bool PLY::DOM::SkipSpacesAndLineEnd(std::vector<char> &buffer) {
  398|     22|    const char *pCur = buffer.empty() ? nullptr : (char *)&buffer[0];
  ------------------
  |  Branch (398:24): [True: 0, False: 22]
  ------------------
  399|     22|    const char *end = pCur + buffer.size();
  400|     22|    bool ret = false;
  401|     22|    if (pCur) {
  ------------------
  |  Branch (401:9): [True: 22, False: 0]
  ------------------
  402|     22|        const char *szCur = pCur;
  403|     22|        ret = Assimp::SkipSpacesAndLineEnd(pCur, &pCur, end);
  404|       |
  405|     22|        uintptr_t iDiff = (uintptr_t)pCur - (uintptr_t)szCur;
  406|     22|        buffer.erase(buffer.begin(), buffer.begin() + iDiff);
  407|     22|        return ret;
  408|     22|    }
  409|       |
  410|      0|    return ret;
  411|     22|}
_ZN6Assimp3PLY3DOM12SkipCommentsENSt3__16vectorIcNS2_9allocatorIcEEEE:
  414|     28|bool PLY::DOM::SkipComments(std::vector<char> buffer) {
  415|     28|    ai_assert(!buffer.empty());
  416|       |
  417|     28|    std::vector<char> nbuffer = std::move(buffer);
  418|       |    // skip spaces
  419|     28|    if (!SkipSpaces(nbuffer)) {
  ------------------
  |  Branch (419:9): [True: 0, False: 28]
  ------------------
  420|      0|        return false;
  421|      0|    }
  422|       |
  423|     28|    if (TokenMatch(nbuffer, "comment", 7)) {
  ------------------
  |  Branch (423:9): [True: 0, False: 28]
  ------------------
  424|      0|        if (!SkipSpaces(nbuffer))
  ------------------
  |  Branch (424:13): [True: 0, False: 0]
  ------------------
  425|      0|            SkipLine(nbuffer);
  426|       |
  427|      0|        if (!TokenMatch(nbuffer, "TextureFile", 11)) {
  ------------------
  |  Branch (427:13): [True: 0, False: 0]
  ------------------
  428|      0|            SkipLine(nbuffer);
  429|      0|            buffer = nbuffer;
  430|      0|            return true;
  431|      0|        }
  432|       |
  433|      0|        return true;
  434|      0|    }
  435|       |
  436|     28|    return false;
  437|     28|}
_ZN6Assimp3PLY3DOM11ParseHeaderERNS_14IOStreamBufferIcEERNSt3__16vectorIcNS5_9allocatorIcEEEEb:
  440|      3|bool PLY::DOM::ParseHeader(IOStreamBuffer<char> &streamBuffer, std::vector<char> &buffer, bool isBinary) {
  441|      3|    ASSIMP_LOG_VERBOSE_DEBUG("PLY::DOM::ParseHeader() begin");
  442|       |
  443|      3|    std::unordered_set<std::string> definedAlElements;
  444|       |    // parse all elements
  445|      8|    while (!buffer.empty()) {
  ------------------
  |  Branch (445:12): [True: 8, False: 0]
  ------------------
  446|       |        // skip all comments
  447|      8|        PLY::DOM::SkipComments(buffer);
  448|       |
  449|      8|        PLY::Element out;
  450|      8|        if (PLY::Element::ParseElement(streamBuffer, buffer, &out)) {
  ------------------
  |  Branch (450:13): [True: 5, False: 3]
  ------------------
  451|       |            // add the element to the list of elements
  452|       |
  453|      5|            const auto propertyName = (out.szName.empty()) ? to_string(out.eSemantic) : out.szName;
  ------------------
  |  Branch (453:39): [True: 5, False: 0]
  ------------------
  454|      5|            auto alreadyDefined = definedAlElements.find(propertyName);
  455|      5|            if (alreadyDefined != definedAlElements.end()) {
  ------------------
  |  Branch (455:17): [True: 1, False: 4]
  ------------------
  456|      1|                throw DeadlyImportError("Property '" + propertyName + "' in header already defined ");
  457|      1|            }
  458|      4|            definedAlElements.insert(propertyName);
  459|      4|            alElements.push_back(out);
  460|      4|        } else if (TokenMatch(buffer, "end_header", 10)) {
  ------------------
  |  Branch (460:20): [True: 2, False: 1]
  ------------------
  461|       |            // we have reached the end of the header
  462|      2|            break;
  463|      2|        } else {
  464|       |            // ignore unknown header elements
  465|      1|            if (!streamBuffer.getNextLine(buffer))
  ------------------
  |  Branch (465:17): [True: 0, False: 1]
  ------------------
  466|      0|                return false;
  467|      1|        }
  468|      8|    }
  469|       |
  470|      2|    if (!isBinary) // it would occur an error, if binary data start with values as space or line end.
  ------------------
  |  Branch (470:9): [True: 2, False: 0]
  ------------------
  471|      2|        SkipSpacesAndLineEnd(buffer);
  472|       |
  473|       |    ASSIMP_LOG_VERBOSE_DEBUG("PLY::DOM::ParseHeader() succeeded");
  474|      2|    return true;
  475|      3|}
_ZN6Assimp3PLY3DOM25ParseElementInstanceListsERNS_14IOStreamBufferIcEERNSt3__16vectorIcNS5_9allocatorIcEEEEPNS_11PLYImporterE:
  478|      2|bool PLY::DOM::ParseElementInstanceLists(IOStreamBuffer<char> &streamBuffer, std::vector<char> &buffer, PLYImporter *loader) {
  479|      2|    ASSIMP_LOG_VERBOSE_DEBUG("PLY::DOM::ParseElementInstanceLists() begin");
  480|      2|    alElementData.resize(alElements.size());
  481|       |
  482|      2|    std::vector<PLY::Element>::const_iterator i = alElements.begin();
  483|      2|    std::vector<PLY::ElementInstanceList>::iterator a = alElementData.begin();
  484|       |
  485|       |    // parse all element instances
  486|       |    // construct vertices and faces
  487|      5|    for (; i != alElements.end(); ++i, ++a) {
  ------------------
  |  Branch (487:12): [True: 3, False: 2]
  ------------------
  488|      3|        if ((*i).eSemantic == EEST_Vertex || (*i).eSemantic == EEST_Face || (*i).eSemantic == EEST_TriStrip) {
  ------------------
  |  Branch (488:13): [True: 2, False: 1]
  |  Branch (488:46): [True: 1, False: 0]
  |  Branch (488:77): [True: 0, False: 0]
  ------------------
  489|      3|            PLY::ElementInstanceList::ParseInstanceList(streamBuffer, buffer, &(*i), nullptr, loader);
  490|      3|        } else {
  491|      0|            (*a).alInstances.resize((*i).NumOccur);
  492|      0|            PLY::ElementInstanceList::ParseInstanceList(streamBuffer, buffer, &(*i), &(*a), nullptr);
  493|      0|        }
  494|      3|    }
  495|       |
  496|       |    ASSIMP_LOG_VERBOSE_DEBUG("PLY::DOM::ParseElementInstanceLists() succeeded");
  497|      2|    return true;
  498|      2|}
_ZN6Assimp3PLY3DOM13ParseInstanceERNS_14IOStreamBufferIcEEPS1_PNS_11PLYImporterE:
  554|      3|bool PLY::DOM::ParseInstance(IOStreamBuffer<char> &streamBuffer, DOM *p_pcOut, PLYImporter *loader) {
  555|      3|    ai_assert(nullptr != p_pcOut);
  556|      3|    ai_assert(nullptr != loader);
  557|       |
  558|      3|    std::vector<char> buffer;
  559|      3|    streamBuffer.getNextLine(buffer);
  560|       |
  561|      3|    ASSIMP_LOG_VERBOSE_DEBUG("PLY::DOM::ParseInstance() begin");
  562|       |
  563|      3|    if (!p_pcOut->ParseHeader(streamBuffer, buffer, false)) {
  ------------------
  |  Branch (563:9): [True: 0, False: 3]
  ------------------
  564|      0|        ASSIMP_LOG_VERBOSE_DEBUG("PLY::DOM::ParseInstance() failure");
  565|      0|        return false;
  566|      0|    }
  567|       |
  568|       |    // get next line after header
  569|      3|    streamBuffer.getNextLine(buffer);
  570|      3|    if (!p_pcOut->ParseElementInstanceLists(streamBuffer, buffer, loader)) {
  ------------------
  |  Branch (570:9): [True: 0, False: 3]
  ------------------
  571|      0|        ASSIMP_LOG_VERBOSE_DEBUG("PLY::DOM::ParseInstance() failure");
  572|      0|        return false;
  573|      0|    }
  574|      3|    ASSIMP_LOG_VERBOSE_DEBUG("PLY::DOM::ParseInstance() succeeded");
  575|      3|    return true;
  576|      3|}
_ZN6Assimp3PLY19ElementInstanceList17ParseInstanceListERNS_14IOStreamBufferIcEERNSt3__16vectorIcNS5_9allocatorIcEEEEPKNS0_7ElementEPS1_PNS_11PLYImporterE:
  584|      3|        PLYImporter *loader) {
  585|      3|    ai_assert(nullptr != pcElement);
  586|       |
  587|       |    // parse all elements
  588|      3|    if (EEST_INVALID == pcElement->eSemantic || pcElement->alProperties.empty()) {
  ------------------
  |  Branch (588:9): [True: 0, False: 3]
  |  Branch (588:49): [True: 0, False: 3]
  ------------------
  589|       |        // if the element has an unknown semantic we can skip all lines
  590|       |        // However, there could be comments
  591|      0|        for (unsigned int i = 0; i < pcElement->NumOccur; ++i) {
  ------------------
  |  Branch (591:34): [True: 0, False: 0]
  ------------------
  592|      0|            PLY::DOM::SkipComments(buffer);
  593|      0|            PLY::DOM::SkipLine(buffer);
  594|      0|            streamBuffer.getNextLine(buffer);
  595|      0|        }
  596|      3|    } else {
  597|      3|        const char *pCur = (const char *)&buffer[0];
  598|      3|        const char *end = pCur + buffer.size();
  599|       |        // be sure to have enough storage
  600|  15.1k|        for (unsigned int i = 0; i < pcElement->NumOccur; ++i) {
  ------------------
  |  Branch (600:34): [True: 15.1k, False: 3]
  ------------------
  601|  15.1k|            if (p_pcOut)
  ------------------
  |  Branch (601:17): [True: 0, False: 15.1k]
  ------------------
  602|      0|                PLY::ElementInstance::ParseInstance(pCur, end, pcElement, &p_pcOut->alInstances[i]);
  603|  15.1k|            else {
  604|  15.1k|                ElementInstance elt;
  605|  15.1k|                PLY::ElementInstance::ParseInstance(pCur, end, pcElement, &elt);
  606|       |
  607|       |                // Create vertex or face
  608|  15.1k|                if (pcElement->eSemantic == EEST_Vertex) {
  ------------------
  |  Branch (608:21): [True: 11.4k, False: 3.73k]
  ------------------
  609|       |                    // call loader instance from here
  610|  11.4k|                    loader->LoadVertex(pcElement, &elt, i);
  611|  11.4k|                } else if (pcElement->eSemantic == EEST_Face) {
  ------------------
  |  Branch (611:28): [True: 3.73k, False: 0]
  ------------------
  612|       |                    // call loader instance from here
  613|  3.73k|                    loader->LoadFace(pcElement, &elt, i);
  614|  3.73k|                } else if (pcElement->eSemantic == EEST_TriStrip) {
  ------------------
  |  Branch (614:28): [True: 0, False: 0]
  ------------------
  615|       |                    // call loader instance from here
  616|      0|                    loader->LoadFace(pcElement, &elt, i);
  617|      0|                }
  618|  15.1k|            }
  619|       |
  620|  15.1k|            streamBuffer.getNextLine(buffer);
  621|  15.1k|            pCur = (buffer.empty()) ? nullptr : (const char *)&buffer[0];
  ------------------
  |  Branch (621:20): [True: 0, False: 15.1k]
  ------------------
  622|  15.1k|        }
  623|      3|    }
  624|      3|    return true;
  625|      3|}
_ZN6Assimp3PLY15ElementInstance13ParseInstanceERPKcS3_PKNS0_7ElementEPS1_:
  669|  15.1k|        PLY::ElementInstance *p_pcOut) {
  670|  15.1k|    ai_assert(nullptr != pcElement);
  671|  15.1k|    ai_assert(nullptr != p_pcOut);
  672|       |
  673|       |    // allocate enough storage
  674|  15.1k|    p_pcOut->alProperties.resize(pcElement->alProperties.size());
  675|       |
  676|  15.1k|    std::vector<PLY::PropertyInstance>::iterator i = p_pcOut->alProperties.begin();
  677|  15.1k|    std::vector<PLY::Property>::const_iterator a = pcElement->alProperties.begin();
  678|   108k|    for (; i != p_pcOut->alProperties.end(); ++i, ++a) {
  ------------------
  |  Branch (678:12): [True: 93.4k, False: 15.1k]
  ------------------
  679|  93.4k|        if (!(PLY::PropertyInstance::ParseInstance(pCur, end, &(*a), &(*i)))) {
  ------------------
  |  Branch (679:13): [True: 92, False: 93.3k]
  ------------------
  680|     92|            ASSIMP_LOG_WARN("Unable to parse property instance. "
  681|     92|                            "Skipping this element instance");
  682|       |
  683|     92|            PLY::PropertyInstance::ValueUnion v = PLY::PropertyInstance::DefaultValue((*a).eType);
  684|     92|            (*i).avList.push_back(v);
  685|     92|        }
  686|  93.4k|    }
  687|  15.1k|    return true;
  688|  15.1k|}
_ZN6Assimp3PLY16PropertyInstance13ParseInstanceERPKcS3_PKNS0_8PropertyEPS1_:
  720|  93.4k|        PLY::PropertyInstance *p_pcOut) {
  721|  93.4k|    ai_assert(nullptr != prop);
  722|  93.4k|    ai_assert(nullptr != p_pcOut);
  723|       |
  724|       |    // skip spaces at the beginning
  725|  93.4k|    if (!SkipSpaces(&pCur, end)) {
  ------------------
  |  Branch (725:9): [True: 66, False: 93.3k]
  ------------------
  726|     66|        return false;
  727|     66|    }
  728|       |
  729|  93.3k|    if (prop->bIsList) {
  ------------------
  |  Branch (729:9): [True: 3.92k, False: 89.4k]
  ------------------
  730|       |        // parse the number of elements in the list
  731|  3.92k|        PLY::PropertyInstance::ValueUnion v;
  732|  3.92k|        PLY::PropertyInstance::ParseValue(pCur, prop->eFirstType, &v);
  733|       |
  734|       |        // convert to unsigned int
  735|  3.92k|        unsigned int iNum = PLY::PropertyInstance::ConvertTo<unsigned int>(v, prop->eFirstType);
  736|       |
  737|       |        // parse all list elements
  738|  3.92k|        p_pcOut->avList.resize(iNum);
  739|  15.4k|        for (unsigned int i = 0; i < iNum; ++i) {
  ------------------
  |  Branch (739:34): [True: 11.5k, False: 3.89k]
  ------------------
  740|  11.5k|            if (!SkipSpaces(&pCur, end))
  ------------------
  |  Branch (740:17): [True: 26, False: 11.5k]
  ------------------
  741|     26|                return false;
  742|       |
  743|  11.5k|            PLY::PropertyInstance::ParseValue(pCur, prop->eType, &p_pcOut->avList[i]);
  744|  11.5k|        }
  745|  89.4k|    } else {
  746|       |        // parse the property
  747|  89.4k|        PLY::PropertyInstance::ValueUnion v;
  748|       |
  749|  89.4k|        PLY::PropertyInstance::ParseValue(pCur, prop->eType, &v);
  750|  89.4k|        p_pcOut->avList.push_back(v);
  751|  89.4k|    }
  752|  93.3k|    SkipSpacesAndLineEnd(&pCur, end);
  753|  93.3k|    return true;
  754|  93.3k|}
_ZN6Assimp3PLY16PropertyInstance12DefaultValueENS0_9EDataTypeE:
  790|     92|PLY::PropertyInstance::ValueUnion PLY::PropertyInstance::DefaultValue(PLY::EDataType eType) {
  791|     92|    PLY::PropertyInstance::ValueUnion out;
  792|       |
  793|     92|    switch (eType) {
  794|      0|    case EDT_Float:
  ------------------
  |  Branch (794:5): [True: 0, False: 92]
  ------------------
  795|      0|        out.fFloat = 0.f;
  796|      0|        return out;
  797|       |
  798|      0|    case EDT_Double:
  ------------------
  |  Branch (798:5): [True: 0, False: 92]
  ------------------
  799|      0|        out.fDouble = 0.;
  800|      0|        return out;
  801|       |
  802|     92|    default:;
  ------------------
  |  Branch (802:5): [True: 92, False: 0]
  ------------------
  803|     92|    };
  804|     92|    out.iUInt = 0;
  805|     92|    return out;
  806|     92|}
_ZN6Assimp3PLY16PropertyInstance10ParseValueERPKcNS0_9EDataTypeEPNS1_10ValueUnionE:
  811|   104k|        PLY::PropertyInstance::ValueUnion *out) {
  812|   104k|    ai_assert(nullptr != pCur);
  813|   104k|    ai_assert(nullptr != out);
  814|       |
  815|       |    // calc element size
  816|   104k|    bool ret = true;
  817|   104k|    switch (eType) {
  818|  11.3k|    case EDT_UInt:
  ------------------
  |  Branch (818:5): [True: 11.3k, False: 93.5k]
  ------------------
  819|  11.3k|    case EDT_UShort:
  ------------------
  |  Branch (819:5): [True: 0, False: 104k]
  ------------------
  820|  15.1k|    case EDT_UChar:
  ------------------
  |  Branch (820:5): [True: 3.73k, False: 101k]
  ------------------
  821|       |
  822|  15.1k|        out->iUInt = (uint32_t)strtoul10(pCur, &pCur);
  823|  15.1k|        break;
  824|       |
  825|    316|    case EDT_Int:
  ------------------
  |  Branch (825:5): [True: 316, False: 104k]
  ------------------
  826|    316|    case EDT_Short:
  ------------------
  |  Branch (826:5): [True: 0, False: 104k]
  ------------------
  827|    316|    case EDT_Char:
  ------------------
  |  Branch (827:5): [True: 0, False: 104k]
  ------------------
  828|       |
  829|    316|        out->iInt = (int32_t)strtol10(pCur, &pCur);
  830|    316|        break;
  831|       |
  832|  89.4k|    case EDT_Float:
  ------------------
  |  Branch (832:5): [True: 89.4k, False: 15.4k]
  ------------------
  833|       |        // technically this should cast to float, but people tend to use float descriptors for double data
  834|       |        // this is the best way to not risk losing precision on import and it doesn't hurt to do this
  835|  89.4k|        ai_real f;
  836|  89.4k|        pCur = fast_atoreal_move(pCur, f);
  837|  89.4k|        out->fFloat = (ai_real)f;
  838|  89.4k|        break;
  839|       |
  840|      0|    case EDT_Double:
  ------------------
  |  Branch (840:5): [True: 0, False: 104k]
  ------------------
  841|      0|        double d;
  842|      0|        pCur = fast_atoreal_move(pCur, d);
  843|      0|        out->fDouble = d;
  844|      0|        break;
  845|       |
  846|      0|    case EDT_INVALID:
  ------------------
  |  Branch (846:5): [True: 0, False: 104k]
  ------------------
  847|      0|    default:
  ------------------
  |  Branch (847:5): [True: 0, False: 104k]
  ------------------
  848|      0|        ret = false;
  849|      0|        break;
  850|   104k|    }
  851|       |
  852|   104k|    return ret;
  853|   104k|}
PlyParser.cpp:_ZN6AssimpL9to_stringENS_3PLY16EElementSemanticE:
   56|      5|static std::string to_string(EElementSemantic e) {
   57|      5|    switch (e) {
   58|      4|        case EEST_Vertex:
  ------------------
  |  Branch (58:9): [True: 4, False: 1]
  ------------------
   59|      4|            return std::string{ "vertex" };
   60|      0|        case EEST_TriStrip:
  ------------------
  |  Branch (60:9): [True: 0, False: 5]
  ------------------
   61|      0|            return std::string{ "tristrips" };
   62|      0|        case EEST_Edge:
  ------------------
  |  Branch (62:9): [True: 0, False: 5]
  ------------------
   63|      0|            return std::string{ "edge" };
   64|      0|        case EEST_Material:
  ------------------
  |  Branch (64:9): [True: 0, False: 5]
  ------------------
   65|      0|            return std::string{ "material" };
   66|      0|        case EEST_TextureFile:
  ------------------
  |  Branch (66:9): [True: 0, False: 5]
  ------------------
   67|      0|            return std::string{ "TextureFile" };
   68|      1|        default:
  ------------------
  |  Branch (68:9): [True: 1, False: 4]
  ------------------
   69|      1|            return std::string{ "invalid" };
   70|      5|    }
   71|      5|}

_ZN6Assimp3PLY8PropertyC2Ev:
  212|     20|    : eType (EDT_Int)
  213|       |    , Semantic()
  214|     20|    , bIsList(false)
  215|     20|    , eFirstType(EDT_UChar) {
  216|       |        // empty
  217|     20|    }
_ZN6Assimp3PLY7ElementC2Ev:
  260|      8|    : eSemantic (EEST_INVALID)
  261|      8|    , NumOccur(0) {
  262|       |        // empty
  263|      8|    }
_ZN6Assimp3PLY3DOMC2Ev:
  403|      3|    DOM() AI_NO_EXCEPT = default;
_ZN6Assimp3PLY16PropertyInstance9ConvertToIfEET_NS1_10ValueUnionENS0_9EDataTypeE:
  444|  89.4k|inline TYPE PLY::PropertyInstance::ConvertTo(PLY::PropertyInstance::ValueUnion v, PLY::EDataType eType) {
  445|  89.4k|    switch (eType) {
  446|  89.4k|    case EDT_Float:
  ------------------
  |  Branch (446:5): [True: 89.4k, False: 0]
  ------------------
  447|  89.4k|        return (TYPE)v.fFloat;
  448|      0|    case EDT_Double:
  ------------------
  |  Branch (448:5): [True: 0, False: 89.4k]
  ------------------
  449|      0|        return (TYPE)v.fDouble;
  450|       |
  451|      0|    case EDT_UInt:
  ------------------
  |  Branch (451:5): [True: 0, False: 89.4k]
  ------------------
  452|      0|    case EDT_UShort:
  ------------------
  |  Branch (452:5): [True: 0, False: 89.4k]
  ------------------
  453|      0|    case EDT_UChar:
  ------------------
  |  Branch (453:5): [True: 0, False: 89.4k]
  ------------------
  454|      0|        return (TYPE)v.iUInt;
  455|       |
  456|      0|    case EDT_Int:
  ------------------
  |  Branch (456:5): [True: 0, False: 89.4k]
  ------------------
  457|      0|    case EDT_Short:
  ------------------
  |  Branch (457:5): [True: 0, False: 89.4k]
  ------------------
  458|      0|    case EDT_Char:
  ------------------
  |  Branch (458:5): [True: 0, False: 89.4k]
  ------------------
  459|      0|        return (TYPE)v.iInt;
  460|      0|    default: ;
  ------------------
  |  Branch (460:5): [True: 0, False: 89.4k]
  ------------------
  461|  89.4k|    };
  462|      0|    return (TYPE)0;
  463|  89.4k|}
_ZN6Assimp3PLY16PropertyInstance9ConvertToIjEET_NS1_10ValueUnionENS0_9EDataTypeE:
  444|  15.1k|inline TYPE PLY::PropertyInstance::ConvertTo(PLY::PropertyInstance::ValueUnion v, PLY::EDataType eType) {
  445|  15.1k|    switch (eType) {
  446|      0|    case EDT_Float:
  ------------------
  |  Branch (446:5): [True: 0, False: 15.1k]
  ------------------
  447|      0|        return (TYPE)v.fFloat;
  448|      0|    case EDT_Double:
  ------------------
  |  Branch (448:5): [True: 0, False: 15.1k]
  ------------------
  449|      0|        return (TYPE)v.fDouble;
  450|       |
  451|  11.3k|    case EDT_UInt:
  ------------------
  |  Branch (451:5): [True: 11.3k, False: 3.73k]
  ------------------
  452|  11.3k|    case EDT_UShort:
  ------------------
  |  Branch (452:5): [True: 0, False: 15.1k]
  ------------------
  453|  15.1k|    case EDT_UChar:
  ------------------
  |  Branch (453:5): [True: 3.73k, False: 11.3k]
  ------------------
  454|  15.1k|        return (TYPE)v.iUInt;
  455|       |
  456|      0|    case EDT_Int:
  ------------------
  |  Branch (456:5): [True: 0, False: 15.1k]
  ------------------
  457|      0|    case EDT_Short:
  ------------------
  |  Branch (457:5): [True: 0, False: 15.1k]
  ------------------
  458|      0|    case EDT_Char:
  ------------------
  |  Branch (458:5): [True: 0, False: 15.1k]
  ------------------
  459|      0|        return (TYPE)v.iInt;
  460|      0|    default: ;
  ------------------
  |  Branch (460:5): [True: 0, False: 15.1k]
  ------------------
  461|  15.1k|    };
  462|      0|    return (TYPE)0;
  463|  15.1k|}
_ZN6Assimp3PLY15ElementInstanceC2Ev:
  359|  15.1k|    ElementInstance() AI_NO_EXCEPT = default;
_ZN6Assimp3PLY19ElementInstanceListC2Ev:
  381|      3|    ElementInstanceList() AI_NO_EXCEPT = default;
_ZN6Assimp3PLY16PropertyInstanceC2Ev:
  297|  93.4k|    PropertyInstance() AI_NO_EXCEPT = default;

_ZN6Assimp17Q3BSPFileImporterC2Ev:
  137|    624|        m_pCurrentMesh(nullptr), m_pCurrentFace(nullptr) {
  138|       |    // empty
  139|    624|}
_ZN6Assimp17Q3BSPFileImporterD2Ev:
  143|    624|Q3BSPFileImporter::~Q3BSPFileImporter() {
  144|    624|    clear();
  145|    624|}
_ZN6Assimp17Q3BSPFileImporter5clearEv:
  148|    624|void Q3BSPFileImporter::clear() {
  149|    624|    for (FaceMap::iterator it = m_MaterialLookupMap.begin(); it != m_MaterialLookupMap.end(); ++it) {
  ------------------
  |  Branch (149:62): [True: 0, False: 624]
  ------------------
  150|      0|        const std::string &matName = it->first;
  151|      0|        if (!matName.empty()) {
  ------------------
  |  Branch (151:13): [True: 0, False: 0]
  ------------------
  152|      0|            delete it->second;
  153|      0|        }
  154|      0|    }
  155|    624|}
_ZNK6Assimp17Q3BSPFileImporter7CanReadERKNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEPNS_8IOSystemEb:
  159|     57|bool Q3BSPFileImporter::CanRead(const std::string &filename, IOSystem * /*pIOHandler*/, bool checkSig) const {
  160|     57|    if (!checkSig) {
  ------------------
  |  Branch (160:9): [True: 0, False: 57]
  ------------------
  161|      0|        return SimpleExtensionCheck(filename, "pk3", "bsp");
  162|      0|    }
  163|     57|    return false;
  164|     57|}
_ZNK6Assimp17Q3BSPFileImporter7GetInfoEv:
  168|    634|const aiImporterDesc *Q3BSPFileImporter::GetInfo() const {
  169|    634|    return &desc;
  170|    634|}

_ZN6Assimp11Q3DImporterC2Ev:
   77|    624|Q3DImporter::Q3DImporter() = default;
_ZN6Assimp11Q3DImporterD2Ev:
   81|    624|Q3DImporter::~Q3DImporter() = default;
_ZNK6Assimp11Q3DImporter7CanReadERKNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEPNS_8IOSystemEb:
   85|    329|bool Q3DImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool /*checkSig*/) const {
   86|    329|    static const char *tokens[] = { "quick3Do", "quick3Ds" };
   87|       |    return SearchFileHeaderForToken(pIOHandler, pFile, tokens, AI_COUNT_OF(tokens));
   88|    329|}
_ZNK6Assimp11Q3DImporter7GetInfoEv:
   91|    643|const aiImporterDesc *Q3DImporter::GetInfo() const {
   92|    643|    return &desc;
   93|    643|}
_ZN6Assimp11Q3DImporter14InternReadFileERKNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEP7aiScenePNS_8IOSystemE:
   98|      9|        aiScene *pScene, IOSystem *pIOHandler) {
   99|       |
  100|      9|    auto file = pIOHandler->Open(pFile, "rb");
  101|      9|    if (!file)
  ------------------
  |  Branch (101:9): [True: 0, False: 9]
  ------------------
  102|      0|        throw DeadlyImportError("Quick3D: Could not open ", pFile);
  103|       |
  104|      9|    StreamReaderLE stream(file);
  105|       |
  106|       |    // The header is 22 bytes large
  107|      9|    if (stream.GetRemainingSize() < 22)
  ------------------
  |  Branch (107:9): [True: 0, False: 9]
  ------------------
  108|      0|        throw DeadlyImportError("File is either empty or corrupt: ", pFile);
  109|       |
  110|       |    // Check the file's signature
  111|      9|    if (ASSIMP_strincmp((const char *)stream.GetPtr(), "quick3Do", 8) &&
  ------------------
  |  Branch (111:9): [True: 3, False: 6]
  ------------------
  112|      3|            ASSIMP_strincmp((const char *)stream.GetPtr(), "quick3Ds", 8)) {
  ------------------
  |  Branch (112:13): [True: 0, False: 3]
  ------------------
  113|      0|        throw DeadlyImportError("Not a Quick3D file. Signature string is: ", ai_str_toprintable((const char *)stream.GetPtr(), 8));
  114|      0|    }
  115|       |
  116|       |    // Print the file format version
  117|      9|    ASSIMP_LOG_INFO("Quick3D File format version: ",
  118|      9|            std::string(&((const char *)stream.GetPtr())[8], 2));
  119|       |
  120|       |    // ... an store it
  121|      9|    char major = ((const char *)stream.GetPtr())[8];
  122|      9|    char minor = ((const char *)stream.GetPtr())[9];
  123|       |
  124|      9|    stream.IncPtr(10);
  125|      9|    unsigned int numMeshes = (unsigned int)stream.GetI4();
  126|      9|    unsigned int numMats = (unsigned int)stream.GetI4();
  127|      9|    unsigned int numTextures = (unsigned int)stream.GetI4();
  128|       |
  129|      9|    std::vector<Material> materials;
  130|      9|    try {
  131|      9|        materials.reserve(numMats);
  132|      9|    } catch (const std::bad_alloc &) {
  133|      0|        ASSIMP_LOG_ERROR("Invalid alloc for materials.");
  134|      0|        throw DeadlyImportError("Invalid Quick3D-file, material allocation failed.");
  135|      0|    }
  136|       |
  137|      9|    std::vector<Mesh> meshes;
  138|      9|    try {
  139|      9|        meshes.reserve(numMeshes);
  140|      9|    } catch (const std::bad_alloc &) {
  141|      0|        ASSIMP_LOG_ERROR("Invalid alloc for meshes.");
  142|      0|        throw DeadlyImportError("Invalid Quick3D-file, mesh allocation failed.");
  143|      0|    }
  144|       |
  145|       |    // Allocate the scene root node
  146|      9|    pScene->mRootNode = new aiNode();
  147|       |
  148|      9|    aiColor3D fgColor(0.6f, 0.6f, 0.6f);
  149|       |
  150|       |    // Now read all file chunks
  151|     19|    while (true) {
  ------------------
  |  Branch (151:12): [True: 19, Folded]
  ------------------
  152|     19|        if (stream.GetRemainingSize() < 1) break;
  ------------------
  |  Branch (152:13): [True: 4, False: 15]
  ------------------
  153|     15|        char c = stream.GetI1();
  154|     15|        switch (c) {
  155|       |            // Meshes chunk
  156|      6|        case 'm': {
  ------------------
  |  Branch (156:9): [True: 6, False: 9]
  ------------------
  157|     39|            for (unsigned int quak = 0; quak < numMeshes; ++quak) {
  ------------------
  |  Branch (157:41): [True: 34, False: 5]
  ------------------
  158|     34|                meshes.emplace_back();
  159|     34|                Mesh &mesh = meshes.back();
  160|       |
  161|       |                // read all vertices
  162|     34|                unsigned int numVerts = (unsigned int)stream.GetI4();
  163|     34|                if (!numVerts)
  ------------------
  |  Branch (163:21): [True: 0, False: 34]
  ------------------
  164|      0|                    throw DeadlyImportError("Quick3D: Found mesh with zero vertices");
  165|       |
  166|     34|                std::vector<aiVector3D> &verts = mesh.verts;
  167|     34|                verts.resize(numVerts);
  168|       |
  169|  21.3k|                for (unsigned int i = 0; i < numVerts; ++i) {
  ------------------
  |  Branch (169:42): [True: 21.2k, False: 34]
  ------------------
  170|  21.2k|                    verts[i].x = stream.GetF4();
  171|  21.2k|                    verts[i].y = stream.GetF4();
  172|  21.2k|                    verts[i].z = stream.GetF4();
  173|  21.2k|                }
  174|       |
  175|       |                // read all faces
  176|     34|                numVerts = (unsigned int)stream.GetI4();
  177|     34|                if (!numVerts)
  ------------------
  |  Branch (177:21): [True: 0, False: 34]
  ------------------
  178|      0|                    throw DeadlyImportError("Quick3D: Found mesh with zero faces");
  179|       |
  180|     34|                std::vector<Face> &faces = mesh.faces;
  181|     34|                faces.reserve(numVerts);
  182|       |
  183|       |                // number of indices
  184|  28.5k|                for (unsigned int i = 0; i < numVerts; ++i) {
  ------------------
  |  Branch (184:42): [True: 28.5k, False: 33]
  ------------------
  185|  28.5k|                    faces.emplace_back(stream.GetI2());
  186|  28.5k|                    if (faces.back().indices.empty())
  ------------------
  |  Branch (186:25): [True: 1, False: 28.5k]
  ------------------
  187|      1|                        throw DeadlyImportError("Quick3D: Found face with zero indices");
  188|  28.5k|                }
  189|       |
  190|       |                // indices
  191|  25.3k|                for (unsigned int i = 0; i < numVerts; ++i) {
  ------------------
  |  Branch (191:42): [True: 25.2k, False: 33]
  ------------------
  192|  25.2k|                    Face &vec = faces[i];
  193|   101k|                    for (unsigned int a = 0; a < (unsigned int)vec.indices.size(); ++a)
  ------------------
  |  Branch (193:46): [True: 75.8k, False: 25.2k]
  ------------------
  194|  75.8k|                        vec.indices[a] = stream.GetI4();
  195|  25.2k|                }
  196|       |
  197|       |                // material indices
  198|  25.3k|                for (unsigned int i = 0; i < numVerts; ++i) {
  ------------------
  |  Branch (198:42): [True: 25.2k, False: 33]
  ------------------
  199|  25.2k|                    faces[i].mat = (unsigned int)stream.GetI4();
  200|  25.2k|                }
  201|       |
  202|       |                // read all normals
  203|     33|                numVerts = (unsigned int)stream.GetI4();
  204|     33|                std::vector<aiVector3D> &normals = mesh.normals;
  205|     33|                normals.resize(numVerts);
  206|       |
  207|  18.1k|                for (unsigned int i = 0; i < numVerts; ++i) {
  ------------------
  |  Branch (207:42): [True: 18.0k, False: 33]
  ------------------
  208|  18.0k|                    normals[i].x = stream.GetF4();
  209|  18.0k|                    normals[i].y = stream.GetF4();
  210|  18.0k|                    normals[i].z = stream.GetF4();
  211|  18.0k|                }
  212|       |
  213|     33|                numVerts = (unsigned int)stream.GetI4();
  214|     33|                if (numTextures && numVerts) {
  ------------------
  |  Branch (214:21): [True: 0, False: 33]
  |  Branch (214:36): [True: 0, False: 0]
  ------------------
  215|       |                    // read all texture coordinates
  216|      0|                    std::vector<aiVector3D> &uv = mesh.uv;
  217|      0|                    uv.resize(numVerts);
  218|       |
  219|      0|                    for (unsigned int i = 0; i < numVerts; ++i) {
  ------------------
  |  Branch (219:46): [True: 0, False: 0]
  ------------------
  220|      0|                        uv[i].x = stream.GetF4();
  221|      0|                        uv[i].y = stream.GetF4();
  222|      0|                    }
  223|       |
  224|       |                    // UV indices
  225|      0|                    for (unsigned int i = 0; i < (unsigned int)faces.size(); ++i) {
  ------------------
  |  Branch (225:46): [True: 0, False: 0]
  ------------------
  226|      0|                        Face &vec = faces[i];
  227|      0|                        for (unsigned int a = 0; a < (unsigned int)vec.indices.size(); ++a) {
  ------------------
  |  Branch (227:50): [True: 0, False: 0]
  ------------------
  228|      0|                            vec.uvindices[a] = stream.GetI4();
  229|      0|                            if (!i && !a)
  ------------------
  |  Branch (229:33): [True: 0, False: 0]
  |  Branch (229:39): [True: 0, False: 0]
  ------------------
  230|      0|                                mesh.prevUVIdx = vec.uvindices[a];
  231|      0|                            else if (vec.uvindices[a] != mesh.prevUVIdx)
  ------------------
  |  Branch (231:38): [True: 0, False: 0]
  ------------------
  232|      0|                                mesh.prevUVIdx = UINT_MAX;
  233|      0|                        }
  234|      0|                    }
  235|      0|                }
  236|       |
  237|       |                // we don't need the rest, but we need to get to the next chunk
  238|     33|                stream.IncPtr(36);
  239|     33|                if (minor > '0' && major == '3')
  ------------------
  |  Branch (239:21): [True: 0, False: 33]
  |  Branch (239:36): [True: 0, False: 0]
  ------------------
  240|      0|                    stream.IncPtr(mesh.faces.size());
  241|     33|            }
  242|      6|        } break;
  243|       |
  244|       |            // materials chunk
  245|      8|        case 'c':
  ------------------
  |  Branch (245:9): [True: 8, False: 7]
  ------------------
  246|       |
  247|  9.87k|            for (unsigned int i = 0; i < numMats; ++i) {
  ------------------
  |  Branch (247:38): [True: 9.86k, False: 8]
  ------------------
  248|  9.86k|                materials.emplace_back();
  249|  9.86k|                Material &mat = materials.back();
  250|       |
  251|       |                // read the material name
  252|  9.86k|                c = stream.GetI1();
  253|  93.1k|                while (c) {
  ------------------
  |  Branch (253:24): [True: 83.2k, False: 9.86k]
  ------------------
  254|  83.2k|                    mat.name.data[mat.name.length++] = c;
  255|  83.2k|                    if (mat.name.length == AI_MAXLEN) {
  ------------------
  |  Branch (255:25): [True: 2, False: 83.2k]
  ------------------
  256|      2|                        ASSIMP_LOG_ERROR("String ouverflow detected, skipped material name parsing.");
  257|      2|                        break;
  258|      2|                    }
  259|  83.2k|                    c = stream.GetI1();
  260|  83.2k|                }
  261|       |
  262|       |                // add the terminal character
  263|  9.86k|                mat.name.data[mat.name.length] = '\0';
  264|       |
  265|       |                // read the ambient color
  266|  9.86k|                mat.ambient.r = stream.GetF4();
  267|  9.86k|                mat.ambient.g = stream.GetF4();
  268|  9.86k|                mat.ambient.b = stream.GetF4();
  269|       |
  270|       |                // read the diffuse color
  271|  9.86k|                mat.diffuse.r = stream.GetF4();
  272|  9.86k|                mat.diffuse.g = stream.GetF4();
  273|  9.86k|                mat.diffuse.b = stream.GetF4();
  274|       |
  275|       |                // read the ambient color
  276|  9.86k|                mat.specular.r = stream.GetF4();
  277|  9.86k|                mat.specular.g = stream.GetF4();
  278|  9.86k|                mat.specular.b = stream.GetF4();
  279|       |
  280|       |                // read the transparency
  281|  9.86k|                mat.transparency = stream.GetF4();
  282|       |
  283|       |                // FIX: it could be the texture index ...
  284|  9.86k|                mat.texIdx = (unsigned int)stream.GetI4();
  285|  9.86k|            }
  286|       |
  287|      8|            break;
  288|       |
  289|       |            // texture chunk
  290|      0|        case 't':
  ------------------
  |  Branch (290:9): [True: 0, False: 15]
  ------------------
  291|       |
  292|      0|            pScene->mNumTextures = numTextures;
  293|      0|            if (!numTextures) {
  ------------------
  |  Branch (293:17): [True: 0, False: 0]
  ------------------
  294|      0|                break;
  295|      0|            }
  296|      0|            pScene->mTextures = new aiTexture *[pScene->mNumTextures];
  297|       |            // to make sure we won't crash if we leave through an exception
  298|      0|            ::memset(pScene->mTextures, 0, sizeof(void *) * pScene->mNumTextures);
  299|      0|            for (unsigned int i = 0; i < pScene->mNumTextures; ++i) {
  ------------------
  |  Branch (299:38): [True: 0, False: 0]
  ------------------
  300|      0|                aiTexture *tex = pScene->mTextures[i] = new aiTexture;
  301|       |
  302|       |                // skip the texture name
  303|      0|                while (stream.GetI1())
  ------------------
  |  Branch (303:24): [True: 0, False: 0]
  ------------------
  304|      0|                    ;
  305|       |
  306|       |                // read texture width and height
  307|      0|                tex->mWidth = (unsigned int)stream.GetI4();
  308|      0|                tex->mHeight = (unsigned int)stream.GetI4();
  309|       |
  310|      0|                if (!tex->mWidth || !tex->mHeight) {
  ------------------
  |  Branch (310:21): [True: 0, False: 0]
  |  Branch (310:37): [True: 0, False: 0]
  ------------------
  311|      0|                    throw DeadlyImportError("Quick3D: Invalid texture. Width or height is zero");
  312|      0|                }
  313|       |
  314|      0|                const unsigned int uint_max = std::numeric_limits<unsigned int>::max();
  315|      0|                if (tex->mWidth > (uint_max / tex->mHeight)) {
  ------------------
  |  Branch (315:21): [True: 0, False: 0]
  ------------------
  316|      0|                    throw DeadlyImportError("Quick3D: Texture dimensions are too large, resulting in overflow.");
  317|      0|                }
  318|       |
  319|      0|                unsigned int mul = tex->mWidth * tex->mHeight;
  320|      0|                aiTexel *begin = tex->pcData = new aiTexel[mul];
  321|      0|                aiTexel *const end = &begin[mul - 1] + 1;
  322|       |
  323|      0|                for (; begin != end; ++begin) {
  ------------------
  |  Branch (323:24): [True: 0, False: 0]
  ------------------
  324|      0|                    begin->r = stream.GetI1();
  325|      0|                    begin->g = stream.GetI1();
  326|      0|                    begin->b = stream.GetI1();
  327|      0|                    begin->a = 0xff;
  328|      0|                }
  329|      0|            }
  330|       |
  331|      0|            break;
  332|       |
  333|       |            // scene chunk
  334|      1|        case 's': {
  ------------------
  |  Branch (334:9): [True: 1, False: 14]
  ------------------
  335|       |            // skip position and rotation
  336|      1|            stream.IncPtr(12);
  337|       |
  338|      5|            for (unsigned int i = 0; i < 4; ++i)
  ------------------
  |  Branch (338:38): [True: 4, False: 1]
  ------------------
  339|     20|                for (unsigned int a = 0; a < 4; ++a)
  ------------------
  |  Branch (339:42): [True: 16, False: 4]
  ------------------
  340|     16|                    pScene->mRootNode->mTransformation[i][a] = stream.GetF4();
  341|       |
  342|      1|            stream.IncPtr(16);
  343|       |
  344|       |            // now setup a single camera
  345|      1|            pScene->mNumCameras = 1;
  346|      1|            pScene->mCameras = new aiCamera *[1];
  347|      1|            aiCamera *cam = pScene->mCameras[0] = new aiCamera();
  348|      1|            cam->mPosition.x = stream.GetF4();
  349|      1|            cam->mPosition.y = stream.GetF4();
  350|      1|            cam->mPosition.z = stream.GetF4();
  351|      1|            cam->mName.Set("Q3DCamera");
  352|       |
  353|       |            // skip eye rotation for the moment
  354|      1|            stream.IncPtr(12);
  355|       |
  356|       |            // read the default material color
  357|      1|            fgColor.r = stream.GetF4();
  358|      1|            fgColor.g = stream.GetF4();
  359|      1|            fgColor.b = stream.GetF4();
  360|       |
  361|       |            // skip some unimportant properties
  362|      1|            stream.IncPtr(29);
  363|       |
  364|       |            // setup a single point light with no attenuation
  365|      1|            pScene->mNumLights = 1;
  366|      1|            pScene->mLights = new aiLight *[1];
  367|      1|            aiLight *light = pScene->mLights[0] = new aiLight();
  368|      1|            light->mName.Set("Q3DLight");
  369|      1|            light->mType = aiLightSource_POINT;
  370|       |
  371|      1|            light->mAttenuationConstant = 1;
  372|      1|            light->mAttenuationLinear = 0;
  373|      1|            light->mAttenuationQuadratic = 0;
  374|       |
  375|      1|            light->mColorDiffuse.r = stream.GetF4();
  376|      1|            light->mColorDiffuse.g = stream.GetF4();
  377|      1|            light->mColorDiffuse.b = stream.GetF4();
  378|       |
  379|      1|            light->mColorSpecular = light->mColorDiffuse;
  380|       |
  381|       |            // We don't need the rest, but we need to know where this chunk ends.
  382|      1|            const auto t1 = stream.GetI4();
  383|      1|            const auto t2 = stream.GetI4();
  384|      1|            if (t1 < 0 || t2 < 0) {
  ------------------
  |  Branch (384:17): [True: 0, False: 1]
  |  Branch (384:27): [True: 0, False: 1]
  ------------------
  385|      0|                throw DeadlyImportError("Quick3D: Overflow detected.");
  386|      0|            }
  387|      1|            const unsigned int temp = static_cast<unsigned int>(t1*t2);
  388|       |
  389|       |            // skip the background file name
  390|      1|            while (stream.GetI1())
  ------------------
  |  Branch (390:20): [True: 0, False: 1]
  ------------------
  391|      0|                ;
  392|       |
  393|       |            // skip background texture data + the remaining fields
  394|      1|            stream.IncPtr(temp * 3 + 20); // 4 bytes of unknown data here
  395|       |
  396|       |            // TODO
  397|      1|            goto outer;
  398|      1|        }
  399|       |
  400|      0|        default:
  ------------------
  |  Branch (400:9): [True: 0, False: 15]
  ------------------
  401|      0|            throw DeadlyImportError("Quick3D: Unknown chunk");
  402|     15|        };
  403|     10|    }
  404|      5|outer:
  405|       |
  406|       |    // If we have no mesh loaded - break here
  407|      5|    if (meshes.empty())
  ------------------
  |  Branch (407:9): [True: 0, False: 5]
  ------------------
  408|      0|        throw DeadlyImportError("Quick3D: No meshes loaded");
  409|       |
  410|       |    // If we have no materials loaded - generate a default mat
  411|      5|    if (materials.empty()) {
  ------------------
  |  Branch (411:9): [True: 0, False: 5]
  ------------------
  412|      0|        ASSIMP_LOG_INFO("Quick3D: No material found, generating one");
  413|      0|        materials.emplace_back();
  414|      0|        materials.back().diffuse = fgColor;
  415|      0|    }
  416|       |
  417|       |    // find out which materials we'll need
  418|      5|    typedef std::pair<unsigned int, unsigned int> FaceIdx;
  419|      5|    typedef std::vector<FaceIdx> FaceIdxArray;
  420|      5|    FaceIdxArray *fidx = new FaceIdxArray[materials.size()];
  421|       |
  422|      5|    unsigned int p = 0;
  423|      5|    for (std::vector<Mesh>::iterator it = meshes.begin(), end = meshes.end();
  424|     38|            it != end; ++it, ++p) {
  ------------------
  |  Branch (424:13): [True: 33, False: 5]
  ------------------
  425|     33|        unsigned int q = 0;
  426|     33|        for (std::vector<Face>::iterator fit = (*it).faces.begin(), fend = (*it).faces.end();
  427|  25.3k|                fit != fend; ++fit, ++q) {
  ------------------
  |  Branch (427:17): [True: 25.2k, False: 33]
  ------------------
  428|  25.2k|            if ((*fit).mat >= materials.size()) {
  ------------------
  |  Branch (428:17): [True: 10.2k, False: 15.0k]
  ------------------
  429|  10.2k|                ASSIMP_LOG_WARN("Quick3D: Material index overflow");
  430|  10.2k|                (*fit).mat = 0;
  431|  10.2k|            }
  432|  25.2k|            if (fidx[(*fit).mat].empty()) ++pScene->mNumMeshes;
  ------------------
  |  Branch (432:17): [True: 12, False: 25.2k]
  ------------------
  433|  25.2k|            fidx[(*fit).mat].emplace_back(p, q);
  434|  25.2k|        }
  435|     33|    }
  436|      5|    pScene->mNumMaterials = pScene->mNumMeshes;
  437|      5|    pScene->mMaterials = new aiMaterial *[pScene->mNumMaterials];
  438|      5|    pScene->mMeshes = new aiMesh *[pScene->mNumMaterials];
  439|       |
  440|     17|    for (unsigned int i = 0, real = 0; i < (unsigned int)materials.size(); ++i) {
  ------------------
  |  Branch (440:40): [True: 12, False: 5]
  ------------------
  441|     12|        if (fidx[i].empty())
  ------------------
  |  Branch (441:13): [True: 0, False: 12]
  ------------------
  442|      0|            continue;
  443|       |
  444|       |        // Allocate a mesh and a material
  445|     12|        aiMesh *mesh = pScene->mMeshes[real] = new aiMesh();
  446|     12|        aiMaterial *mat = new aiMaterial();
  447|     12|        pScene->mMaterials[real] = mat;
  448|       |
  449|     12|        mesh->mMaterialIndex = real;
  450|       |
  451|       |        // Build the output material
  452|     12|        Material &srcMat = materials[i];
  453|     12|        mat->AddProperty(&srcMat.diffuse, 1, AI_MATKEY_COLOR_DIFFUSE);
  454|     12|        mat->AddProperty(&srcMat.specular, 1, AI_MATKEY_COLOR_SPECULAR);
  455|     12|        mat->AddProperty(&srcMat.ambient, 1, AI_MATKEY_COLOR_AMBIENT);
  456|       |
  457|       |        // NOTE: Ignore transparency for the moment - it seems
  458|       |        // unclear how to interpret the data
  459|       |#if 0
  460|       |        if (!(minor > '0' && major == '3'))
  461|       |            srcMat.transparency = 1.0f - srcMat.transparency;
  462|       |        mat->AddProperty(&srcMat.transparency, 1, AI_MATKEY_OPACITY);
  463|       |#endif
  464|       |
  465|       |        // add shininess - Quick3D seems to use it ins its viewer
  466|     12|        srcMat.transparency = 16.f;
  467|     12|        mat->AddProperty(&srcMat.transparency, 1, AI_MATKEY_SHININESS);
  468|       |
  469|     12|        int m = (int)aiShadingMode_Phong;
  470|     12|        mat->AddProperty(&m, 1, AI_MATKEY_SHADING_MODEL);
  471|       |
  472|     12|        if (srcMat.name.length)
  ------------------
  |  Branch (472:13): [True: 12, False: 0]
  ------------------
  473|     12|            mat->AddProperty(&srcMat.name, AI_MATKEY_NAME);
  474|       |
  475|       |        // Add a texture
  476|     12|        if (srcMat.texIdx < pScene->mNumTextures || real < pScene->mNumTextures) {
  ------------------
  |  Branch (476:13): [True: 0, False: 12]
  |  Branch (476:53): [True: 0, False: 12]
  ------------------
  477|      0|            srcMat.name.data[0] = '*';
  478|      0|            srcMat.name.length = ASSIMP_itoa10(&srcMat.name.data[1], 1000,
  479|      0|                    (srcMat.texIdx < pScene->mNumTextures ? srcMat.texIdx : real));
  ------------------
  |  Branch (479:22): [True: 0, False: 0]
  ------------------
  480|      0|            mat->AddProperty(&srcMat.name, AI_MATKEY_TEXTURE_DIFFUSE(0));
  481|      0|        }
  482|       |
  483|     12|        mesh->mNumFaces = (unsigned int)fidx[i].size();
  484|     12|        aiFace *faces = mesh->mFaces = new aiFace[mesh->mNumFaces];
  485|       |
  486|       |        // Now build the output mesh. First find out how many
  487|       |        // vertices we'll need
  488|     12|        for (FaceIdxArray::const_iterator it = fidx[i].begin(), end = fidx[i].end();
  489|  25.3k|                it != end; ++it) {
  ------------------
  |  Branch (489:17): [True: 25.2k, False: 12]
  ------------------
  490|  25.2k|            mesh->mNumVertices += (unsigned int)meshes[(*it).first].faces[(*it).second].indices.size();
  491|  25.2k|        }
  492|       |
  493|     12|        aiVector3D *verts = mesh->mVertices = new aiVector3D[mesh->mNumVertices];
  494|     12|        aiVector3D *norms = mesh->mNormals = new aiVector3D[mesh->mNumVertices];
  495|     12|        aiVector3D *uv = nullptr;
  496|     12|        if (real < pScene->mNumTextures) {
  ------------------
  |  Branch (496:13): [True: 0, False: 12]
  ------------------
  497|      0|            uv = mesh->mTextureCoords[0] = new aiVector3D[mesh->mNumVertices];
  498|      0|            mesh->mNumUVComponents[0] = 2;
  499|      0|        }
  500|       |
  501|       |        // Build the final array
  502|     12|        unsigned int cnt = 0;
  503|     12|        for (FaceIdxArray::const_iterator it = fidx[i].begin(), end = fidx[i].end();
  504|  25.3k|                it != end; ++it, ++faces) {
  ------------------
  |  Branch (504:17): [True: 25.2k, False: 12]
  ------------------
  505|  25.2k|            Mesh &curMesh = meshes[(*it).first];
  506|  25.2k|            Face &face = curMesh.faces[(*it).second];
  507|  25.2k|            faces->mNumIndices = (unsigned int)face.indices.size();
  508|  25.2k|            faces->mIndices = new unsigned int[faces->mNumIndices];
  509|       |
  510|  25.2k|            aiVector3D faceNormal;
  511|  25.2k|            bool fnOK = false;
  512|       |
  513|   101k|            for (unsigned int n = 0; n < faces->mNumIndices; ++n, ++cnt, ++norms, ++verts) {
  ------------------
  |  Branch (513:38): [True: 75.8k, False: 25.2k]
  ------------------
  514|  75.8k|                if (face.indices[n] >= curMesh.verts.size()) {
  ------------------
  |  Branch (514:21): [True: 3, False: 75.8k]
  ------------------
  515|      3|                    ASSIMP_LOG_WARN("Quick3D: Vertex index overflow");
  516|      3|                    face.indices[n] = 0;
  517|      3|                }
  518|       |
  519|       |                // copy vertices
  520|  75.8k|                *verts = curMesh.verts[face.indices[n]];
  521|       |
  522|  75.8k|                if (face.indices[n] >= curMesh.normals.size() && faces->mNumIndices >= 3) {
  ------------------
  |  Branch (522:21): [True: 0, False: 75.8k]
  |  Branch (522:66): [True: 0, False: 0]
  ------------------
  523|       |                    // we have no normal here - assign the face normal
  524|      0|                    if (!fnOK) {
  ------------------
  |  Branch (524:25): [True: 0, False: 0]
  ------------------
  525|      0|                        const aiVector3D &pV1 = curMesh.verts[face.indices[0]];
  526|      0|                        const aiVector3D &pV2 = curMesh.verts[face.indices[1]];
  527|      0|                        const aiVector3D &pV3 = curMesh.verts[face.indices.size() - 1];
  528|      0|                        faceNormal = (pV2 - pV1) ^ (pV3 - pV1).Normalize();
  529|      0|                        fnOK = true;
  530|      0|                    }
  531|      0|                    *norms = faceNormal;
  532|  75.8k|                } else {
  533|  75.8k|                    *norms = curMesh.normals[face.indices[n]];
  534|  75.8k|                }
  535|       |
  536|       |                // copy texture coordinates
  537|  75.8k|                if (uv && curMesh.uv.size()) {
  ------------------
  |  Branch (537:21): [True: 0, False: 75.8k]
  |  Branch (537:27): [True: 0, False: 0]
  ------------------
  538|      0|                    if (curMesh.prevUVIdx != 0xffffffff && curMesh.uv.size() >= curMesh.verts.size()) // workaround
  ------------------
  |  Branch (538:25): [True: 0, False: 0]
  |  Branch (538:60): [True: 0, False: 0]
  ------------------
  539|      0|                    {
  540|      0|                        *uv = curMesh.uv[face.indices[n]];
  541|      0|                    } else {
  542|      0|                        if (face.uvindices[n] >= curMesh.uv.size()) {
  ------------------
  |  Branch (542:29): [True: 0, False: 0]
  ------------------
  543|      0|                            ASSIMP_LOG_WARN("Quick3D: Texture coordinate index overflow");
  544|      0|                            face.uvindices[n] = 0;
  545|      0|                        }
  546|      0|                        *uv = curMesh.uv[face.uvindices[n]];
  547|      0|                    }
  548|      0|                    uv->y = 1.f - uv->y;
  549|      0|                    ++uv;
  550|      0|                }
  551|       |
  552|       |                // setup the new vertex index
  553|  75.8k|                faces->mIndices[n] = cnt;
  554|  75.8k|            }
  555|  25.2k|        }
  556|     12|        ++real;
  557|     12|    }
  558|       |
  559|       |    // Delete our nice helper array
  560|      5|    delete[] fidx;
  561|       |
  562|       |    // Now we need to attach the meshes to the root node of the scene
  563|      5|    pScene->mRootNode->mNumMeshes = pScene->mNumMeshes;
  564|      5|    pScene->mRootNode->mMeshes = new unsigned int[pScene->mNumMeshes];
  565|     17|    for (unsigned int i = 0; i < pScene->mNumMeshes; ++i) {
  ------------------
  |  Branch (565:30): [True: 12, False: 5]
  ------------------
  566|     12|        pScene->mRootNode->mMeshes[i] = i;
  567|     12|    }
  568|       |
  569|       |    // Add cameras and light sources to the scene root node
  570|      5|    pScene->mRootNode->mNumChildren = pScene->mNumLights + pScene->mNumCameras;
  571|      5|    if (pScene->mRootNode->mNumChildren) {
  ------------------
  |  Branch (571:9): [True: 1, False: 4]
  ------------------
  572|      1|        pScene->mRootNode->mChildren = new aiNode *[pScene->mRootNode->mNumChildren];
  573|       |
  574|       |        // the light source
  575|      1|        aiNode *nd = pScene->mRootNode->mChildren[0] = new aiNode();
  576|      1|        nd->mParent = pScene->mRootNode;
  577|      1|        nd->mName.Set("Q3DLight");
  578|      1|        nd->mTransformation = pScene->mRootNode->mTransformation;
  579|      1|        nd->mTransformation.Inverse();
  580|       |
  581|       |        // camera
  582|      1|        nd = pScene->mRootNode->mChildren[1] = new aiNode();
  583|      1|        nd->mParent = pScene->mRootNode;
  584|      1|        nd->mName.Set("Q3DCamera");
  585|      1|        nd->mTransformation = pScene->mRootNode->mChildren[0]->mTransformation;
  586|      1|    }
  587|      5|}

_ZN6Assimp11Q3DImporter8MaterialC2Ev:
   85|  9.86k|        Material() : diffuse(0.6f,0.6f,0.6f), transparency(0.f), texIdx(UINT_MAX) {
   86|       |            // empty
   87|  9.86k|        }
_ZN6Assimp11Q3DImporter4FaceC2Ej:
   96|  28.5k|        explicit Face(unsigned int s) : indices(s), uvindices(s), mat(0) {
   97|       |            // empty
   98|  28.5k|        }

_ZNK6Assimp11RAWImporter7CanReadERKNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEPNS_8IOSystemEb:
   75|    353|bool RAWImporter::CanRead(const std::string &filename, IOSystem * /*pIOHandler*/, bool /*checkSig*/) const {
   76|    353|    return SimpleExtensionCheck(filename, "raw");
   77|    353|}
_ZNK6Assimp11RAWImporter7GetInfoEv:
   80|    634|const aiImporterDesc *RAWImporter::GetInfo() const {
   81|    634|    return &desc;
   82|    634|}

_ZN6Assimp11RAWImporterC2Ev:
   60|    624|    RAWImporter() = default;

_ZNK6Assimp11SIBImporter7CanReadERKNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEPNS_8IOSystemEb:
  201|    353|bool SIBImporter::CanRead(const std::string &filename, IOSystem * /*pIOHandler*/, bool /*checkSig*/) const {
  202|    353|    return SimpleExtensionCheck(filename, "sib");
  203|    353|}
_ZNK6Assimp11SIBImporter7GetInfoEv:
  206|    634|const aiImporterDesc *SIBImporter::GetInfo() const {
  207|    634|    return &desc;
  208|    634|}

_ZN6Assimp11SIBImporterC2Ev:
   60|    624|    SIBImporter() = default;

_ZN6Assimp11SMDImporterC2Ev:
   86|    624|        mBuffer(),
   87|    624|        mEnd(nullptr),
   88|    624|        pScene(nullptr),
   89|    624|        iFileSize( 0 ),
   90|    624|        iSmallestFrame( INT_MAX ),
   91|    624|        dLengthOfAnim( 0.0 ),
   92|    624|        bHasUVs(false ),
   93|    624|        iLineNumber((unsigned int)-1)  {
   94|       |    // empty
   95|    624|}
_ZNK6Assimp11SMDImporter7CanReadERKNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEPNS_8IOSystemEb:
  100|    410|bool SMDImporter::CanRead( const std::string& filename, IOSystem* /*pIOHandler*/, bool) const {
  101|    410|    return SimpleExtensionCheck(filename, "smd", "vta");
  102|    410|}
_ZNK6Assimp11SMDImporter7GetInfoEv:
  106|    647|const aiImporterDesc* SMDImporter::GetInfo () const {
  107|    647|    return &desc;
  108|    647|}
_ZN6Assimp11SMDImporter15SetupPropertiesEPKNS_8ImporterE:
  112|     13|void SMDImporter::SetupProperties(const Importer* pImp) {
  113|       |    // The
  114|       |    // AI_CONFIG_IMPORT_SMD_KEYFRAME option overrides the
  115|       |    // AI_CONFIG_IMPORT_GLOBAL_KEYFRAME option.
  116|     13|    configFrameID = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_SMD_KEYFRAME,-1);
  117|     13|    if(static_cast<unsigned int>(-1) == configFrameID)  {
  ------------------
  |  Branch (117:8): [True: 13, False: 0]
  ------------------
  118|     13|        configFrameID = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_GLOBAL_KEYFRAME,0);
  119|     13|    }
  120|       |
  121|     13|    bLoadAnimationList = pImp->GetPropertyBool(AI_CONFIG_IMPORT_SMD_LOAD_ANIMATION_LIST, true);
  122|       |    noSkeletonMesh = pImp->GetPropertyBool(AI_CONFIG_IMPORT_NO_SKELETON_MESHES, false);
  123|     13|}
_ZN6Assimp11SMDImporter14InternReadFileERKNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEP7aiScenePNS_8IOSystemE:
  127|     13|void SMDImporter::InternReadFile( const std::string& pFile, aiScene* scene, IOSystem* pIOHandler) {
  128|     13|    this->pScene = scene;
  129|     13|    ReadSmd(pFile, pIOHandler);
  130|       |
  131|       |    // If there are no triangles it seems to be an animation SMD,
  132|       |    // containing only the animation skeleton.
  133|     13|    if (asTriangles.empty()) {
  ------------------
  |  Branch (133:9): [True: 2, False: 11]
  ------------------
  134|      2|        if (asBones.empty()) {
  ------------------
  |  Branch (134:13): [True: 0, False: 2]
  ------------------
  135|      0|            throw DeadlyImportError("SMD: No triangles and no bones have "
  136|      0|                "been found in the file. This file seems to be invalid.");
  137|      0|        }
  138|       |
  139|       |        // Set the flag in the scene structure which indicates
  140|       |        // that there is nothing than an animation skeleton
  141|      2|        pScene->mFlags |= AI_SCENE_FLAGS_INCOMPLETE;
  142|      2|    }
  143|       |
  144|     13|    if (!asBones.empty()) {
  ------------------
  |  Branch (144:9): [True: 2, False: 11]
  ------------------
  145|       |        // Check whether all bones have been initialized
  146|      2|        for (const auto &asBone : asBones) {
  ------------------
  |  Branch (146:33): [True: 2, False: 2]
  ------------------
  147|      2|            if (!asBone.mName.length()) {
  ------------------
  |  Branch (147:17): [True: 0, False: 2]
  ------------------
  148|      0|                ASSIMP_LOG_WARN("SMD: Not all bones have been initialized");
  149|      0|                break;
  150|      0|            }
  151|      2|        }
  152|       |
  153|       |        // now fix invalid time values and make sure the animation starts at frame 0
  154|      2|        FixTimeValues();
  155|      2|    }
  156|       |
  157|       |    // build output nodes (bones are added as empty dummy nodes)
  158|     13|    CreateOutputNodes();
  159|       |
  160|     13|    if (!(pScene->mFlags & AI_SCENE_FLAGS_INCOMPLETE)) {
  ------------------
  |  Branch (160:9): [True: 4, False: 9]
  ------------------
  161|       |        // create output meshes
  162|      4|        CreateOutputMeshes();
  163|       |
  164|       |        // build an output material list
  165|      4|        CreateOutputMaterials();
  166|       |
  167|       |        // use root node that renders all meshes
  168|      4|        pScene->mRootNode->mNumMeshes = pScene->mNumMeshes;
  169|      4|        pScene->mRootNode->mMeshes = new unsigned int[pScene->mNumMeshes];
  170|     16|        for (unsigned int i = 0; i < pScene->mNumMeshes; ++i) {
  ------------------
  |  Branch (170:34): [True: 12, False: 4]
  ------------------
  171|     12|            pScene->mRootNode->mMeshes[i] = i;
  172|     12|        }
  173|      4|    }
  174|       |
  175|       |    // build the output animation
  176|     13|    CreateOutputAnimations(pFile, pIOHandler);
  177|       |
  178|     13|    if ((pScene->mFlags & AI_SCENE_FLAGS_INCOMPLETE) && !noSkeletonMesh) {
  ------------------
  |  Branch (178:9): [True: 2, False: 11]
  |  Branch (178:57): [True: 2, False: 0]
  ------------------
  179|      2|        SkeletonMeshBuilder skeleton(pScene);
  180|      2|    }
  181|     13|}
_ZN6Assimp11SMDImporter15LogErrorNoThrowEPKc:
  185|  45.9k|void SMDImporter::LogErrorNoThrow(const char* msg) {
  186|  45.9k|    const size_t _BufferSize = 1024;
  187|  45.9k|    char szTemp[_BufferSize];
  188|       |    ai_snprintf(szTemp,_BufferSize,"Line %u: %s",iLineNumber,msg);
  189|  45.9k|    DefaultLogger::get()->error(szTemp);
  190|  45.9k|}
_ZN6Assimp11SMDImporter10LogWarningEPKc:
  194|    124|void SMDImporter::LogWarning(const char* msg) {
  195|    124|    const size_t _BufferSize = 1024;
  196|    124|    char szTemp[_BufferSize];
  197|    124|    ai_assert(strlen(msg) < 1000);
  198|    124|    ai_snprintf(szTemp,_BufferSize,"Line %u: %s",iLineNumber,msg);
  199|       |    ASSIMP_LOG_WARN(szTemp);
  200|    124|}
_ZN6Assimp11SMDImporter13FixTimeValuesEv:
  204|     48|void SMDImporter::FixTimeValues() {
  205|     48|    double dDelta = (double)iSmallestFrame;
  206|     48|    double dMax = 0.0f;
  207|     48|    for (auto &asBone : asBones) {
  ------------------
  |  Branch (207:23): [True: 48, False: 48]
  ------------------
  208|     48|        for (auto &asKey : asBone.sAnim.asKeys) {
  ------------------
  |  Branch (208:26): [True: 0, False: 48]
  ------------------
  209|      0|            asKey.dTime -= dDelta;
  210|      0|            dMax = std::max(dMax, asKey.dTime);
  211|      0|        }
  212|     48|    }
  213|     48|    dLengthOfAnim = dMax;
  214|     48|}
_ZN6Assimp11SMDImporter18CreateOutputMeshesEv:
  218|      4|void SMDImporter::CreateOutputMeshes() {
  219|      4|    if (aszTextures.empty()) {
  ------------------
  |  Branch (219:9): [True: 0, False: 4]
  ------------------
  220|      0|        aszTextures.emplace_back();
  221|      0|    }
  222|       |
  223|       |    // we need to sort all faces by their material index
  224|       |    // in opposition to other loaders we can be sure that each
  225|       |    // material is at least used once.
  226|      4|    pScene->mNumMeshes = (unsigned int) aszTextures.size();
  227|      4|    pScene->mMeshes = new aiMesh*[pScene->mNumMeshes];
  228|       |
  229|      4|    typedef std::vector<unsigned int> FaceList;
  230|      4|    std::unique_ptr<FaceList[]> aaiFaces(new FaceList[pScene->mNumMeshes]);
  231|       |
  232|       |    // approximate the space that will be required
  233|      4|    unsigned int iNum = (unsigned int)asTriangles.size() / pScene->mNumMeshes;
  234|      4|    iNum += iNum >> 1;
  235|     16|    for (unsigned int i = 0; i < pScene->mNumMeshes;++i) {
  ------------------
  |  Branch (235:30): [True: 12, False: 4]
  ------------------
  236|     12|        aaiFaces[i].reserve(iNum);
  237|     12|    }
  238|       |
  239|       |    // collect all faces
  240|      4|    iNum = 0;
  241|     12|    for (const auto &asTriangle : asTriangles) {
  ------------------
  |  Branch (241:33): [True: 12, False: 4]
  ------------------
  242|     12|        if (asTriangle.iTexture >= aszTextures.size()) {
  ------------------
  |  Branch (242:13): [True: 0, False: 12]
  ------------------
  243|      0|            ASSIMP_LOG_INFO("[SMD/VTA] Material index overflow in face");
  244|      0|            aaiFaces[asTriangle.iTexture].push_back((unsigned int)aszTextures.size()-1);
  245|     12|        } else {
  246|     12|            aaiFaces[asTriangle.iTexture].push_back(iNum);
  247|     12|        }
  248|     12|        ++iNum;
  249|     12|    }
  250|       |
  251|       |    // now create the output meshes
  252|     16|    for (unsigned int i = 0; i < pScene->mNumMeshes;++i) {
  ------------------
  |  Branch (252:30): [True: 12, False: 4]
  ------------------
  253|     12|        aiMesh*& pcMesh = pScene->mMeshes[i] = new aiMesh();
  254|     12|        ai_assert(!aaiFaces[i].empty()); // should not be empty ...
  255|       |
  256|     12|        pcMesh->mPrimitiveTypes = aiPrimitiveType_TRIANGLE;
  257|     12|        pcMesh->mNumVertices = (unsigned int)aaiFaces[i].size()*3;
  258|     12|        pcMesh->mNumFaces = (unsigned int)aaiFaces[i].size();
  259|     12|        pcMesh->mMaterialIndex = i;
  260|       |
  261|       |        // storage for bones
  262|     12|        typedef std::pair<unsigned int,float> TempWeightListEntry;
  263|     12|        typedef std::vector< TempWeightListEntry > TempBoneWeightList;
  264|       |
  265|     12|        std::unique_ptr<TempBoneWeightList[]> aaiBones(new TempBoneWeightList[asBones.size()]());
  266|       |
  267|       |        // try to reserve enough memory without wasting too much
  268|     12|        for (unsigned int iBone = 0; iBone < asBones.size();++iBone) {
  ------------------
  |  Branch (268:38): [True: 0, False: 12]
  ------------------
  269|      0|            aaiBones[iBone].reserve(pcMesh->mNumVertices/asBones.size());
  270|      0|        }
  271|       |
  272|       |        // allocate storage
  273|     12|        pcMesh->mFaces = new aiFace[pcMesh->mNumFaces];
  274|     12|        aiVector3D* pcNormals = pcMesh->mNormals = new aiVector3D[pcMesh->mNumVertices];
  275|     12|        aiVector3D* pcVerts = pcMesh->mVertices = new aiVector3D[pcMesh->mNumVertices];
  276|       |
  277|     12|        aiVector3D* pcUVs = nullptr;
  278|     12|        if (bHasUVs) {
  ------------------
  |  Branch (278:13): [True: 12, False: 0]
  ------------------
  279|     12|            pcUVs = pcMesh->mTextureCoords[0] = new aiVector3D[pcMesh->mNumVertices];
  280|     12|            pcMesh->mNumUVComponents[0] = 2;
  281|     12|        }
  282|       |
  283|     12|        iNum = 0;
  284|     24|        for (unsigned int iFace = 0; iFace < pcMesh->mNumFaces;++iFace) {
  ------------------
  |  Branch (284:38): [True: 12, False: 12]
  ------------------
  285|     12|            pcMesh->mFaces[iFace].mIndices = new unsigned int[3];
  286|     12|            pcMesh->mFaces[iFace].mNumIndices = 3;
  287|       |
  288|       |            // fill the vertices
  289|     12|            unsigned int iSrcFace = aaiFaces[i][iFace];
  290|     12|            SMD::Face& face = asTriangles[iSrcFace];
  291|       |
  292|     12|            *pcVerts++ = face.avVertices[0].pos;
  293|     12|            *pcVerts++ = face.avVertices[1].pos;
  294|     12|            *pcVerts++ = face.avVertices[2].pos;
  295|       |
  296|       |            // fill the normals
  297|     12|            *pcNormals++ = face.avVertices[0].nor;
  298|     12|            *pcNormals++ = face.avVertices[1].nor;
  299|     12|            *pcNormals++ = face.avVertices[2].nor;
  300|       |
  301|       |            // fill the texture coordinates
  302|     12|            if (pcUVs) {
  ------------------
  |  Branch (302:17): [True: 12, False: 0]
  ------------------
  303|     12|                *pcUVs++ = face.avVertices[0].uv;
  304|     12|                *pcUVs++ = face.avVertices[1].uv;
  305|     12|                *pcUVs++ = face.avVertices[2].uv;
  306|     12|            }
  307|       |
  308|     48|            for (unsigned int iVert = 0; iVert < 3;++iVert) {
  ------------------
  |  Branch (308:42): [True: 36, False: 12]
  ------------------
  309|     36|                float fSum = 0.0f;
  310|     36|                for (unsigned int iBone = 0;iBone < face.avVertices[iVert].aiBoneLinks.size();++iBone)  {
  ------------------
  |  Branch (310:45): [True: 0, False: 36]
  ------------------
  311|      0|                    TempWeightListEntry& pairval = face.avVertices[iVert].aiBoneLinks[iBone];
  312|       |
  313|       |                    // FIX: The second check is here just to make sure we won't
  314|       |                    // assign more than one weight to a single vertex index
  315|      0|                    if (pairval.first >= asBones.size() || pairval.first == face.avVertices[iVert].iParentNode) {
  ------------------
  |  Branch (315:25): [True: 0, False: 0]
  |  Branch (315:60): [True: 0, False: 0]
  ------------------
  316|      0|                        ASSIMP_LOG_ERROR("[SMD/VTA] Bone index overflow. "
  317|      0|                            "The bone index will be ignored, the weight will be assigned "
  318|      0|                            "to the vertex' parent node");
  319|      0|                        continue;
  320|      0|                    }
  321|      0|                    aaiBones[pairval.first].emplace_back(iNum,pairval.second);
  322|      0|                    fSum += pairval.second;
  323|      0|                }
  324|       |                // ******************************************************************
  325|       |                // If the sum of all vertex weights is not 1.0 we must assign
  326|       |                // the rest to the vertex' parent node. Well, at least the doc says
  327|       |                // we should ...
  328|       |                // FIX: We use 0.975 as limit, floating-point inaccuracies seem to
  329|       |                // be very strong in some SMD exporters. Furthermore it is possible
  330|       |                // that the parent of a vertex is 0xffffffff (if the corresponding
  331|       |                // entry in the file was unreadable)
  332|       |                // ******************************************************************
  333|     36|                if (fSum < 0.975f && face.avVertices[iVert].iParentNode != UINT_MAX) {
  ------------------
  |  Branch (333:21): [True: 36, False: 0]
  |  Branch (333:38): [True: 24, False: 12]
  ------------------
  334|     24|                    if (face.avVertices[iVert].iParentNode >= asBones.size()) {
  ------------------
  |  Branch (334:25): [True: 24, False: 0]
  ------------------
  335|     24|                        ASSIMP_LOG_ERROR("[SMD/VTA] Bone index overflow. "
  336|     24|                            "The index of the vertex parent bone is invalid. "
  337|     24|                            "The remaining weights will be normalized to 1.0");
  338|       |
  339|     24|                        if (fSum) {
  ------------------
  |  Branch (339:29): [True: 0, False: 24]
  ------------------
  340|      0|                            fSum = 1 / fSum;
  341|      0|                            for (auto &pairval : face.avVertices[iVert].aiBoneLinks) {
  ------------------
  |  Branch (341:48): [True: 0, False: 0]
  ------------------
  342|      0|                                if (pairval.first >= asBones.size()) {
  ------------------
  |  Branch (342:37): [True: 0, False: 0]
  ------------------
  343|      0|                                    continue;
  344|      0|                                }
  345|      0|                                aaiBones[pairval.first].back().second *= fSum;
  346|      0|                            }
  347|      0|                        }
  348|     24|                    } else {
  349|      0|                        aaiBones[face.avVertices[iVert].iParentNode].emplace_back(iNum,1.0f-fSum);
  350|      0|                    }
  351|     24|                }
  352|     36|                pcMesh->mFaces[iFace].mIndices[iVert] = iNum++;
  353|     36|            }
  354|     12|        }
  355|       |
  356|       |        // now build all bones of the mesh
  357|     12|        iNum = 0;
  358|     12|        for (unsigned int iBone = 0; iBone < asBones.size();++iBone) {
  ------------------
  |  Branch (358:38): [True: 0, False: 12]
  ------------------
  359|      0|            if (!aaiBones[iBone].empty())++iNum;
  ------------------
  |  Branch (359:17): [True: 0, False: 0]
  ------------------
  360|      0|        }
  361|       |
  362|     12|        if (iNum) {
  ------------------
  |  Branch (362:13): [True: 0, False: 12]
  ------------------
  363|      0|            pcMesh->mNumBones = iNum;
  364|      0|            pcMesh->mBones = new aiBone*[pcMesh->mNumBones];
  365|      0|            iNum = 0;
  366|      0|            for (unsigned int iBone = 0; iBone < asBones.size();++iBone) {
  ------------------
  |  Branch (366:42): [True: 0, False: 0]
  ------------------
  367|      0|                if (aaiBones[iBone].empty()) {
  ------------------
  |  Branch (367:21): [True: 0, False: 0]
  ------------------
  368|      0|                    continue;
  369|      0|                }
  370|      0|                aiBone*& bone = pcMesh->mBones[iNum] = new aiBone();
  371|       |
  372|      0|                bone->mNumWeights = (unsigned int)aaiBones[iBone].size();
  373|      0|                bone->mWeights = new aiVertexWeight[bone->mNumWeights];
  374|      0|                bone->mOffsetMatrix = asBones[iBone].mOffsetMatrix;
  375|      0|                bone->mName.Set( asBones[iBone].mName );
  376|       |
  377|      0|                asBones[iBone].bIsUsed = true;
  378|       |
  379|      0|                for (unsigned int iWeight = 0; iWeight < bone->mNumWeights;++iWeight) {
  ------------------
  |  Branch (379:48): [True: 0, False: 0]
  ------------------
  380|      0|                    bone->mWeights[iWeight].mVertexId = aaiBones[iBone][iWeight].first;
  381|      0|                    bone->mWeights[iWeight].mWeight = aaiBones[iBone][iWeight].second;
  382|      0|                }
  383|      0|                ++iNum;
  384|      0|            }
  385|      0|        }
  386|     12|    }
  387|      4|}
_ZN6Assimp11SMDImporter15AddBoneChildrenEP6aiNodej:
  391|      7|void SMDImporter::AddBoneChildren(aiNode* pcNode, uint32_t iParent) {
  392|      7|    ai_assert( nullptr != pcNode );
  393|      7|    ai_assert( 0 == pcNode->mNumChildren );
  394|      7|    ai_assert( nullptr == pcNode->mChildren);
  395|       |
  396|       |    // first count ...
  397|      7|    for (auto &bone : asBones) {
  ------------------
  |  Branch (397:21): [True: 3, False: 7]
  ------------------
  398|      3|        if (bone.iParent == iParent) {
  ------------------
  |  Branch (398:13): [True: 1, False: 2]
  ------------------
  399|      1|            ++pcNode->mNumChildren;
  400|      1|        }
  401|      3|    }
  402|       |
  403|       |    // nothing to do
  404|      7|    if (pcNode->mNumChildren == 0)
  ------------------
  |  Branch (404:9): [True: 6, False: 1]
  ------------------
  405|      6|        return;
  406|       |
  407|       |    // now allocate the output array
  408|      1|    pcNode->mChildren = new aiNode *[pcNode->mNumChildren];
  409|       |
  410|       |    // and fill all subnodes
  411|      1|    unsigned int qq( 0 );
  412|      2|    for (unsigned int i = 0; i < asBones.size();++i) {
  ------------------
  |  Branch (412:30): [True: 1, False: 1]
  ------------------
  413|      1|        SMD::Bone& bone = asBones[i];
  414|      1|        if (bone.iParent != iParent) {
  ------------------
  |  Branch (414:13): [True: 0, False: 1]
  ------------------
  415|      0|            continue;
  416|      0|        }
  417|       |
  418|      1|        aiNode* pc = pcNode->mChildren[qq++] = new aiNode();
  419|      1|        pc->mName.Set(bone.mName);
  420|       |
  421|       |        // store the local transformation matrix of the bind pose
  422|      1|        if (bone.sAnim.asKeys.size()) {
  ------------------
  |  Branch (422:13): [True: 0, False: 1]
  ------------------
  423|      0|            pc->mTransformation = bone.sAnim.asKeys[0].matrix;
  424|      0|        }
  425|       |
  426|      1|        if (bone.iParent == static_cast<uint32_t>(-1)) {
  ------------------
  |  Branch (426:13): [True: 1, False: 0]
  ------------------
  427|      1|            bone.mOffsetMatrix = pc->mTransformation;
  428|      1|        } else {
  429|      0|            bone.mOffsetMatrix = asBones[bone.iParent].mOffsetMatrix * pc->mTransformation;
  430|      0|        }
  431|       |
  432|      1|        pc->mParent = pcNode;
  433|       |
  434|       |        // add children to this node, too
  435|      1|        AddBoneChildren(pc,i);
  436|      1|    }
  437|      1|}
_ZN6Assimp11SMDImporter17CreateOutputNodesEv:
  441|      6|void SMDImporter::CreateOutputNodes() {
  442|      6|    pScene->mRootNode = new aiNode();
  443|       |
  444|       |    // now add all bones as dummy sub nodes to the graph
  445|      6|    AddBoneChildren(pScene->mRootNode,(uint32_t)-1);
  446|      6|    for (auto &bone : asBones) {
  ------------------
  |  Branch (446:21): [True: 2, False: 6]
  ------------------
  447|      2|        bone.mOffsetMatrix.Inverse();
  448|      2|    }
  449|       |
  450|       |    // if we have only one bone we can even remove the root node
  451|      6|    if (pScene->mFlags & AI_SCENE_FLAGS_INCOMPLETE && 1 == pScene->mRootNode->mNumChildren) {
  ------------------
  |  Branch (451:9): [True: 2, False: 4]
  |  Branch (451:55): [True: 1, False: 1]
  ------------------
  452|      1|        aiNode* pcOldRoot = pScene->mRootNode;
  453|      1|        pScene->mRootNode = pcOldRoot->mChildren[0];
  454|      1|        pcOldRoot->mChildren[0] = nullptr;
  455|      1|        delete pcOldRoot;
  456|       |
  457|      1|        pScene->mRootNode->mParent = nullptr;
  458|      5|    } else {
  459|      5|        static constexpr char rootName[11] = "<SMD_root>";
  460|      5|        pScene->mRootNode->mName.length = 10;
  461|      5|        ::strncpy(pScene->mRootNode->mName.data, rootName, pScene->mRootNode->mName.length);
  462|      5|    }
  463|      6|}
_ZN6Assimp11SMDImporter22CreateOutputAnimationsERKNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEPNS_8IOSystemE:
  467|      6|void SMDImporter::CreateOutputAnimations(const std::string &pFile, IOSystem* pIOHandler) {
  468|      6|    std::vector<std::tuple<std::string, std::string>> animFileList;
  469|       |
  470|      6|    if (bLoadAnimationList) {
  ------------------
  |  Branch (470:9): [True: 6, False: 0]
  ------------------
  471|      6|        GetAnimationFileList(pFile, pIOHandler, animFileList);
  472|      6|    }
  473|      6|    int animCount = static_cast<int>( animFileList.size() + 1u );
  474|      6|    pScene->mNumAnimations = 1;
  475|      6|    pScene->mAnimations = new aiAnimation*[animCount];
  476|      6|    memset(pScene->mAnimations, 0, sizeof(aiAnimation*)*animCount);
  477|      6|    CreateOutputAnimation(0, "");
  478|       |
  479|  5.13k|    for (auto &animFile : animFileList) {
  ------------------
  |  Branch (479:25): [True: 5.13k, False: 6]
  ------------------
  480|  5.13k|        ReadSmd(std::get<1>(animFile), pIOHandler);
  481|  5.13k|        if (asBones.empty()) {
  ------------------
  |  Branch (481:13): [True: 5.08k, False: 46]
  ------------------
  482|  5.08k|            continue;
  483|  5.08k|        }
  484|       |
  485|     46|        FixTimeValues();
  486|     46|        CreateOutputAnimation(pScene->mNumAnimations++, std::get<0>(animFile));
  487|     46|    }
  488|      6|}
_ZN6Assimp11SMDImporter21CreateOutputAnimationEiRKNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEE:
  490|     52|void SMDImporter::CreateOutputAnimation(int index, const std::string &name) {
  491|     52|    aiAnimation*& anim = pScene->mAnimations[index] = new aiAnimation();
  492|       |
  493|     52|    if (name.length()) {
  ------------------
  |  Branch (493:9): [True: 46, False: 6]
  ------------------
  494|     46|        anim->mName.Set(name.c_str());
  495|     46|    }
  496|     52|    anim->mDuration = dLengthOfAnim;
  497|     52|    anim->mNumChannels = static_cast<unsigned int>( asBones.size() );
  498|     52|    anim->mTicksPerSecond = 25.0; // FIXME: is this correct?
  499|       |
  500|     52|    aiNodeAnim** pp = anim->mChannels = new aiNodeAnim*[anim->mNumChannels];
  501|       |
  502|       |    // now build valid keys
  503|     52|    unsigned int a = 0;
  504|     52|    for (const auto &asBone : asBones) {
  ------------------
  |  Branch (504:29): [True: 48, False: 52]
  ------------------
  505|     48|        aiNodeAnim* p = pp[a] = new aiNodeAnim();
  506|       |
  507|       |        // copy the name of the bone
  508|     48|        p->mNodeName.Set(asBone.mName);
  509|       |
  510|     48|        p->mNumRotationKeys = (unsigned int)asBone.sAnim.asKeys.size();
  511|     48|        if (p->mNumRotationKeys){
  ------------------
  |  Branch (511:13): [True: 0, False: 48]
  ------------------
  512|      0|            p->mNumPositionKeys = p->mNumRotationKeys;
  513|      0|            aiVectorKey* pVecKeys = p->mPositionKeys = new aiVectorKey[p->mNumRotationKeys];
  514|      0|            aiQuatKey* pRotKeys = p->mRotationKeys = new aiQuatKey[p->mNumRotationKeys];
  515|       |
  516|      0|            for (const auto &asKey : asBone.sAnim.asKeys) {
  ------------------
  |  Branch (516:36): [True: 0, False: 0]
  ------------------
  517|      0|                pRotKeys->mTime = pVecKeys->mTime = asKey.dTime;
  518|       |
  519|       |                // compute the rotation quaternion from the euler angles
  520|       |                // aiQuaternion: The order of the parameters is yzx?
  521|      0|                pRotKeys->mValue = aiQuaternion(asKey.vRot.y, asKey.vRot.z, asKey.vRot.x);
  522|      0|                pVecKeys->mValue = asKey.vPos;
  523|       |
  524|      0|                ++pVecKeys; ++pRotKeys;
  525|      0|            }
  526|      0|        }
  527|     48|        ++a;
  528|       |
  529|       |        // there are no scaling keys ...
  530|     48|    }
  531|     52|}
_ZN6Assimp11SMDImporter20GetAnimationFileListERKNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEPNS_8IOSystemERNS1_6vectorINS1_5tupleIJS7_S7_EEENS5_ISE_EEEE:
  533|      6|void SMDImporter::GetAnimationFileList(const std::string &pFile, IOSystem* pIOHandler, std::vector<std::tuple<std::string, std::string>>& outList) {
  534|      6|    auto base = DefaultIOSystem::absolutePath(pFile);
  535|      6|    auto name = DefaultIOSystem::completeBaseName(pFile);
  536|      6|    auto path = base + "/" + name + "_animation.txt";
  537|       |
  538|      6|    std::unique_ptr<IOStream> file(pIOHandler->Open(path.c_str(), "rb"));
  539|      6|    if (file == nullptr) {
  ------------------
  |  Branch (539:9): [True: 0, False: 6]
  ------------------
  540|      0|        return;
  541|      0|    }
  542|       |
  543|       |    // Allocate storage and copy the contents of the file to a memory buffer
  544|      6|    std::vector<char> buf;
  545|      6|    size_t fileSize = file->FileSize();
  546|      6|    buf.resize(fileSize + 1);
  547|      6|    TextFileToBuffer(file.get(), buf);
  548|       |
  549|       |    /*
  550|       |        *_animation.txt format:
  551|       |        name path
  552|       |        idle idle.smd
  553|       |        jump anim/jump.smd
  554|       |        walk.smd
  555|       |        ...
  556|       |    */
  557|      6|    std::string animName, animPath;
  558|      6|    char *tok1, *tok2;
  559|      6|    char *context1, *context2;
  560|       |
  561|      6|    tok1 = strtok_s(&buf[0], "\r\n", &context1);
  ------------------
  |  |   64|      6|#define strtok_s strtok_r
  ------------------
  562|  5.14k|    while (tok1 != nullptr) {
  ------------------
  |  Branch (562:12): [True: 5.13k, False: 6]
  ------------------
  563|  5.13k|        tok2 = strtok_s(tok1, " \t", &context2);
  ------------------
  |  |   64|  5.13k|#define strtok_s strtok_r
  ------------------
  564|  5.13k|        if (tok2) {
  ------------------
  |  Branch (564:13): [True: 5.13k, False: 0]
  ------------------
  565|  5.13k|            char *p = tok2;
  566|  5.13k|            tok2 = strtok_s(nullptr, " \t", &context2);
  ------------------
  |  |   64|  5.13k|#define strtok_s strtok_r
  ------------------
  567|  5.13k|            if (tok2) {
  ------------------
  |  Branch (567:17): [True: 1.70k, False: 3.42k]
  ------------------
  568|  1.70k|                animPath = tok2;
  569|  1.70k|                animName = p;
  570|  3.42k|            } else  {
  571|       |                // No name
  572|  3.42k|                animPath = p;
  573|  3.42k|                animName = DefaultIOSystem::completeBaseName(animPath);
  574|  3.42k|            }
  575|  5.13k|            outList.emplace_back(animName, base + "/" + animPath);
  576|  5.13k|        }
  577|  5.13k|        tok1 = strtok_s(nullptr, "\r\n", &context1);
  ------------------
  |  |   64|  5.13k|#define strtok_s strtok_r
  ------------------
  578|  5.13k|    }
  579|      6|}
_ZN6Assimp11SMDImporter21CreateOutputMaterialsEv:
  583|      4|void SMDImporter::CreateOutputMaterials() {
  584|      4|    ai_assert( nullptr != pScene );
  585|       |
  586|      4|    pScene->mNumMaterials = (unsigned int)aszTextures.size();
  587|      4|    pScene->mMaterials = new aiMaterial*[std::max(1u, pScene->mNumMaterials)];
  588|       |
  589|     16|    for (unsigned int iMat = 0; iMat < pScene->mNumMaterials; ++iMat) {
  ------------------
  |  Branch (589:33): [True: 12, False: 4]
  ------------------
  590|     12|        aiMaterial* pcMat = new aiMaterial();
  591|     12|        ai_assert( nullptr != pcMat );
  592|     12|        pScene->mMaterials[iMat] = pcMat;
  593|       |
  594|     12|        aiString szName;
  595|     12|        szName.length = static_cast<ai_uint32>(ai_snprintf(szName.data, AI_MAXLEN, "Texture_%u", iMat));
  596|     12|        pcMat->AddProperty(&szName,AI_MATKEY_NAME);
  597|       |
  598|     12|        if (aszTextures[iMat].length())
  ------------------
  |  Branch (598:13): [True: 12, False: 0]
  ------------------
  599|     12|        {
  600|     12|            ::strncpy(szName.data, aszTextures[iMat].c_str(), AI_MAXLEN - 1);
  601|     12|            szName.length = static_cast<ai_uint32>( aszTextures[iMat].length() );
  602|     12|            pcMat->AddProperty(&szName,AI_MATKEY_TEXTURE_DIFFUSE(0));
  603|     12|        }
  604|     12|    }
  605|       |
  606|       |    // create a default material if necessary
  607|      4|    if (0 == pScene->mNumMaterials) {
  ------------------
  |  Branch (607:9): [True: 0, False: 4]
  ------------------
  608|      0|        pScene->mNumMaterials = 1;
  609|       |
  610|      0|        aiMaterial* pcHelper = new aiMaterial();
  611|      0|        pScene->mMaterials[0] = pcHelper;
  612|       |
  613|      0|        int iMode = static_cast<int>(aiShadingMode_Gouraud);
  614|      0|        pcHelper->AddProperty<int>(&iMode, 1, AI_MATKEY_SHADING_MODEL);
  615|       |
  616|      0|        aiColor3D clr;
  617|      0|        clr.b = clr.g = clr.r = 0.7f;
  618|      0|        pcHelper->AddProperty<aiColor3D>(&clr, 1,AI_MATKEY_COLOR_DIFFUSE);
  619|      0|        pcHelper->AddProperty<aiColor3D>(&clr, 1,AI_MATKEY_COLOR_SPECULAR);
  620|       |
  621|      0|        clr.b = clr.g = clr.r = 0.05f;
  622|      0|        pcHelper->AddProperty<aiColor3D>(&clr, 1,AI_MATKEY_COLOR_AMBIENT);
  623|       |
  624|      0|        aiString szName;
  625|      0|        szName.Set(AI_DEFAULT_MATERIAL_NAME);
  626|       |        pcHelper->AddProperty(&szName,AI_MATKEY_NAME);
  627|      0|    }
  628|      4|}
_ZN6Assimp11SMDImporter9ParseFileEv:
  632|  5.14k|void SMDImporter::ParseFile() {
  633|  5.14k|    const char* szCurrent = &mBuffer[0];
  634|       |
  635|       |    // read line per line ...
  636|  6.44M|    for ( ;; ) {
  637|  6.44M|        if(!SkipSpacesAndLineEnd(szCurrent,&szCurrent, mEnd)) {
  ------------------
  |  Branch (637:12): [True: 5.14k, False: 6.43M]
  ------------------
  638|  5.14k|            break;
  639|  5.14k|        }
  640|       |
  641|       |        // "version <n> \n", <n> should be 1 for hl and hl2 SMD files
  642|  6.43M|        if (TokenMatch(szCurrent,"version",7)) {
  ------------------
  |  Branch (642:13): [True: 0, False: 6.43M]
  ------------------
  643|      0|            if(!SkipSpaces(szCurrent,&szCurrent, mEnd)) break;
  ------------------
  |  Branch (643:16): [True: 0, False: 0]
  ------------------
  644|      0|            if (1 != strtoul10(szCurrent,&szCurrent)) {
  ------------------
  |  Branch (644:17): [True: 0, False: 0]
  ------------------
  645|      0|                ASSIMP_LOG_WARN("SMD.version is not 1. This "
  646|      0|                    "file format is not known. Continuing happily ...");
  647|      0|            }
  648|      0|            continue;
  649|      0|        }
  650|       |        // "nodes\n" - Starts the node section
  651|  6.43M|        if (TokenMatch(szCurrent,"nodes",5)) {
  ------------------
  |  Branch (651:13): [True: 111, False: 6.43M]
  ------------------
  652|    111|            ParseNodesSection(szCurrent, &szCurrent, mEnd);
  653|    111|            continue;
  654|    111|        }
  655|       |        // "triangles\n" - Starts the triangle section
  656|  6.43M|        if (TokenMatch(szCurrent,"triangles",9)) {
  ------------------
  |  Branch (656:13): [True: 5.09k, False: 6.43M]
  ------------------
  657|  5.09k|            ParseTrianglesSection(szCurrent, &szCurrent, mEnd);
  658|  5.09k|            continue;
  659|  5.09k|        }
  660|       |        // "vertexanimation\n" - Starts the vertex animation section
  661|  6.43M|        if (TokenMatch(szCurrent,"vertexanimation",15)) {
  ------------------
  |  Branch (661:13): [True: 13, False: 6.43M]
  ------------------
  662|     13|            bHasUVs = false;
  663|     13|            ParseVASection(szCurrent, &szCurrent, mEnd);
  664|     13|            continue;
  665|     13|        }
  666|       |        // "skeleton\n" - Starts the skeleton section
  667|  6.43M|        if (TokenMatch(szCurrent,"skeleton",8)) {
  ------------------
  |  Branch (667:13): [True: 7, False: 6.43M]
  ------------------
  668|      7|            ParseSkeletonSection(szCurrent, &szCurrent, mEnd);
  669|      7|            continue;
  670|      7|        }
  671|  6.43M|        SkipLine(szCurrent, &szCurrent, mEnd);
  672|  6.43M|    }
  673|  5.14k|}
_ZN6Assimp11SMDImporter7ReadSmdERKNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEPNS_8IOSystemE:
  675|  5.14k|void SMDImporter::ReadSmd(const std::string &pFile, IOSystem* pIOHandler) {
  676|  5.14k|    std::unique_ptr<IOStream> file(pIOHandler->Open(pFile, "rb"));
  677|       |
  678|       |    // Check whether we can read from the file
  679|  5.14k|    if (file == nullptr) {
  ------------------
  |  Branch (679:9): [True: 0, False: 5.14k]
  ------------------
  680|      0|        throw DeadlyImportError("Failed to open SMD/VTA file ", pFile, ".");
  681|      0|    }
  682|       |
  683|  5.14k|    iFileSize = (unsigned int)file->FileSize();
  684|       |
  685|       |    // Allocate storage and copy the contents of the file to a memory buffer
  686|  5.14k|    mBuffer.resize(iFileSize + 1);
  687|  5.14k|    TextFileToBuffer(file.get(), mBuffer);
  688|  5.14k|    mEnd = &mBuffer[mBuffer.size() - 1] + 1;
  689|       |
  690|  5.14k|    iSmallestFrame = INT_MAX;
  691|  5.14k|    bHasUVs = true;
  692|  5.14k|    iLineNumber = 1;
  693|       |
  694|       |    // Reserve enough space for ... hm ... 10 textures
  695|  5.14k|    aszTextures.reserve(10);
  696|       |
  697|       |    // Reserve enough space for ... hm ... 1000 triangles
  698|  5.14k|    asTriangles.reserve(1000);
  699|       |
  700|       |    // Reserve enough space for ... hm ... 20 bones
  701|  5.14k|    asBones.reserve(20);
  702|       |
  703|  5.14k|    aszTextures.clear();
  704|  5.14k|    asTriangles.clear();
  705|  5.14k|    asBones.clear();
  706|       |
  707|       |    // parse the file ...
  708|  5.14k|    ParseFile();
  709|  5.14k|}
_ZN6Assimp11SMDImporter15GetTextureIndexERKNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEE:
  712|  15.2k|unsigned int SMDImporter::GetTextureIndex(const std::string& filename) {
  713|  15.2k|    unsigned int iIndex = 0;
  714|  15.2k|    for (std::vector<std::string>::const_iterator
  715|  15.2k|            i =  aszTextures.begin();
  716|  30.5k|            i != aszTextures.end();++i,++iIndex) {
  ------------------
  |  Branch (716:13): [True: 15.2k, False: 15.2k]
  ------------------
  717|       |        // case-insensitive ... it's a path
  718|  15.2k|        if (0 == ASSIMP_stricmp ( filename.c_str(),(*i).c_str())) {
  ------------------
  |  Branch (718:13): [True: 0, False: 15.2k]
  ------------------
  719|      0|            return iIndex;
  720|      0|        }
  721|  15.2k|    }
  722|  15.2k|    iIndex = (unsigned int)aszTextures.size();
  723|  15.2k|    aszTextures.push_back(filename);
  724|  15.2k|    return iIndex;
  725|  15.2k|}
_ZN6Assimp11SMDImporter17ParseNodesSectionEPKcPS2_S2_:
  729|    111|void SMDImporter::ParseNodesSection(const char* szCurrent, const char** szCurrentOut, const char *end) {
  730|    235|    for ( ;; ) {
  731|       |        // "end\n" - Ends the nodes section
  732|    235|        if (0 == ASSIMP_strincmp(szCurrent, "end", 3) && IsSpaceOrNewLine(*(szCurrent+3))) {
  ------------------
  |  Branch (732:13): [True: 111, False: 124]
  |  Branch (732:58): [True: 111, False: 0]
  ------------------
  733|    111|            szCurrent += 4;
  734|    111|            break;
  735|    111|        }
  736|    124|        ParseNodeInfo(szCurrent,&szCurrent, end);
  737|    124|    }
  738|    111|    SkipSpacesAndLineEnd(szCurrent, &szCurrent, end);
  739|    111|    *szCurrentOut = szCurrent;
  740|    111|}
_ZN6Assimp11SMDImporter21ParseTrianglesSectionEPKcPS2_S2_:
  744|  5.09k|void SMDImporter::ParseTrianglesSection(const char *szCurrent, const char **szCurrentOut, const char *end) {
  745|       |    // Parse a triangle, parse another triangle, parse the next triangle ...
  746|       |    // and so on until we reach a token that looks quite similar to "end"
  747|  20.3k|    for ( ;; ) {
  748|  20.3k|        if(!SkipSpacesAndLineEnd(szCurrent,&szCurrent, end)) {
  ------------------
  |  Branch (748:12): [True: 5.09k, False: 15.2k]
  ------------------
  749|  5.09k|            break;
  750|  5.09k|        }
  751|       |
  752|       |        // "end\n" - Ends the triangles section
  753|  15.2k|        if (TokenMatch(szCurrent,"end",3)) {
  ------------------
  |  Branch (753:13): [True: 0, False: 15.2k]
  ------------------
  754|      0|            break;
  755|      0|        }
  756|  15.2k|        ParseTriangle(szCurrent,&szCurrent, end);
  757|  15.2k|    }
  758|  5.09k|    SkipSpacesAndLineEnd(szCurrent,&szCurrent, end);
  759|  5.09k|    *szCurrentOut = szCurrent;
  760|  5.09k|}
_ZN6Assimp11SMDImporter14ParseVASectionEPKcPS2_S2_:
  763|     13|void SMDImporter::ParseVASection(const char *szCurrent, const char **szCurrentOut, const char *end) {
  764|     13|    unsigned int iCurIndex = 0;
  765|     13|    for ( ;; ) {
  766|     13|        if (!SkipSpacesAndLineEnd(szCurrent,&szCurrent, end)) {
  ------------------
  |  Branch (766:13): [True: 13, False: 0]
  ------------------
  767|     13|            break;
  768|     13|        }
  769|       |
  770|       |        // "end\n" - Ends the "vertexanimation" section
  771|      0|        if (TokenMatch(szCurrent,"end",3)) {
  ------------------
  |  Branch (771:13): [True: 0, False: 0]
  ------------------
  772|      0|            break;
  773|      0|        }
  774|       |
  775|       |        // "time <n>\n"
  776|      0|        if (TokenMatch(szCurrent,"time",4)) {
  ------------------
  |  Branch (776:13): [True: 0, False: 0]
  ------------------
  777|       |            // NOTE: The doc says that time values COULD be negative ...
  778|       |            // NOTE2: this is the shape key -> valve docs
  779|      0|            int iTime = 0;
  780|      0|            if (!ParseSignedInt(szCurrent, &szCurrent, end, iTime) || configFrameID != (unsigned int)iTime) {
  ------------------
  |  Branch (780:17): [True: 0, False: 0]
  |  Branch (780:71): [True: 0, False: 0]
  ------------------
  781|      0|                break;
  782|      0|            }
  783|      0|            SkipLine(szCurrent,&szCurrent, end);
  784|      0|        } else {
  785|      0|            if(0 == iCurIndex) {
  ------------------
  |  Branch (785:16): [True: 0, False: 0]
  ------------------
  786|      0|                asTriangles.emplace_back();
  787|      0|            }
  788|      0|            if (++iCurIndex == 3) {
  ------------------
  |  Branch (788:17): [True: 0, False: 0]
  ------------------
  789|      0|                iCurIndex = 0;
  790|      0|            }
  791|      0|            ParseVertex(szCurrent,&szCurrent, end, asTriangles.back().avVertices[iCurIndex],true);
  792|      0|        }
  793|      0|    }
  794|       |
  795|     13|    if (iCurIndex != 2 && !asTriangles.empty()) {
  ------------------
  |  Branch (795:9): [True: 13, False: 0]
  |  Branch (795:27): [True: 0, False: 13]
  ------------------
  796|       |        // we want to no degenerates, so throw this triangle away
  797|      0|        asTriangles.pop_back();
  798|      0|    }
  799|       |
  800|     13|    SkipSpacesAndLineEnd(szCurrent,&szCurrent, end);
  801|     13|    *szCurrentOut = szCurrent;
  802|     13|}
_ZN6Assimp11SMDImporter20ParseSkeletonSectionEPKcPS2_S2_:
  806|      7|void SMDImporter::ParseSkeletonSection(const char *szCurrent, const char **szCurrentOut, const char *end) {
  807|      7|    int iTime = 0;
  808|     14|    for ( ;; ) {
  809|     14|        if (!SkipSpacesAndLineEnd(szCurrent,&szCurrent, end)) {
  ------------------
  |  Branch (809:13): [True: 0, False: 14]
  ------------------
  810|      0|            break;
  811|      0|        }
  812|       |
  813|       |        // "end\n" - Ends the skeleton section
  814|     14|        if (TokenMatch(szCurrent,"end",3)) {
  ------------------
  |  Branch (814:13): [True: 0, False: 14]
  ------------------
  815|      0|            break;
  816|     14|        } else if (TokenMatch(szCurrent,"time",4)) {
  ------------------
  |  Branch (816:20): [True: 0, False: 14]
  ------------------
  817|       |            // "time <n>\n" - Specifies the current animation frame
  818|      0|            if (!ParseSignedInt(szCurrent, &szCurrent, end, iTime)) {
  ------------------
  |  Branch (818:17): [True: 0, False: 0]
  ------------------
  819|      0|                break;
  820|      0|            }
  821|       |
  822|      0|            iSmallestFrame = std::min(iSmallestFrame,iTime);
  823|      0|            SkipLine(szCurrent, &szCurrent, end);
  824|     14|        } else {
  825|     14|            ParseSkeletonElement(szCurrent, &szCurrent, end, iTime);
  826|     14|        }
  827|     14|    }
  828|      7|    *szCurrentOut = szCurrent;
  829|      7|}
_ZN6Assimp11SMDImporter13ParseNodeInfoEPKcPS2_S2_:
  839|    124|void SMDImporter::ParseNodeInfo(const char *szCurrent, const char **szCurrentOut, const char *end) {
  840|    124|    unsigned int iBone  = 0;
  841|    124|    SkipSpacesAndLineEnd(szCurrent, &szCurrent, end);
  842|    124|    if ( !ParseUnsignedInt(szCurrent, &szCurrent, end, iBone) || !SkipSpaces(szCurrent,&szCurrent, end)) {
  ------------------
  |  Branch (842:10): [True: 0, False: 124]
  |  Branch (842:66): [True: 0, False: 124]
  ------------------
  843|      0|        throw DeadlyImportError("Unexpected EOF/EOL while parsing bone index");
  844|      0|    }
  845|    124|    if (iBone == UINT_MAX) {
  ------------------
  |  Branch (845:9): [True: 0, False: 124]
  ------------------
  846|      0|        LogErrorNoThrow("Invalid bone number while parsing bone index");
  847|      0|        SMDI_PARSE_RETURN;
  ------------------
  |  |  832|      0|#define SMDI_PARSE_RETURN { \
  |  |  833|      0|    SkipLine(szCurrent,&szCurrent, end); \
  |  |  834|      0|    *szCurrentOut = szCurrent; \
  |  |  835|      0|    return; \
  |  |  836|      0|}
  ------------------
  848|      0|    }
  849|       |    // add our bone to the list
  850|    124|    if (iBone >= asBones.size()) {
  ------------------
  |  Branch (850:9): [True: 55, False: 69]
  ------------------
  851|     55|        asBones.resize(iBone+1);
  852|     55|    }
  853|    124|    SMD::Bone& bone = asBones[iBone];
  854|       |
  855|    124|    bool bQuota = true;
  856|    124|    if ('\"' != *szCurrent) {
  ------------------
  |  Branch (856:9): [True: 124, False: 0]
  ------------------
  857|    124|        LogWarning("Bone name is expected to be enclosed in "
  858|    124|            "double quotation marks. ");
  859|    124|        bQuota = false;
  860|    124|    } else {
  861|      0|        ++szCurrent;
  862|      0|    }
  863|       |
  864|    124|    const char* szEnd = szCurrent;
  865|    639|    for ( ;; ) {
  866|    639|        if (bQuota && '\"' == *szEnd) {
  ------------------
  |  Branch (866:13): [True: 0, False: 639]
  |  Branch (866:23): [True: 0, False: 0]
  ------------------
  867|      0|            iBone = (unsigned int)(szEnd - szCurrent);
  868|      0|            ++szEnd;
  869|      0|            break;
  870|    639|        } else if (!bQuota && IsSpaceOrNewLine(*szEnd)) {
  ------------------
  |  Branch (870:20): [True: 639, False: 0]
  |  Branch (870:31): [True: 124, False: 515]
  ------------------
  871|    124|            iBone = (unsigned int)(szEnd - szCurrent);
  872|    124|            break;
  873|    515|        } else if (!(*szEnd)) {
  ------------------
  |  Branch (873:20): [True: 0, False: 515]
  ------------------
  874|      0|            LogErrorNoThrow("Unexpected EOF/EOL while parsing bone name");
  875|      0|            SMDI_PARSE_RETURN;
  ------------------
  |  |  832|      0|#define SMDI_PARSE_RETURN { \
  |  |  833|      0|    SkipLine(szCurrent,&szCurrent, end); \
  |  |  834|      0|    *szCurrentOut = szCurrent; \
  |  |  835|      0|    return; \
  |  |  836|      0|}
  ------------------
  876|      0|        }
  877|    515|        ++szEnd;
  878|    515|    }
  879|    124|    bone.mName = std::string(szCurrent,iBone);
  880|    124|    szCurrent = szEnd;
  881|       |
  882|       |    // the only negative bone parent index that could occur is -1 AFAIK
  883|    124|    if(!ParseSignedInt(szCurrent, &szCurrent, end, (int&)bone.iParent))  {
  ------------------
  |  Branch (883:8): [True: 89, False: 35]
  ------------------
  884|     89|        LogErrorNoThrow("Unexpected EOF/EOL while parsing bone parent index. Assuming -1");
  885|     89|        SMDI_PARSE_RETURN;
  ------------------
  |  |  832|     89|#define SMDI_PARSE_RETURN { \
  |  |  833|     89|    SkipLine(szCurrent,&szCurrent, end); \
  |  |  834|     89|    *szCurrentOut = szCurrent; \
  |  |  835|     89|    return; \
  |  |  836|     89|}
  ------------------
  886|      0|    }
  887|       |
  888|       |    // go to the beginning of the next line
  889|     35|    SMDI_PARSE_RETURN;
  ------------------
  |  |  832|     35|#define SMDI_PARSE_RETURN { \
  |  |  833|     35|    SkipLine(szCurrent,&szCurrent, end); \
  |  |  834|     35|    *szCurrentOut = szCurrent; \
  |  |  835|     35|    return; \
  |  |  836|     35|}
  ------------------
  890|      0|}
_ZN6Assimp11SMDImporter20ParseSkeletonElementEPKcPS2_S2_i:
  894|     14|void SMDImporter::ParseSkeletonElement(const char *szCurrent, const char **szCurrentOut, const char *end, int iTime) {
  895|     14|    aiVector3D vPos;
  896|     14|    aiVector3D vRot;
  897|       |
  898|     14|    unsigned int iBone  = 0;
  899|     14|    if (!ParseUnsignedInt(szCurrent, &szCurrent, end, iBone)) {
  ------------------
  |  Branch (899:9): [True: 0, False: 14]
  ------------------
  900|      0|        ASSIMP_LOG_ERROR("Unexpected EOF/EOL while parsing bone index");
  901|      0|        SMDI_PARSE_RETURN;
  ------------------
  |  |  832|      0|#define SMDI_PARSE_RETURN { \
  |  |  833|      0|    SkipLine(szCurrent,&szCurrent, end); \
  |  |  834|      0|    *szCurrentOut = szCurrent; \
  |  |  835|      0|    return; \
  |  |  836|      0|}
  ------------------
  902|      0|    }
  903|     14|    if (iBone >= asBones.size()) {
  ------------------
  |  Branch (903:9): [True: 0, False: 14]
  ------------------
  904|      0|        LogErrorNoThrow("Bone index in skeleton section is out of range");
  905|      0|        SMDI_PARSE_RETURN;
  ------------------
  |  |  832|      0|#define SMDI_PARSE_RETURN { \
  |  |  833|      0|    SkipLine(szCurrent,&szCurrent, end); \
  |  |  834|      0|    *szCurrentOut = szCurrent; \
  |  |  835|      0|    return; \
  |  |  836|      0|}
  ------------------
  906|      0|    }
  907|     14|    SMD::Bone& bone = asBones[iBone];
  908|       |
  909|     14|    bone.sAnim.asKeys.emplace_back();
  910|     14|    SMD::Bone::Animation::MatrixKey& key = bone.sAnim.asKeys.back();
  911|       |
  912|     14|    key.dTime = (double)iTime;
  913|     14|    if(!ParseFloat(szCurrent, &szCurrent, end, (float&)vPos.x)) {
  ------------------
  |  Branch (913:8): [True: 7, False: 7]
  ------------------
  914|      7|        LogErrorNoThrow("Unexpected EOF/EOL while parsing bone.pos.x");
  915|      7|        SMDI_PARSE_RETURN;
  ------------------
  |  |  832|      7|#define SMDI_PARSE_RETURN { \
  |  |  833|      7|    SkipLine(szCurrent,&szCurrent, end); \
  |  |  834|      7|    *szCurrentOut = szCurrent; \
  |  |  835|      7|    return; \
  |  |  836|      7|}
  ------------------
  916|      0|    }
  917|      7|    if(!ParseFloat(szCurrent, &szCurrent, end, (float&)vPos.y)) {
  ------------------
  |  Branch (917:8): [True: 0, False: 7]
  ------------------
  918|      0|        LogErrorNoThrow("Unexpected EOF/EOL while parsing bone.pos.y");
  919|      0|        SMDI_PARSE_RETURN;
  ------------------
  |  |  832|      0|#define SMDI_PARSE_RETURN { \
  |  |  833|      0|    SkipLine(szCurrent,&szCurrent, end); \
  |  |  834|      0|    *szCurrentOut = szCurrent; \
  |  |  835|      0|    return; \
  |  |  836|      0|}
  ------------------
  920|      0|    }
  921|      7|    if(!ParseFloat(szCurrent, &szCurrent, end, (float&)vPos.z)) {
  ------------------
  |  Branch (921:8): [True: 0, False: 7]
  ------------------
  922|      0|        LogErrorNoThrow("Unexpected EOF/EOL while parsing bone.pos.z");
  923|      0|        SMDI_PARSE_RETURN;
  ------------------
  |  |  832|      0|#define SMDI_PARSE_RETURN { \
  |  |  833|      0|    SkipLine(szCurrent,&szCurrent, end); \
  |  |  834|      0|    *szCurrentOut = szCurrent; \
  |  |  835|      0|    return; \
  |  |  836|      0|}
  ------------------
  924|      0|    }
  925|      7|    if(!ParseFloat(szCurrent, &szCurrent, end, (float&)vRot.x)) {
  ------------------
  |  Branch (925:8): [True: 0, False: 7]
  ------------------
  926|      0|        LogErrorNoThrow("Unexpected EOF/EOL while parsing bone.rot.x");
  927|      0|        SMDI_PARSE_RETURN;
  ------------------
  |  |  832|      0|#define SMDI_PARSE_RETURN { \
  |  |  833|      0|    SkipLine(szCurrent,&szCurrent, end); \
  |  |  834|      0|    *szCurrentOut = szCurrent; \
  |  |  835|      0|    return; \
  |  |  836|      0|}
  ------------------
  928|      0|    }
  929|      7|    if(!ParseFloat(szCurrent, &szCurrent, end, (float&)vRot.y)) {
  ------------------
  |  Branch (929:8): [True: 0, False: 7]
  ------------------
  930|      0|        LogErrorNoThrow("Unexpected EOF/EOL while parsing bone.rot.y");
  931|      0|        SMDI_PARSE_RETURN;
  ------------------
  |  |  832|      0|#define SMDI_PARSE_RETURN { \
  |  |  833|      0|    SkipLine(szCurrent,&szCurrent, end); \
  |  |  834|      0|    *szCurrentOut = szCurrent; \
  |  |  835|      0|    return; \
  |  |  836|      0|}
  ------------------
  932|      0|    }
  933|      7|    if(!ParseFloat(szCurrent, &szCurrent, end, (float&)vRot.z)) {
  ------------------
  |  Branch (933:8): [True: 0, False: 7]
  ------------------
  934|      0|        LogErrorNoThrow("Unexpected EOF/EOL while parsing bone.rot.z");
  935|      0|        SMDI_PARSE_RETURN;
  ------------------
  |  |  832|      0|#define SMDI_PARSE_RETURN { \
  |  |  833|      0|    SkipLine(szCurrent,&szCurrent, end); \
  |  |  834|      0|    *szCurrentOut = szCurrent; \
  |  |  835|      0|    return; \
  |  |  836|      0|}
  ------------------
  936|      0|    }
  937|       |    // build the transformation matrix of the key
  938|      7|    key.matrix.FromEulerAnglesXYZ(vRot.x,vRot.y,vRot.z); {
  939|      7|        aiMatrix4x4 mTemp;
  940|      7|        mTemp.a4 = vPos.x;
  941|      7|        mTemp.b4 = vPos.y;
  942|      7|        mTemp.c4 = vPos.z;
  943|      7|        key.matrix = mTemp * key.matrix;
  944|      7|    }
  945|      7|    key.vPos = vPos;
  946|      7|    key.vRot = vRot;
  947|       |    // go to the beginning of the next line
  948|      7|    SMDI_PARSE_RETURN;
  ------------------
  |  |  832|      7|#define SMDI_PARSE_RETURN { \
  |  |  833|      7|    SkipLine(szCurrent,&szCurrent, end); \
  |  |  834|      7|    *szCurrentOut = szCurrent; \
  |  |  835|      7|    return; \
  |  |  836|      7|}
  ------------------
  949|      0|}
_ZN6Assimp11SMDImporter13ParseTriangleEPKcPS2_S2_:
  953|  15.2k|void SMDImporter::ParseTriangle(const char *szCurrent, const char **szCurrentOut, const char *end) {
  954|  15.2k|    asTriangles.emplace_back();
  955|  15.2k|    SMD::Face& face = asTriangles.back();
  956|       |
  957|  15.2k|    if(!SkipSpaces(szCurrent, &szCurrent, end)) {
  ------------------
  |  Branch (957:8): [True: 0, False: 15.2k]
  ------------------
  958|      0|        LogErrorNoThrow("Unexpected EOF/EOL while parsing a triangle");
  959|      0|        return;
  960|      0|    }
  961|       |
  962|       |    // read the texture file name
  963|  15.2k|    const char* szLast = szCurrent;
  964|   269k|    while (!IsSpaceOrNewLine(*++szCurrent));
  ------------------
  |  Branch (964:12): [True: 254k, False: 15.2k]
  ------------------
  965|       |
  966|       |    // ... and get the index that belongs to this file name
  967|  15.2k|    face.iTexture = GetTextureIndex(std::string(szLast,(uintptr_t)szCurrent-(uintptr_t)szLast));
  968|       |
  969|  15.2k|    SkipSpacesAndLineEnd(szCurrent, &szCurrent, end);
  970|       |
  971|       |    // load three vertices
  972|  45.8k|    for (auto &avVertex : face.avVertices) {
  ------------------
  |  Branch (972:25): [True: 45.8k, False: 15.2k]
  ------------------
  973|  45.8k|        ParseVertex(szCurrent, &szCurrent, end, avVertex);
  974|  45.8k|    }
  975|  15.2k|    *szCurrentOut = szCurrent;
  976|  15.2k|}
_ZN6Assimp11SMDImporter10ParseFloatEPKcPS2_S2_Rf:
  980|  50.9k|bool SMDImporter::ParseFloat(const char *szCurrent, const char **szCurrentOut, const char *end, float &out) {
  981|  50.9k|    if (!SkipSpaces(&szCurrent, end)) {
  ------------------
  |  Branch (981:9): [True: 30.5k, False: 20.3k]
  ------------------
  982|  30.5k|        return false;
  983|  30.5k|    }
  984|       |
  985|  20.3k|    *szCurrentOut = fast_atoreal_move(szCurrent,out);
  986|  20.3k|    return true;
  987|  50.9k|}
_ZN6Assimp11SMDImporter16ParseUnsignedIntEPKcPS2_S2_Rj:
  991|    138|bool SMDImporter::ParseUnsignedInt(const char *szCurrent, const char **szCurrentOut, const char *end, unsigned int &out) {
  992|    138|    if(!SkipSpaces(&szCurrent, end)) {
  ------------------
  |  Branch (992:8): [True: 0, False: 138]
  ------------------
  993|      0|        return false;
  994|      0|    }
  995|       |
  996|    138|    out = strtoul10(szCurrent,szCurrentOut);
  997|    138|    return true;
  998|    138|}
_ZN6Assimp11SMDImporter14ParseSignedIntEPKcPS2_S2_Ri:
 1002|  45.9k|bool SMDImporter::ParseSignedInt(const char *szCurrent, const char **szCurrentOut, const char *end, int &out) {
 1003|  45.9k|    if(!SkipSpaces(&szCurrent, end)) {
  ------------------
  |  Branch (1003:8): [True: 15.3k, False: 30.5k]
  ------------------
 1004|  15.3k|        return false;
 1005|  15.3k|    }
 1006|       |
 1007|  30.5k|    out = strtol10(szCurrent,szCurrentOut);
 1008|  30.5k|    return true;
 1009|  45.9k|}
_ZN6Assimp11SMDImporter11ParseVertexEPKcPS2_S2_RNS_3SMD6VertexEb:
 1015|  45.8k|        bool bVASection /*= false*/) {
 1016|  45.8k|    if (SkipSpaces(&szCurrent, end) && IsLineEnd(*szCurrent)) {
  ------------------
  |  Branch (1016:9): [True: 30.5k, False: 15.2k]
  |  Branch (1016:40): [True: 0, False: 30.5k]
  ------------------
 1017|      0|        SkipSpacesAndLineEnd(szCurrent,&szCurrent, end);
 1018|      0|        return ParseVertex(szCurrent, szCurrentOut, end, vertex, bVASection);
 1019|      0|    }
 1020|  45.8k|    if(!ParseSignedInt(szCurrent, &szCurrent, end, (int&)vertex.iParentNode)) {
  ------------------
  |  Branch (1020:8): [True: 15.2k, False: 30.5k]
  ------------------
 1021|  15.2k|        LogErrorNoThrow("Unexpected EOF/EOL while parsing vertex.parent");
 1022|  15.2k|        SMDI_PARSE_RETURN;
  ------------------
  |  |  832|  15.2k|#define SMDI_PARSE_RETURN { \
  |  |  833|  15.2k|    SkipLine(szCurrent,&szCurrent, end); \
  |  |  834|  15.2k|    *szCurrentOut = szCurrent; \
  |  |  835|  15.2k|    return; \
  |  |  836|  15.2k|}
  ------------------
 1023|      0|    }
 1024|  30.5k|    if(!ParseFloat(szCurrent, &szCurrent, end, (float&)vertex.pos.x)) {
  ------------------
  |  Branch (1024:8): [True: 20.3k, False: 10.1k]
  ------------------
 1025|  20.3k|        LogErrorNoThrow("Unexpected EOF/EOL while parsing vertex.pos.x");
 1026|  20.3k|        SMDI_PARSE_RETURN;
  ------------------
  |  |  832|  20.3k|#define SMDI_PARSE_RETURN { \
  |  |  833|  20.3k|    SkipLine(szCurrent,&szCurrent, end); \
  |  |  834|  20.3k|    *szCurrentOut = szCurrent; \
  |  |  835|  20.3k|    return; \
  |  |  836|  20.3k|}
  ------------------
 1027|      0|    }
 1028|  10.1k|    if(!ParseFloat(szCurrent, &szCurrent, end, (float&)vertex.pos.y)) {
  ------------------
  |  Branch (1028:8): [True: 5.09k, False: 5.09k]
  ------------------
 1029|  5.09k|        LogErrorNoThrow("Unexpected EOF/EOL while parsing vertex.pos.y");
 1030|  5.09k|        SMDI_PARSE_RETURN;
  ------------------
  |  |  832|  5.09k|#define SMDI_PARSE_RETURN { \
  |  |  833|  5.09k|    SkipLine(szCurrent,&szCurrent, end); \
  |  |  834|  5.09k|    *szCurrentOut = szCurrent; \
  |  |  835|  5.09k|    return; \
  |  |  836|  5.09k|}
  ------------------
 1031|      0|    }
 1032|  5.09k|    if(!ParseFloat(szCurrent, &szCurrent, end, (float&)vertex.pos.z)) {
  ------------------
  |  Branch (1032:8): [True: 0, False: 5.09k]
  ------------------
 1033|      0|        LogErrorNoThrow("Unexpected EOF/EOL while parsing vertex.pos.z");
 1034|      0|        SMDI_PARSE_RETURN;
  ------------------
  |  |  832|      0|#define SMDI_PARSE_RETURN { \
  |  |  833|      0|    SkipLine(szCurrent,&szCurrent, end); \
  |  |  834|      0|    *szCurrentOut = szCurrent; \
  |  |  835|      0|    return; \
  |  |  836|      0|}
  ------------------
 1035|      0|    }
 1036|  5.09k|    if(!ParseFloat(szCurrent,&szCurrent,end, (float&)vertex.nor.x)) {
  ------------------
  |  Branch (1036:8): [True: 5.09k, False: 0]
  ------------------
 1037|  5.09k|        LogErrorNoThrow("Unexpected EOF/EOL while parsing vertex.nor.x");
 1038|  5.09k|        SMDI_PARSE_RETURN;
  ------------------
  |  |  832|  5.09k|#define SMDI_PARSE_RETURN { \
  |  |  833|  5.09k|    SkipLine(szCurrent,&szCurrent, end); \
  |  |  834|  5.09k|    *szCurrentOut = szCurrent; \
  |  |  835|  5.09k|    return; \
  |  |  836|  5.09k|}
  ------------------
 1039|      0|    }
 1040|      0|    if(!ParseFloat(szCurrent,&szCurrent, end, (float&)vertex.nor.y)) {
  ------------------
  |  Branch (1040:8): [True: 0, False: 0]
  ------------------
 1041|      0|        LogErrorNoThrow("Unexpected EOF/EOL while parsing vertex.nor.y");
 1042|      0|        SMDI_PARSE_RETURN;
  ------------------
  |  |  832|      0|#define SMDI_PARSE_RETURN { \
  |  |  833|      0|    SkipLine(szCurrent,&szCurrent, end); \
  |  |  834|      0|    *szCurrentOut = szCurrent; \
  |  |  835|      0|    return; \
  |  |  836|      0|}
  ------------------
 1043|      0|    }
 1044|      0|    if(!ParseFloat(szCurrent, &szCurrent, end, (float&)vertex.nor.z)) {
  ------------------
  |  Branch (1044:8): [True: 0, False: 0]
  ------------------
 1045|      0|        LogErrorNoThrow("Unexpected EOF/EOL while parsing vertex.nor.z");
 1046|      0|        SMDI_PARSE_RETURN;
  ------------------
  |  |  832|      0|#define SMDI_PARSE_RETURN { \
  |  |  833|      0|    SkipLine(szCurrent,&szCurrent, end); \
  |  |  834|      0|    *szCurrentOut = szCurrent; \
  |  |  835|      0|    return; \
  |  |  836|      0|}
  ------------------
 1047|      0|    }
 1048|       |
 1049|      0|    if (bVASection) {
  ------------------
  |  Branch (1049:9): [True: 0, False: 0]
  ------------------
 1050|      0|        SMDI_PARSE_RETURN;
  ------------------
  |  |  832|      0|#define SMDI_PARSE_RETURN { \
  |  |  833|      0|    SkipLine(szCurrent,&szCurrent, end); \
  |  |  834|      0|    *szCurrentOut = szCurrent; \
  |  |  835|      0|    return; \
  |  |  836|      0|}
  ------------------
 1051|      0|    }
 1052|       |
 1053|      0|    if(!ParseFloat(szCurrent, &szCurrent, end, (float&)vertex.uv.x)) {
  ------------------
  |  Branch (1053:8): [True: 0, False: 0]
  ------------------
 1054|      0|        LogErrorNoThrow("Unexpected EOF/EOL while parsing vertex.uv.x");
 1055|      0|        SMDI_PARSE_RETURN;
  ------------------
  |  |  832|      0|#define SMDI_PARSE_RETURN { \
  |  |  833|      0|    SkipLine(szCurrent,&szCurrent, end); \
  |  |  834|      0|    *szCurrentOut = szCurrent; \
  |  |  835|      0|    return; \
  |  |  836|      0|}
  ------------------
 1056|      0|    }
 1057|      0|    if(!ParseFloat(szCurrent, &szCurrent, end, (float&)vertex.uv.y)) {
  ------------------
  |  Branch (1057:8): [True: 0, False: 0]
  ------------------
 1058|      0|        LogErrorNoThrow("Unexpected EOF/EOL while parsing vertex.uv.y");
 1059|      0|        SMDI_PARSE_RETURN;
  ------------------
  |  |  832|      0|#define SMDI_PARSE_RETURN { \
  |  |  833|      0|    SkipLine(szCurrent,&szCurrent, end); \
  |  |  834|      0|    *szCurrentOut = szCurrent; \
  |  |  835|      0|    return; \
  |  |  836|      0|}
  ------------------
 1060|      0|    }
 1061|       |
 1062|       |    // now read the number of bones affecting this vertex
 1063|       |    // all elements from now are fully optional, we don't need them
 1064|      0|    unsigned int iSize = 0;
 1065|      0|    if(!ParseUnsignedInt(szCurrent, &szCurrent, end, iSize)) {
  ------------------
  |  Branch (1065:8): [True: 0, False: 0]
  ------------------
 1066|      0|        SMDI_PARSE_RETURN;
  ------------------
  |  |  832|      0|#define SMDI_PARSE_RETURN { \
  |  |  833|      0|    SkipLine(szCurrent,&szCurrent, end); \
  |  |  834|      0|    *szCurrentOut = szCurrent; \
  |  |  835|      0|    return; \
  |  |  836|      0|}
  ------------------
 1067|      0|    }
 1068|      0|    vertex.aiBoneLinks.resize(iSize,std::pair<unsigned int, float>(0,0.0f));
 1069|       |
 1070|      0|    for (auto &aiBoneLink : vertex.aiBoneLinks) {
  ------------------
  |  Branch (1070:27): [True: 0, False: 0]
  ------------------
 1071|      0|        if(!ParseUnsignedInt(szCurrent, &szCurrent, end, aiBoneLink.first)) {
  ------------------
  |  Branch (1071:12): [True: 0, False: 0]
  ------------------
 1072|      0|            SMDI_PARSE_RETURN;
  ------------------
  |  |  832|      0|#define SMDI_PARSE_RETURN { \
  |  |  833|      0|    SkipLine(szCurrent,&szCurrent, end); \
  |  |  834|      0|    *szCurrentOut = szCurrent; \
  |  |  835|      0|    return; \
  |  |  836|      0|}
  ------------------
 1073|      0|        }
 1074|      0|        if(!ParseFloat(szCurrent, &szCurrent, end, aiBoneLink.second)) {
  ------------------
  |  Branch (1074:12): [True: 0, False: 0]
  ------------------
 1075|      0|            SMDI_PARSE_RETURN;
  ------------------
  |  |  832|      0|#define SMDI_PARSE_RETURN { \
  |  |  833|      0|    SkipLine(szCurrent,&szCurrent, end); \
  |  |  834|      0|    *szCurrentOut = szCurrent; \
  |  |  835|      0|    return; \
  |  |  836|      0|}
  ------------------
 1076|      0|        }
 1077|      0|    }
 1078|       |
 1079|       |    // go to the beginning of the next line
 1080|      0|    SMDI_PARSE_RETURN;
  ------------------
  |  |  832|      0|#define SMDI_PARSE_RETURN { \
  |  |  833|      0|    SkipLine(szCurrent,&szCurrent, end); \
  |  |  834|      0|    *szCurrentOut = szCurrent; \
  |  |  835|      0|    return; \
  |  |  836|      0|}
  ------------------
 1081|      0|}

_ZN6Assimp3SMD6VertexC2Ev:
   68|  45.8k|    Vertex() AI_NO_EXCEPT : iParentNode(UINT_MAX) {
   69|       |        // empty
   70|  45.8k|    }
_ZN6Assimp3SMD4FaceC2Ev:
   90|  15.2k|            iTexture(0x0) {
   91|       |        // empty
   92|  15.2k|    }
_ZN6Assimp3SMD4BoneC2Ev:
  106|     55|    Bone() AI_NO_EXCEPT : iParent(UINT_MAX), bIsUsed(false) {
  107|       |        // empty
  108|     55|    }
_ZN6Assimp3SMD4Bone9AnimationC2Ev:
  119|     55|        Animation() AI_NO_EXCEPT : iFirstTimeKey() {
  120|     55|            asKeys.reserve(20);
  121|     55|        }
_ZN6Assimp11SMDImporter8SkipLineEPKcPS2_S2_:
  330|  6.48M|    inline bool SkipLine( const char* in, const char** out, const char *end) {
  331|  6.48M|        Assimp::SkipLine(in, out, end);
  332|  6.48M|        ++iLineNumber;
  333|  6.48M|        return true;
  334|  6.48M|    }
_ZN6Assimp11SMDImporter20SkipSpacesAndLineEndEPKcPS2_S2_:
  336|  6.48M|    inline bool SkipSpacesAndLineEnd(const char *in, const char **out, const char *end) {
  337|  6.48M|        ++iLineNumber;
  338|  6.48M|        return Assimp::SkipSpacesAndLineEnd(in, out, end);
  339|  6.48M|    }
_ZN6Assimp11SMDImporterD2Ev:
  165|    624|    ~SMDImporter() override = default;

_ZN6Assimp4STEP12StringToUTF8ERNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEE:
  284|      4|{
  285|       |    // very basic handling for escaped string sequences
  286|       |    // http://doc.spatial.com/index.php?title=InterOp:Connect/STEP&redirect=no
  287|       |
  288|     34|    for (size_t i = 0; i < s.size(); ) {
  ------------------
  |  Branch (288:24): [True: 32, False: 2]
  ------------------
  289|     32|        if (s[i] == '\\') {
  ------------------
  |  Branch (289:13): [True: 4, False: 28]
  ------------------
  290|       |            // \S\X - cp1252 (X is the character remapped to [0,127])
  291|      4|            if (i+3 < s.size() && s[i+1] == 'S' && s[i+2] == '\\') {
  ------------------
  |  Branch (291:17): [True: 4, False: 0]
  |  Branch (291:35): [True: 0, False: 4]
  |  Branch (291:52): [True: 0, False: 0]
  ------------------
  292|       |                // http://stackoverflow.com/questions/5586214/how-to-convert-char-from-iso-8859-1-to-utf-8-in-c-multiplatformly
  293|      0|                ai_assert((uint8_t)s[i+3] < 0x80);
  294|      0|                const uint8_t ch = s[i+3] + 0x80;
  295|       |
  296|      0|                s[i] = 0xc0 | (ch & 0xc0) >> 6;
  297|      0|                s[i+1] =  0x80 | (ch & 0x3f);
  298|       |
  299|      0|                s.erase(i + 2,2);
  300|      0|                ++i;
  301|      0|            }
  302|       |            // \X\xx - mac/roman (xx is a hex sequence)
  303|      4|            else if (i+4 < s.size() && s[i+1] == 'X' && s[i+2] == '\\') {
  ------------------
  |  Branch (303:22): [True: 4, False: 0]
  |  Branch (303:40): [True: 4, False: 0]
  |  Branch (303:57): [True: 0, False: 4]
  ------------------
  304|       |
  305|      0|                const uint8_t macval = HexOctetToDecimal(s.c_str() + i + 3);
  306|      0|                if(macval < 0x20) {
  ------------------
  |  Branch (306:20): [True: 0, False: 0]
  ------------------
  307|      0|                    return false;
  308|      0|                }
  309|       |
  310|      0|                ai_assert(sizeof(mac_codetable) / sizeof(mac_codetable[0]) == 0x100-0x20);
  311|       |
  312|      0|                const uint32_t unival = mac_codetable[macval - 0x20], *univalp = &unival;
  313|       |
  314|      0|                unsigned char temp[5], *tempp = temp;
  315|      0|                ai_assert(sizeof( unsigned char ) == 1);
  316|       |
  317|      0|                utf8::utf32to8( univalp, univalp + 1, tempp );
  318|       |
  319|      0|                const size_t outcount = static_cast<size_t>(tempp-temp);
  320|       |
  321|      0|                s.erase(i,5);
  322|      0|                s.insert(i, reinterpret_cast<char*>(temp), outcount);
  323|      0|                i += outcount;
  324|      0|            }
  325|       |            // \Xn\ .. \X0\ - various unicode encodings (n=2: utf16; n=4: utf32)
  326|      4|            else if (i+3 < s.size() && s[i+1] == 'X' && s[i+2] >= '0' && s[i+2] <= '9') {
  ------------------
  |  Branch (326:22): [True: 4, False: 0]
  |  Branch (326:40): [True: 4, False: 0]
  |  Branch (326:57): [True: 4, False: 0]
  |  Branch (326:74): [True: 4, False: 0]
  ------------------
  327|      4|                switch(s[i+2]) {
  328|       |                    // utf16
  329|      0|                case '2':
  ------------------
  |  Branch (329:17): [True: 0, False: 4]
  ------------------
  330|       |                    // utf32
  331|      4|                case '4':
  ------------------
  |  Branch (331:17): [True: 4, False: 0]
  ------------------
  332|      4|                    if (s[i+3] == '\\') {
  ------------------
  |  Branch (332:25): [True: 4, False: 0]
  ------------------
  333|      4|                        const size_t basei = i+4;
  334|      4|                        size_t j = basei, jend = s.size()-3;
  335|       |
  336|   105k|                        for (; j < jend; ++j) {
  ------------------
  |  Branch (336:32): [True: 105k, False: 0]
  ------------------
  337|   105k|                            if (s[j] == '\\' && s[j+1] == 'X' && s[j+2] == '0' && s[j+3] == '\\') {
  ------------------
  |  Branch (337:33): [True: 12, False: 105k]
  |  Branch (337:49): [True: 8, False: 4]
  |  Branch (337:66): [True: 4, False: 4]
  |  Branch (337:83): [True: 4, False: 0]
  ------------------
  338|      4|                                break;
  339|      4|                            }
  340|   105k|                        }
  341|      4|                        if (j == jend) {
  ------------------
  |  Branch (341:29): [True: 0, False: 4]
  ------------------
  342|      0|                            return false;
  343|      0|                        }
  344|       |
  345|      4|                        if (j == basei) {
  ------------------
  |  Branch (345:29): [True: 0, False: 4]
  ------------------
  346|      0|                            s.erase(i,8);
  347|      0|                            continue;
  348|      0|                        }
  349|       |
  350|      4|                        if (s[i+2] == '2') {
  ------------------
  |  Branch (350:29): [True: 0, False: 4]
  ------------------
  351|      0|                            if (((j - basei) % 4) != 0) {
  ------------------
  |  Branch (351:33): [True: 0, False: 0]
  ------------------
  352|      0|                                return false;
  353|      0|                            }
  354|       |
  355|      0|                            const size_t count = (j-basei)/4;
  356|      0|                            std::unique_ptr<uint16_t[]> src(new uint16_t[count]);
  357|       |
  358|      0|                            const char* cur = s.c_str() + basei;
  359|      0|                            for (size_t k = 0; k < count; ++k, cur += 4) {
  ------------------
  |  Branch (359:48): [True: 0, False: 0]
  ------------------
  360|      0|                                src[k] = (static_cast<uint16_t>(HexOctetToDecimal(cur)) << 8u)  |
  361|      0|                                     static_cast<uint16_t>(HexOctetToDecimal(cur+2));
  362|      0|                            }
  363|       |
  364|      0|                            const size_t dcount = count * 3; // this is enough to hold all possible outputs
  365|      0|                            std::unique_ptr<unsigned char[]> dest(new unsigned char[dcount]);
  366|       |
  367|      0|                            const uint16_t* srct = src.get();
  368|      0|                            unsigned char* destt = dest.get();
  369|      0|                            utf8::utf16to8( srct, srct + count, destt );
  370|       |
  371|      0|                            const size_t outcount = static_cast<size_t>(destt-dest.get());
  372|       |
  373|      0|                            s.erase(i,(j+4-i));
  374|       |
  375|      0|                            ai_assert(sizeof(unsigned char) == 1);
  376|      0|                            s.insert(i, reinterpret_cast<char*>(dest.get()), outcount);
  377|       |
  378|      0|                            i += outcount;
  379|      0|                            continue;
  380|      0|                        }
  381|      4|                        else if (s[i+2] == '4') {
  ------------------
  |  Branch (381:34): [True: 4, False: 0]
  ------------------
  382|      4|                            if (((j - basei) % 8) != 0) {
  ------------------
  |  Branch (382:33): [True: 2, False: 2]
  ------------------
  383|      2|                                return false;
  384|      2|                            }
  385|       |
  386|      2|                            const size_t count = (j-basei)/8;
  387|      2|                            std::unique_ptr<uint32_t[]> src(new uint32_t[count]);
  388|       |
  389|      2|                            const char* cur = s.c_str() + basei;
  390|  5.06k|                            for (size_t k = 0; k < count; ++k, cur += 8) {
  ------------------
  |  Branch (390:48): [True: 5.06k, False: 2]
  ------------------
  391|  5.06k|                                src[k] = (static_cast<uint32_t>(HexOctetToDecimal(cur  )) << 24u) |
  392|  5.06k|                                         (static_cast<uint32_t>(HexOctetToDecimal(cur+2)) << 16u) |
  393|  5.06k|                                         (static_cast<uint32_t>(HexOctetToDecimal(cur+4)) << 8u)  |
  394|  5.06k|                                         (static_cast<uint32_t>(HexOctetToDecimal(cur+6)));
  395|  5.06k|                            }
  396|       |
  397|      2|                            const size_t dcount = count * 5; // this is enough to hold all possible outputs
  398|      2|                            std::unique_ptr<unsigned char[]> dest(new unsigned char[dcount]);
  399|       |
  400|      2|                            const uint32_t* srct = src.get();
  401|      2|                            unsigned char* destt = dest.get();
  402|      2|                            utf8::utf32to8( srct, srct + count, destt );
  403|       |
  404|      2|                            const size_t outcount = static_cast<size_t>(destt-dest.get());
  405|       |
  406|      2|                            s.erase(i,(j+4-i));
  407|       |
  408|      2|                            ai_assert(sizeof(unsigned char) == 1);
  409|      2|                            s.insert(i, reinterpret_cast<char*>(dest.get()), outcount);
  410|       |
  411|      2|                            i += outcount;
  412|      2|                            continue;
  413|      4|                        }
  414|      4|                    }
  415|      0|                    break;
  416|       |
  417|       |                    // TODO: other encoding patterns?
  418|       |
  419|      0|                default:
  ------------------
  |  Branch (419:17): [True: 0, False: 4]
  ------------------
  420|      0|                    return false;
  421|      4|                }
  422|      4|            }
  423|      4|        }
  424|     28|        ++i;
  425|     28|    }
  426|      2|    return true;
  427|      4|}

_ZN6Assimp4STEP14ReadFileHeaderENSt3__110shared_ptrINS_8IOStreamEEE:
   84|      3|STEP::DB* STEP::ReadFileHeader(std::shared_ptr<IOStream> stream) {
   85|      3|    std::shared_ptr<StreamReaderLE> reader = std::shared_ptr<StreamReaderLE>(new StreamReaderLE(std::move(stream)));
   86|      3|    std::unique_ptr<STEP::DB> db = std::unique_ptr<STEP::DB>(new STEP::DB(reader));
   87|       |
   88|      3|    LineSplitter &splitter = db->GetSplitter();
   89|      3|    if (!splitter || *splitter != ISO_Token ) {
  ------------------
  |  Branch (89:9): [True: 0, False: 3]
  |  Branch (89:9): [True: 0, False: 3]
  |  Branch (89:22): [True: 0, False: 3]
  ------------------
   90|      0|        throw STEP::SyntaxError("expected magic token: " + std::string( ISO_Token ), 1);
   91|      0|    }
   92|       |
   93|      3|    HeaderInfo& head = db->GetHeader();
   94|  19.8k|    for(++splitter; splitter; ++splitter) {
  ------------------
  |  Branch (94:21): [True: 19.8k, False: 3]
  ------------------
   95|  19.8k|        const std::string& s = *splitter;
   96|  19.8k|        if (s == "DATA;") {
  ------------------
  |  Branch (96:13): [True: 0, False: 19.8k]
  ------------------
   97|       |            // here we go, header done, start of data section
   98|      0|            ++splitter;
   99|      0|            break;
  100|      0|        }
  101|       |
  102|       |        // want one-based line numbers for human readers, so +1
  103|  19.8k|        const uint64_t line = splitter.get_index()+1;
  104|       |
  105|  19.8k|        if (s.substr(0,11) == FILE_SCHEMA_Token) {
  ------------------
  |  Branch (105:13): [True: 23, False: 19.8k]
  ------------------
  106|     23|            const char* sz = s.c_str()+11;
  107|     23|            const char *end = s.c_str() + s.size();
  108|     23|            SkipSpaces(sz,&sz, end);
  109|     23|            std::shared_ptr< const EXPRESS::DataType > schema = EXPRESS::DataType::Parse(sz, end);
  110|       |
  111|       |            // the file schema should be a regular list entity, although it usually contains exactly one entry
  112|       |            // since the list itself is contained in a regular parameter list, we actually have
  113|       |            // two nested lists.
  114|     23|            const EXPRESS::LIST* list = dynamic_cast<const EXPRESS::LIST*>(schema.get());
  115|     23|            if (list && list->GetSize()) {
  ------------------
  |  Branch (115:17): [True: 4, False: 19]
  |  Branch (115:25): [True: 0, False: 4]
  ------------------
  116|      0|                list = dynamic_cast<const EXPRESS::LIST*>( (*list)[0].get() );
  117|      0|                if (!list) {
  ------------------
  |  Branch (117:21): [True: 0, False: 0]
  ------------------
  118|      0|                    throw STEP::SyntaxError("expected FILE_SCHEMA to be a list",line);
  119|      0|                }
  120|       |
  121|       |                // XXX need support for multiple schemas?
  122|      0|                if (list->GetSize() > 1)    {
  ------------------
  |  Branch (122:21): [True: 0, False: 0]
  ------------------
  123|      0|                    ASSIMP_LOG_WARN(AddLineNumber("multiple schemas currently not supported",line));
  124|      0|                }
  125|      0|                const EXPRESS::STRING *string = dynamic_cast<const EXPRESS::STRING *>((*list)[0].get());
  126|      0|                if (!list->GetSize() || nullptr == string ) {
  ------------------
  |  Branch (126:21): [True: 0, False: 0]
  |  Branch (126:41): [True: 0, False: 0]
  ------------------
  127|      0|                    throw STEP::SyntaxError("expected FILE_SCHEMA to contain a single string literal",line);
  128|      0|                }
  129|      0|                head.fileSchema =  *string;
  130|      0|            }
  131|     23|        }
  132|       |
  133|       |        // XXX handle more header fields
  134|  19.8k|    }
  135|       |
  136|      3|    return db.release();
  137|      3|}
_ZN6Assimp4STEP7EXPRESS8DataType5ParseERPKcS4_mPKNS1_16ConversionSchemaE:
  303|     23|{
  304|     23|    const char* cur = inout;
  305|     23|    SkipSpaces(&cur, end);
  306|     23|    if (*cur == ',' || IsSpaceOrNewLine(*cur)) {
  ------------------
  |  Branch (306:9): [True: 0, False: 23]
  |  Branch (306:24): [True: 0, False: 23]
  ------------------
  307|      0|        throw STEP::SyntaxError("unexpected token, expected parameter",line);
  308|      0|    }
  309|       |
  310|       |    // just skip over constructions such as IFCPLANEANGLEMEASURE(0.01) and read only the value
  311|     23|    if (schema) {
  ------------------
  |  Branch (311:9): [True: 0, False: 23]
  ------------------
  312|      0|        bool ok = false;
  313|      0|        for(const char* t = cur; *t && *t != ')' && *t != ','; ++t) {
  ------------------
  |  Branch (313:34): [True: 0, False: 0]
  |  Branch (313:40): [True: 0, False: 0]
  |  Branch (313:53): [True: 0, False: 0]
  ------------------
  314|      0|            if (*t=='(') {
  ------------------
  |  Branch (314:17): [True: 0, False: 0]
  ------------------
  315|      0|                if (!ok) {
  ------------------
  |  Branch (315:21): [True: 0, False: 0]
  ------------------
  316|      0|                    break;
  317|      0|                }
  318|      0|                for(--t;IsSpace(*t);--t);
  ------------------
  |  Branch (318:25): [True: 0, False: 0]
  ------------------
  319|      0|                std::string s(cur,static_cast<size_t>(t-cur+1));
  320|      0|                std::transform(s.begin(),s.end(),s.begin(),&ai_tolower<char> );
  321|      0|                if (schema->IsKnownToken(s)) {
  ------------------
  |  Branch (321:21): [True: 0, False: 0]
  ------------------
  322|      0|                    for(cur = t+1;*cur++ != '(';);
  ------------------
  |  Branch (322:35): [True: 0, False: 0]
  ------------------
  323|      0|                    std::shared_ptr<const EXPRESS::DataType> dt = Parse(cur, end);
  324|      0|                    inout = *cur ? cur+1 : cur;
  ------------------
  |  Branch (324:29): [True: 0, False: 0]
  ------------------
  325|      0|                    return dt;
  326|      0|                }
  327|      0|                break;
  328|      0|            }
  329|      0|            else if (!IsSpace(*t)) {
  ------------------
  |  Branch (329:22): [True: 0, False: 0]
  ------------------
  330|      0|                ok = true;
  331|      0|            }
  332|      0|        }
  333|      0|    }
  334|       |
  335|     23|    if (*cur == '*' ) {
  ------------------
  |  Branch (335:9): [True: 0, False: 23]
  ------------------
  336|      0|        inout = cur+1;
  337|      0|        return std::make_shared<EXPRESS::ISDERIVED>();
  338|      0|    }
  339|     23|    else if (*cur == '$' ) {
  ------------------
  |  Branch (339:14): [True: 0, False: 23]
  ------------------
  340|      0|        inout = cur+1;
  341|      0|        return std::make_shared<EXPRESS::UNSET>();
  342|      0|    }
  343|     23|    else if (*cur == '(' ) {
  ------------------
  |  Branch (343:14): [True: 4, False: 19]
  ------------------
  344|       |        // start of an aggregate, further parsing is done by the LIST factory constructor
  345|      4|        inout = cur;
  346|      4|        return EXPRESS::LIST::Parse(inout, end, line, schema);
  347|      4|    }
  348|     19|    else if (*cur == '.' ) {
  ------------------
  |  Branch (348:14): [True: 0, False: 19]
  ------------------
  349|       |        // enum (includes boolean)
  350|      0|        const char* start = ++cur;
  351|      0|        for(;*cur != '.';++cur) {
  ------------------
  |  Branch (351:14): [True: 0, False: 0]
  ------------------
  352|      0|            if (*cur == '\0') {
  ------------------
  |  Branch (352:17): [True: 0, False: 0]
  ------------------
  353|      0|                throw STEP::SyntaxError("enum not closed",line);
  354|      0|            }
  355|      0|        }
  356|      0|        inout = cur+1;
  357|      0|        return std::make_shared<EXPRESS::ENUMERATION>(std::string(start, static_cast<size_t>(cur-start) ));
  358|      0|    }
  359|     19|    else if (*cur == '#' ) {
  ------------------
  |  Branch (359:14): [True: 0, False: 19]
  ------------------
  360|       |        // object reference
  361|      0|        return std::make_shared<EXPRESS::ENTITY>(strtoul10_64(++cur,&inout));
  362|      0|    }
  363|     19|    else if (*cur == '\'' ) {
  ------------------
  |  Branch (363:14): [True: 4, False: 15]
  ------------------
  364|       |        // string literal
  365|      4|        const char* start = ++cur;
  366|       |
  367|   105k|        for(;*cur != '\'';++cur)    {
  ------------------
  |  Branch (367:14): [True: 105k, False: 4]
  ------------------
  368|   105k|            if (*cur == '\0')   {
  ------------------
  |  Branch (368:17): [True: 0, False: 105k]
  ------------------
  369|      0|                throw STEP::SyntaxError("string literal not closed",line);
  370|      0|            }
  371|   105k|        }
  372|       |
  373|      4|        if (cur[1] == '\'') {
  ------------------
  |  Branch (373:13): [True: 0, False: 4]
  ------------------
  374|       |            // Vesanen: more than 2 escaped ' in one literal!
  375|      0|            do  {
  376|      0|                for(cur += 2;*cur != '\'';++cur)    {
  ------------------
  |  Branch (376:30): [True: 0, False: 0]
  ------------------
  377|      0|                    if (*cur == '\0')   {
  ------------------
  |  Branch (377:25): [True: 0, False: 0]
  ------------------
  378|      0|                        throw STEP::SyntaxError("string literal not closed",line);
  379|      0|                    }
  380|      0|                }
  381|      0|            }
  382|      0|            while(cur[1] == '\'');
  ------------------
  |  Branch (382:19): [True: 0, False: 0]
  ------------------
  383|      0|        }
  384|       |
  385|      4|        inout = cur + 1;
  386|       |
  387|       |        // assimp is supposed to output UTF8 strings, so we have to deal
  388|       |        // with foreign encodings.
  389|      4|        std::string stemp = std::string(start, static_cast<size_t>(cur - start));
  390|      4|        if(!StringToUTF8(stemp)) {
  ------------------
  |  Branch (390:12): [True: 2, False: 2]
  ------------------
  391|       |            // TODO: route this to a correct logger with line numbers etc., better error messages
  392|      2|            ASSIMP_LOG_ERROR("an error occurred reading escape sequences in ASCII text");
  393|      2|        }
  394|       |
  395|      4|        return std::make_shared<EXPRESS::STRING>(stemp);
  396|      4|    }
  397|     15|    else if (*cur == '\"' ) {
  ------------------
  |  Branch (397:14): [True: 0, False: 15]
  ------------------
  398|      0|        throw STEP::SyntaxError("binary data not supported yet",line);
  399|      0|    }
  400|       |
  401|       |    // else -- must be a number. if there is a decimal dot in it,
  402|       |    // parse it as real value, otherwise as integer.
  403|     15|    const char* start = cur;
  404|     39|    for(;*cur  && *cur != ',' && *cur != ')' && !IsSpace(*cur);++cur) {
  ------------------
  |  Branch (404:10): [True: 39, False: 0]
  |  Branch (404:19): [True: 39, False: 0]
  |  Branch (404:34): [True: 24, False: 15]
  |  Branch (404:49): [True: 24, False: 0]
  ------------------
  405|     24|        if (*cur == '.') {
  ------------------
  |  Branch (405:13): [True: 0, False: 24]
  ------------------
  406|      0|            double f;
  407|      0|            inout = fast_atoreal_move(start,f);
  408|      0|            return std::make_shared<EXPRESS::REAL>(f);
  409|      0|        }
  410|     24|    }
  411|       |
  412|     15|    bool neg = false;
  413|     15|    if (*start == '-') {
  ------------------
  |  Branch (413:9): [True: 0, False: 15]
  ------------------
  414|      0|        neg = true;
  415|      0|        ++start;
  416|      0|    }
  417|     15|    else if (*start == '+') {
  ------------------
  |  Branch (417:14): [True: 0, False: 15]
  ------------------
  418|      0|        ++start;
  419|      0|    }
  420|     15|    int64_t num = static_cast<int64_t>( strtoul10_64(start,&inout) );
  421|     15|    return std::make_shared<EXPRESS::INTEGER>(neg?-num:num);
  ------------------
  |  Branch (421:47): [True: 0, False: 15]
  ------------------
  422|     15|}
_ZN6Assimp4STEP7EXPRESS4LIST5ParseERPKcS4_mPKNS1_16ConversionSchemaE:
  426|      4|        uint64_t line, const EXPRESS::ConversionSchema* schema) {
  427|      4|    const std::shared_ptr<EXPRESS::LIST> list = std::make_shared<EXPRESS::LIST>();
  428|      4|    EXPRESS::LIST::MemberList& cur_members = list->members;
  429|       |
  430|      4|    const char* cur = inout;
  431|      4|    if (*cur++ != '(') {
  ------------------
  |  Branch (431:9): [True: 0, False: 4]
  ------------------
  432|      0|        throw STEP::SyntaxError("unexpected token, expected \'(\' token at beginning of list",line);
  433|      0|    }
  434|       |
  435|       |    // estimate the number of items upfront - lists can grow large
  436|      4|    size_t count = 1;
  437|      4|    for(const char* c=cur; *c && *c != ')'; ++c) {
  ------------------
  |  Branch (437:28): [True: 4, False: 0]
  |  Branch (437:34): [True: 0, False: 4]
  ------------------
  438|      0|        count += (*c == ',' ? 1 : 0);
  ------------------
  |  Branch (438:19): [True: 0, False: 0]
  ------------------
  439|      0|    }
  440|       |
  441|      4|    cur_members.reserve(count);
  442|       |
  443|      4|    for(;;++cur) {
  444|      4|        if (!*cur) {
  ------------------
  |  Branch (444:13): [True: 0, False: 4]
  ------------------
  445|      0|            throw STEP::SyntaxError("unexpected end of line while reading list");
  446|      0|        }
  447|      4|        SkipSpaces(cur,&cur, end);
  448|      4|        if (*cur == ')') {
  ------------------
  |  Branch (448:13): [True: 4, False: 0]
  ------------------
  449|      4|            break;
  450|      4|        }
  451|       |
  452|      0|        cur_members.push_back(EXPRESS::DataType::Parse(cur, end, line, schema));
  453|      0|        SkipSpaces(cur, &cur, end);
  454|       |
  455|      0|        if (*cur != ',') {
  ------------------
  |  Branch (455:13): [True: 0, False: 0]
  ------------------
  456|      0|            if (*cur == ')') {
  ------------------
  |  Branch (456:17): [True: 0, False: 0]
  ------------------
  457|      0|                break;
  458|      0|            }
  459|      0|            throw STEP::SyntaxError("unexpected token, expected \',\' or \')\' token after list element",line);
  460|      0|        }
  461|      0|    }
  462|       |
  463|      4|    inout = cur + 1;
  464|      4|    return list;
  465|      4|}

_ZN6Assimp11STLImporterC2Ev:
  130|    624|        mFileSize(0),
  131|    624|        mScene() {
  132|       |    // empty
  133|    624|}
_ZN6Assimp11STLImporterD2Ev:
  137|    624|STLImporter::~STLImporter() = default;
_ZNK6Assimp11STLImporter7CanReadERKNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEPNS_8IOSystemEb:
  141|    402|bool STLImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool /*checkSig*/) const {
  142|    402|    static const char *tokens[] = { "STL", "solid" };
  143|       |    return SearchFileHeaderForToken(pIOHandler, pFile, tokens, AI_COUNT_OF(tokens));
  144|    402|}
_ZNK6Assimp11STLImporter7GetInfoEv:
  147|    641|const aiImporterDesc *STLImporter::GetInfo() const {
  148|    641|    return &desc;
  149|    641|}
_ZN6Assimp14addFacesToMeshEP6aiMesh:
  151|      6|void addFacesToMesh(aiMesh *pMesh) {
  152|      6|    pMesh->mFaces = new aiFace[pMesh->mNumFaces];
  153|  10.1k|    for (unsigned int i = 0, p = 0; i < pMesh->mNumFaces; ++i) {
  ------------------
  |  Branch (153:37): [True: 10.1k, False: 6]
  ------------------
  154|       |
  155|  10.1k|        aiFace &face = pMesh->mFaces[i];
  156|  10.1k|        face.mIndices = new unsigned int[face.mNumIndices = 3];
  157|  40.4k|        for (unsigned int o = 0; o < 3; ++o, ++p) {
  ------------------
  |  Branch (157:34): [True: 30.3k, False: 10.1k]
  ------------------
  158|  30.3k|            face.mIndices[o] = p;
  159|  30.3k|        }
  160|  10.1k|    }
  161|      6|}
_ZN6Assimp11STLImporter14InternReadFileERKNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEP7aiScenePNS_8IOSystemE:
  165|      7|void STLImporter::InternReadFile(const std::string &pFile, aiScene *pScene, IOSystem *pIOHandler) {
  166|      7|    std::unique_ptr<IOStream> file(pIOHandler->Open(pFile, "rb"));
  167|       |
  168|       |    // Check whether we can read from the file
  169|      7|    if (file == nullptr) {
  ------------------
  |  Branch (169:9): [True: 0, False: 7]
  ------------------
  170|      0|        throw DeadlyImportError("Failed to open STL file ", pFile, ".");
  171|      0|    }
  172|       |
  173|      7|    mFileSize = file->FileSize();
  174|       |
  175|       |    // allocate storage and copy the contents of the file to a memory buffer
  176|       |    // (terminate it with zero)
  177|      7|    std::vector<char> buffer2;
  178|      7|    TextFileToBuffer(file.get(), buffer2);
  179|       |
  180|      7|    mScene = pScene;
  181|      7|    mBuffer = &buffer2[0];
  182|       |
  183|       |    // the default vertex color is light gray.
  184|      7|    mClrColorDefault.r = mClrColorDefault.g = mClrColorDefault.b = mClrColorDefault.a = 0.6f;
  185|       |
  186|       |    // allocate a single node
  187|      7|    mScene->mRootNode = new aiNode();
  188|       |
  189|      7|    bool bMatClr = false;
  190|       |
  191|      7|    if (IsBinarySTL(mBuffer, mFileSize)) {
  ------------------
  |  Branch (191:9): [True: 2, False: 5]
  ------------------
  192|      2|        bMatClr = LoadBinaryFile();
  193|      5|    } else if (IsAsciiSTL(mBuffer, mFileSize)) {
  ------------------
  |  Branch (193:16): [True: 5, False: 0]
  ------------------
  194|      5|        LoadASCIIFile(mScene->mRootNode);
  195|      5|    } else {
  196|      0|        throw DeadlyImportError("Failed to determine STL storage representation for ", pFile, ".");
  197|      0|    }
  198|       |
  199|       |    // create a single default material, using a white diffuse color for consistency with
  200|       |    // other geometric types (e.g., PLY).
  201|      7|    aiMaterial *pcMat = new aiMaterial();
  202|      7|    aiString s;
  203|      7|    s.Set(AI_DEFAULT_MATERIAL_NAME);
  204|      7|    pcMat->AddProperty(&s, AI_MATKEY_NAME);
  205|       |
  206|      7|    aiColor4D clrDiffuse(ai_real(1.0), ai_real(1.0), ai_real(1.0), ai_real(1.0));
  207|      7|    if (bMatClr) {
  ------------------
  |  Branch (207:9): [True: 0, False: 7]
  ------------------
  208|      0|        clrDiffuse = mClrColorDefault;
  209|      0|    }
  210|      7|    pcMat->AddProperty(&clrDiffuse, 1, AI_MATKEY_COLOR_DIFFUSE);
  211|      7|    pcMat->AddProperty(&clrDiffuse, 1, AI_MATKEY_COLOR_SPECULAR);
  212|      7|    clrDiffuse = aiColor4D(0.05f, 0.05f, 0.05f, 1.0f);
  213|      7|    pcMat->AddProperty(&clrDiffuse, 1, AI_MATKEY_COLOR_AMBIENT);
  214|       |
  215|      7|    mScene->mNumMaterials = 1;
  216|      7|    mScene->mMaterials = new aiMaterial *[1];
  217|      7|    mScene->mMaterials[0] = pcMat;
  218|       |
  219|      7|    mBuffer = nullptr;
  220|      7|}
_ZN6Assimp11STLImporter13LoadASCIIFileEP6aiNode:
  224|      5|void STLImporter::LoadASCIIFile(aiNode *root) {
  225|      5|    std::vector<aiMesh *> meshes;
  226|      5|    std::vector<aiNode *> nodes;
  227|      5|    const char *sz = mBuffer;
  228|      5|    const char *bufferEnd = mBuffer + mFileSize;
  229|      5|    std::vector<aiVector3D> positionBuffer;
  230|      5|    std::vector<aiVector3D> normalBuffer;
  231|       |
  232|       |    // try to guess how many vertices we could have
  233|       |    // assume we'll need 160 bytes for each face
  234|      5|    size_t sizeEstimate = std::max(1ull, mFileSize / 160ull) * 3ull;
  235|      5|    positionBuffer.reserve(sizeEstimate);
  236|      5|    normalBuffer.reserve(sizeEstimate);
  237|       |
  238|     10|    while (IsAsciiSTL(sz, static_cast<unsigned int>(bufferEnd - sz))) {
  ------------------
  |  Branch (238:12): [True: 5, False: 5]
  ------------------
  239|      5|        std::vector<unsigned int> meshIndices;
  240|      5|        aiMesh *pMesh = new aiMesh();
  241|      5|        pMesh->mMaterialIndex = 0;
  242|      5|        meshIndices.push_back((unsigned int)meshes.size());
  243|      5|        meshes.push_back(pMesh);
  244|      5|        aiNode *node = new aiNode;
  245|      5|        node->mParent = root;
  246|      5|        nodes.push_back(node);
  247|      5|        SkipSpaces(&sz, bufferEnd);
  248|      5|        ai_assert(!IsLineEnd(sz));
  249|       |
  250|      5|        sz += 5; // skip the "solid"
  251|      5|        SkipSpaces(&sz, bufferEnd);
  252|      5|        const char *szMe = sz;
  253|     56|        while (!IsSpaceOrNewLine(*sz)) {
  ------------------
  |  Branch (253:16): [True: 51, False: 5]
  ------------------
  254|     51|            sz++;
  255|     51|        }
  256|       |
  257|      5|        size_t temp = (size_t)(sz - szMe);
  258|       |        // setup the name of the node
  259|      5|        if (temp) {
  ------------------
  |  Branch (259:13): [True: 5, False: 0]
  ------------------
  260|      5|            if (temp >= AI_MAXLEN) {
  ------------------
  |  Branch (260:17): [True: 0, False: 5]
  ------------------
  261|      0|                throw DeadlyImportError("STL: Node name too long");
  262|      0|            }
  263|      5|            std::string name(szMe, temp);
  264|      5|            node->mName.Set(name.c_str());
  265|      5|            pMesh->mName.Set(name.c_str());
  266|      5|        } else {
  267|      0|            mScene->mRootNode->mName.Set("<STL_ASCII>");
  268|      0|        }
  269|       |
  270|      5|        unsigned int faceVertexCounter = 3;
  271|  39.3k|        for (;;) {
  272|       |            // go to the next token
  273|  39.3k|            if (!SkipSpacesAndLineEnd(&sz, bufferEnd)) {
  ------------------
  |  Branch (273:17): [True: 0, False: 39.3k]
  ------------------
  274|       |                // seems we're finished although there was no end marker
  275|      0|                ASSIMP_LOG_WARN("STL: unexpected EOF. \'endsolid\' keyword was expected");
  276|      0|                break;
  277|      0|            }
  278|       |            // facet normal -0.13 -0.13 -0.98
  279|  39.3k|            if (!strncmp(sz, "facet", 5) && IsSpaceOrNewLine(*(sz + 5)) && *(sz + 5) != '\0') {
  ------------------
  |  Branch (279:17): [True: 4.88k, False: 34.4k]
  |  Branch (279:45): [True: 4.88k, False: 0]
  |  Branch (279:76): [True: 4.88k, False: 0]
  ------------------
  280|       |
  281|  4.88k|                if (faceVertexCounter != 3) {
  ------------------
  |  Branch (281:21): [True: 0, False: 4.88k]
  ------------------
  282|      0|                    ASSIMP_LOG_WARN("STL: A new facet begins but the old is not yet complete");
  283|      0|                }
  284|  4.88k|                faceVertexCounter = 0;
  285|       |
  286|  4.88k|                sz += 6;
  287|  4.88k|                SkipSpaces(&sz, bufferEnd);
  288|  4.88k|                if (strncmp(sz, "normal", 6)) {
  ------------------
  |  Branch (288:21): [True: 0, False: 4.88k]
  ------------------
  289|      0|                    ASSIMP_LOG_WARN("STL: a facet normal vector was expected but not found");
  290|  4.88k|                } else {
  291|  4.88k|                    if (sz[6] == '\0') {
  ------------------
  |  Branch (291:25): [True: 0, False: 4.88k]
  ------------------
  292|      0|                        throw DeadlyImportError("STL: unexpected EOF while parsing facet");
  293|      0|                    }
  294|  4.88k|                    aiVector3D vn;
  295|  4.88k|                    sz += 7;
  296|  4.88k|                    SkipSpaces(&sz, bufferEnd);
  297|  4.88k|                    sz = fast_atoreal_move(sz, vn.x);
  298|  4.88k|                    SkipSpaces(&sz, bufferEnd);
  299|  4.88k|                    sz = fast_atoreal_move(sz, vn.y);
  300|  4.88k|                    SkipSpaces(&sz, bufferEnd);
  301|  4.88k|                    sz = fast_atoreal_move(sz, vn.z);
  302|  4.88k|                    normalBuffer.emplace_back(vn);
  303|  4.88k|                    normalBuffer.emplace_back(vn);
  304|  4.88k|                    normalBuffer.emplace_back(vn);
  305|  4.88k|                }
  306|  34.4k|            } else if (!strncmp(sz, "vertex", 6) && IsSpaceOrNewLine(*(sz + 6))) { // vertex 1.50000 1.50000 0.00000
  ------------------
  |  Branch (306:24): [True: 14.6k, False: 19.8k]
  |  Branch (306:53): [True: 14.6k, False: 0]
  ------------------
  307|  14.6k|                if (faceVertexCounter >= 3) {
  ------------------
  |  Branch (307:21): [True: 0, False: 14.6k]
  ------------------
  308|      0|                    ASSIMP_LOG_ERROR("STL: a facet with more than 3 vertices has been found");
  309|      0|                    ++sz;
  310|  14.6k|                } else {
  311|  14.6k|                    if (sz[6] == '\0') {
  ------------------
  |  Branch (311:25): [True: 0, False: 14.6k]
  ------------------
  312|      0|                        throw DeadlyImportError("STL: unexpected EOF while parsing facet");
  313|      0|                    }
  314|  14.6k|                    sz += 7;
  315|  14.6k|                    SkipSpaces(&sz, bufferEnd);
  316|  14.6k|                    positionBuffer.emplace_back();
  317|  14.6k|                    aiVector3D *vn = &positionBuffer.back();
  318|  14.6k|                    sz = fast_atoreal_move(sz, vn->x);
  319|  14.6k|                    SkipSpaces(&sz, bufferEnd);
  320|  14.6k|                    sz = fast_atoreal_move(sz, vn->y);
  321|  14.6k|                    SkipSpaces(&sz, bufferEnd);
  322|  14.6k|                    sz = fast_atoreal_move(sz, vn->z);
  323|  14.6k|                    faceVertexCounter++;
  324|  14.6k|                }
  325|  19.8k|            } else if (!::strncmp(sz, "endsolid", 8)) {
  ------------------
  |  Branch (325:24): [True: 4, False: 19.8k]
  ------------------
  326|     59|                do {
  327|     59|                    ++sz;
  328|     59|                } while (!IsLineEnd(*sz));
  ------------------
  |  Branch (328:26): [True: 55, False: 4]
  ------------------
  329|      4|                SkipSpacesAndLineEnd(&sz, bufferEnd);
  330|       |                // finished!
  331|      4|                break;
  332|  19.8k|            } else { // else skip the whole identifier
  333|   118k|                do {
  334|   118k|                    ++sz;
  335|   118k|                } while (!IsSpaceOrNewLine(*sz));
  ------------------
  |  Branch (335:26): [True: 98.3k, False: 19.8k]
  ------------------
  336|  19.8k|            }
  337|  39.3k|        }
  338|       |
  339|      5|        if (positionBuffer.empty()) {
  ------------------
  |  Branch (339:13): [True: 0, False: 5]
  ------------------
  340|      0|            pMesh->mNumFaces = 0;
  341|      0|            ASSIMP_LOG_WARN("STL: mesh is empty or invalid; no data loaded");
  342|      0|        }
  343|      5|        if (positionBuffer.size() % 3 != 0) {
  ------------------
  |  Branch (343:13): [True: 0, False: 5]
  ------------------
  344|      0|            pMesh->mNumFaces = 0;
  345|      0|            throw DeadlyImportError("STL: Invalid number of vertices");
  346|      0|        }
  347|      5|        if (normalBuffer.size() != positionBuffer.size()) {
  ------------------
  |  Branch (347:13): [True: 0, False: 5]
  ------------------
  348|      0|            pMesh->mNumFaces = 0;
  349|      0|            throw DeadlyImportError("Normal buffer size does not match position buffer size");
  350|      0|        }
  351|       |
  352|       |        // only process position buffer when filled, else exception when accessing with index operator
  353|       |        // see line 353: only warning is triggered
  354|       |        // see line 373(now): access to empty position buffer with index operator forced exception
  355|      5|        if (!positionBuffer.empty()) {
  ------------------
  |  Branch (355:13): [True: 4, False: 1]
  ------------------
  356|      4|            pMesh->mNumFaces = static_cast<unsigned int>(positionBuffer.size() / 3);
  357|      4|            pMesh->mNumVertices = static_cast<unsigned int>(positionBuffer.size());
  358|      4|            pMesh->mVertices = new aiVector3D[pMesh->mNumVertices];
  359|  13.1k|            for (size_t i = 0; i < pMesh->mNumVertices; ++i) {
  ------------------
  |  Branch (359:32): [True: 13.1k, False: 4]
  ------------------
  360|  13.1k|                pMesh->mVertices[i].x = positionBuffer[i].x;
  361|  13.1k|                pMesh->mVertices[i].y = positionBuffer[i].y;
  362|  13.1k|                pMesh->mVertices[i].z = positionBuffer[i].z;
  363|  13.1k|            }
  364|      4|            positionBuffer.clear();
  365|      4|        }
  366|       |        // also only process normalBuffer when filled, else exception when accessing with index operator
  367|      5|        if (!normalBuffer.empty()) {
  ------------------
  |  Branch (367:13): [True: 4, False: 1]
  ------------------
  368|      4|            pMesh->mNormals = new aiVector3D[pMesh->mNumVertices];
  369|  13.1k|            for (size_t i = 0; i < pMesh->mNumVertices; ++i) {
  ------------------
  |  Branch (369:32): [True: 13.1k, False: 4]
  ------------------
  370|  13.1k|                pMesh->mNormals[i].x = normalBuffer[i].x;
  371|  13.1k|                pMesh->mNormals[i].y = normalBuffer[i].y;
  372|  13.1k|                pMesh->mNormals[i].z = normalBuffer[i].z;
  373|  13.1k|            }
  374|      4|            normalBuffer.clear();
  375|      4|        }
  376|       |
  377|       |        // now copy faces
  378|      5|        addFacesToMesh(pMesh);
  379|       |
  380|       |        // assign the meshes to the current node
  381|      5|        pushMeshesToNode(meshIndices, node);
  382|      5|    }
  383|       |
  384|       |    // now add the loaded meshes
  385|      5|    mScene->mNumMeshes = (unsigned int)meshes.size();
  386|      5|    mScene->mMeshes = new aiMesh *[mScene->mNumMeshes];
  387|      9|    for (size_t i = 0; i < meshes.size(); i++) {
  ------------------
  |  Branch (387:24): [True: 4, False: 5]
  ------------------
  388|      4|        mScene->mMeshes[i] = meshes[i];
  389|      4|    }
  390|       |
  391|      5|    root->mNumChildren = (unsigned int)nodes.size();
  392|      5|    root->mChildren = new aiNode *[root->mNumChildren];
  393|      9|    for (size_t i = 0; i < nodes.size(); ++i) {
  ------------------
  |  Branch (393:24): [True: 4, False: 5]
  ------------------
  394|      4|        root->mChildren[i] = nodes[i];
  395|      4|    }
  396|      5|}
_ZN6Assimp11STLImporter14LoadBinaryFileEv:
  400|      2|bool STLImporter::LoadBinaryFile() {
  401|       |    // allocate one mesh
  402|      2|    mScene->mNumMeshes = 1;
  403|      2|    mScene->mMeshes = new aiMesh *[1];
  404|      2|    aiMesh *pMesh = mScene->mMeshes[0] = new aiMesh();
  405|      2|    pMesh->mMaterialIndex = 0;
  406|       |
  407|       |    // skip the first 80 bytes
  408|      2|    if (mFileSize < 84) {
  ------------------
  |  Branch (408:9): [True: 0, False: 2]
  ------------------
  409|      0|        throw DeadlyImportError("STL: file is too small for the header");
  410|      0|    }
  411|      2|    bool bIsMaterialise = false;
  412|       |
  413|       |    // search for an occurrence of "COLOR=" in the header
  414|      2|    const unsigned char *sz2 = (const unsigned char *)mBuffer;
  415|      2|    const unsigned char *const szEnd = sz2 + 80;
  416|    162|    while (sz2 < szEnd) {
  ------------------
  |  Branch (416:12): [True: 160, False: 2]
  ------------------
  417|       |
  418|    160|        if ('C' == *sz2++ && 'O' == *sz2++ && 'L' == *sz2++ &&
  ------------------
  |  Branch (418:13): [True: 0, False: 160]
  |  Branch (418:30): [True: 0, False: 0]
  |  Branch (418:47): [True: 0, False: 0]
  ------------------
  419|      0|                'O' == *sz2++ && 'R' == *sz2++ && '=' == *sz2++) {
  ------------------
  |  Branch (419:17): [True: 0, False: 0]
  |  Branch (419:34): [True: 0, False: 0]
  |  Branch (419:51): [True: 0, False: 0]
  ------------------
  420|       |
  421|       |            // read the default vertex color for facets
  422|      0|            bIsMaterialise = true;
  423|      0|            ASSIMP_LOG_INFO("STL: Taking code path for Materialise files");
  424|      0|            const ai_real invByte = (ai_real)1.0 / (ai_real)255.0;
  425|      0|            mClrColorDefault.r = (*sz2++) * invByte;
  426|      0|            mClrColorDefault.g = (*sz2++) * invByte;
  427|      0|            mClrColorDefault.b = (*sz2++) * invByte;
  428|      0|            mClrColorDefault.a = (*sz2++) * invByte;
  429|      0|            break;
  430|      0|        }
  431|    160|    }
  432|      2|    const unsigned char *sz = (const unsigned char *)mBuffer + 80;
  433|       |
  434|       |    // now read the number of facets
  435|      2|    mScene->mRootNode->mName.Set("<STL_BINARY>");
  436|       |
  437|      2|    pMesh->mNumFaces = *((uint32_t *)sz);
  438|      2|    sz += 4;
  439|       |
  440|      2|    if (mFileSize < 84ull + pMesh->mNumFaces * 50ull) {
  ------------------
  |  Branch (440:9): [True: 0, False: 2]
  ------------------
  441|      0|        throw DeadlyImportError("STL: file is too small to hold all facets");
  442|      0|    }
  443|       |
  444|      2|    if (!pMesh->mNumFaces) {
  ------------------
  |  Branch (444:9): [True: 0, False: 2]
  ------------------
  445|      0|        throw DeadlyImportError("STL: file is empty. There are no facets defined");
  446|      0|    }
  447|       |
  448|      2|    pMesh->mNumVertices = pMesh->mNumFaces * 3;
  449|       |
  450|      2|    aiVector3D *vp = pMesh->mVertices = new aiVector3D[pMesh->mNumVertices];
  451|      2|    aiVector3D *vn = pMesh->mNormals = new aiVector3D[pMesh->mNumVertices];
  452|       |
  453|      2|    aiVector3f *theVec;
  454|      2|    aiVector3f theVec3F;
  455|       |
  456|  5.73k|    for (unsigned int i = 0; i < pMesh->mNumFaces; ++i) {
  ------------------
  |  Branch (456:30): [True: 5.73k, False: 2]
  ------------------
  457|       |        // NOTE: Blender sometimes writes empty normals ... this is not
  458|       |        // our fault ... the RemoveInvalidData helper step should fix that
  459|       |
  460|       |        // There's one normal for the face in the STL; use it three times
  461|       |        // for vertex normals
  462|  5.73k|        theVec = (aiVector3f *)sz;
  463|  5.73k|        ::memcpy(&theVec3F, theVec, sizeof(aiVector3f));
  464|  5.73k|        vn->x = theVec3F.x;
  465|  5.73k|        vn->y = theVec3F.y;
  466|  5.73k|        vn->z = theVec3F.z;
  467|  5.73k|        *(vn + 1) = *vn;
  468|  5.73k|        *(vn + 2) = *vn;
  469|  5.73k|        ++theVec;
  470|  5.73k|        vn += 3;
  471|       |
  472|       |        // vertex 1
  473|  5.73k|        ::memcpy(&theVec3F, theVec, sizeof(aiVector3f));
  474|  5.73k|        vp->x = theVec3F.x;
  475|  5.73k|        vp->y = theVec3F.y;
  476|  5.73k|        vp->z = theVec3F.z;
  477|  5.73k|        ++theVec;
  478|  5.73k|        ++vp;
  479|       |
  480|       |        // vertex 2
  481|  5.73k|        ::memcpy(&theVec3F, theVec, sizeof(aiVector3f));
  482|  5.73k|        vp->x = theVec3F.x;
  483|  5.73k|        vp->y = theVec3F.y;
  484|  5.73k|        vp->z = theVec3F.z;
  485|  5.73k|        ++theVec;
  486|  5.73k|        ++vp;
  487|       |
  488|       |        // vertex 3
  489|  5.73k|        ::memcpy(&theVec3F, theVec, sizeof(aiVector3f));
  490|  5.73k|        vp->x = theVec3F.x;
  491|  5.73k|        vp->y = theVec3F.y;
  492|  5.73k|        vp->z = theVec3F.z;
  493|  5.73k|        ++theVec;
  494|  5.73k|        ++vp;
  495|       |
  496|  5.73k|        sz = (const unsigned char *)theVec;
  497|       |
  498|  5.73k|        uint16_t color = *((uint16_t *)sz);
  499|  5.73k|        sz += 2;
  500|       |
  501|  5.73k|        if (color & (1 << 15)) {
  ------------------
  |  Branch (501:13): [True: 0, False: 5.73k]
  ------------------
  502|       |            // seems we need to take the color
  503|      0|            if (!pMesh->mColors[0]) {
  ------------------
  |  Branch (503:17): [True: 0, False: 0]
  ------------------
  504|      0|                pMesh->mColors[0] = new aiColor4D[pMesh->mNumVertices];
  505|      0|                for (unsigned int j = 0; j < pMesh->mNumVertices; ++j) {
  ------------------
  |  Branch (505:42): [True: 0, False: 0]
  ------------------
  506|      0|                    *pMesh->mColors[0]++ = mClrColorDefault;
  507|      0|                }
  508|      0|                pMesh->mColors[0] -= pMesh->mNumVertices;
  509|       |
  510|      0|                ASSIMP_LOG_INFO("STL: Mesh has vertex colors");
  511|      0|            }
  512|      0|            aiColor4D *clr = &pMesh->mColors[0][i * 3];
  513|      0|            clr->a = 1.0;
  514|      0|            const ai_real invVal((ai_real)1.0 / (ai_real)31.0);
  515|      0|            if (bIsMaterialise) // this is reversed
  ------------------
  |  Branch (515:17): [True: 0, False: 0]
  ------------------
  516|      0|            {
  517|      0|                clr->r = (color & 0x1fu) * invVal;
  518|      0|                clr->g = ((color & (0x1fu << 5)) >> 5u) * invVal;
  519|      0|                clr->b = ((color & (0x1fu << 10)) >> 10u) * invVal;
  520|      0|            } else {
  521|      0|                clr->b = (color & 0x1fu) * invVal;
  522|      0|                clr->g = ((color & (0x1fu << 5)) >> 5u) * invVal;
  523|      0|                clr->r = ((color & (0x1fu << 10)) >> 10u) * invVal;
  524|      0|            }
  525|       |            // assign the color to all vertices of the face
  526|      0|            *(clr + 1) = *clr;
  527|      0|            *(clr + 2) = *clr;
  528|      0|        }
  529|  5.73k|    }
  530|       |
  531|       |    // now copy faces
  532|      2|    addFacesToMesh(pMesh);
  533|       |
  534|      2|    aiNode *root = mScene->mRootNode;
  535|       |
  536|       |    // allocate one node
  537|      2|    aiNode *node = new aiNode();
  538|      2|    node->mParent = root;
  539|       |
  540|      2|    root->mNumChildren = 1u;
  541|      2|    root->mChildren = new aiNode *[root->mNumChildren];
  542|      2|    root->mChildren[0] = node;
  543|       |
  544|       |    // add all created meshes to the single node
  545|      2|    node->mNumMeshes = mScene->mNumMeshes;
  546|      2|    node->mMeshes = new unsigned int[mScene->mNumMeshes];
  547|      4|    for (unsigned int i = 0; i < mScene->mNumMeshes; ++i) {
  ------------------
  |  Branch (547:30): [True: 2, False: 2]
  ------------------
  548|      2|        node->mMeshes[i] = i;
  549|      2|    }
  550|       |
  551|      2|    if (bIsMaterialise && !pMesh->mColors[0]) {
  ------------------
  |  Branch (551:9): [True: 0, False: 2]
  |  Branch (551:27): [True: 0, False: 0]
  ------------------
  552|       |        // use the color as diffuse material color
  553|      0|        return true;
  554|      0|    }
  555|      2|    return false;
  556|      2|}
_ZN6Assimp11STLImporter16pushMeshesToNodeERNSt3__16vectorIjNS1_9allocatorIjEEEEP6aiNode:
  558|      4|void STLImporter::pushMeshesToNode(std::vector<unsigned int> &meshIndices, aiNode *node) {
  559|      4|    ai_assert(nullptr != node);
  560|      4|    if (meshIndices.empty()) {
  ------------------
  |  Branch (560:9): [True: 0, False: 4]
  ------------------
  561|      0|        return;
  562|      0|    }
  563|       |
  564|      4|    node->mNumMeshes = static_cast<unsigned int>(meshIndices.size());
  565|      4|    node->mMeshes = new unsigned int[meshIndices.size()];
  566|      8|    for (size_t i = 0; i < meshIndices.size(); ++i) {
  ------------------
  |  Branch (566:24): [True: 4, False: 4]
  ------------------
  567|      4|        node->mMeshes[i] = meshIndices[i];
  568|      4|    }
  569|      4|    meshIndices.clear();
  570|      4|}
STLLoader.cpp:_ZN6Assimp12_GLOBAL__N_111IsBinarySTLEPKcm:
   76|     21|static bool IsBinarySTL(const char *buffer, size_t fileSize) {
   77|     21|    if (fileSize < 84) {
  ------------------
  |  Branch (77:9): [True: 4, False: 17]
  ------------------
   78|      4|        return false;
   79|      4|    }
   80|       |
   81|     17|    const char *facecount_pos = buffer + 80;
   82|     17|    uint32_t faceCount(0);
   83|     17|    ::memcpy(&faceCount, facecount_pos, sizeof(uint32_t));
   84|     17|    const uint32_t expectedBinaryFileSize = faceCount * 50 + 84;
   85|       |
   86|     17|    return expectedBinaryFileSize == fileSize;
   87|     21|}
STLLoader.cpp:_ZN6Assimp12_GLOBAL__N_110IsAsciiSTLEPKcm:
   95|     14|static bool IsAsciiSTL(const char *buffer, size_t fileSize) {
   96|     14|    if (IsBinarySTL(buffer, fileSize))
  ------------------
  |  Branch (96:9): [True: 0, False: 14]
  ------------------
   97|      0|        return false;
   98|       |
   99|     14|    const char *bufferEnd = buffer + fileSize;
  100|       |
  101|     14|    if (!SkipSpaces(&buffer, bufferEnd)) {
  ------------------
  |  Branch (101:9): [True: 4, False: 10]
  ------------------
  102|      4|        return false;
  103|      4|    }
  104|       |
  105|     10|    if (buffer + 5 >= bufferEnd) {
  ------------------
  |  Branch (105:9): [True: 0, False: 10]
  ------------------
  106|      0|        return false;
  107|      0|    }
  108|       |
  109|     10|    bool isASCII(strncmp(buffer, "solid", 5) == 0);
  110|     10|    if (isASCII) {
  ------------------
  |  Branch (110:9): [True: 10, False: 0]
  ------------------
  111|       |        // A lot of importers are write solid even if the file is binary. So we have to check for ASCII-characters.
  112|     10|        if (fileSize >= BufferSize) {
  ------------------
  |  Branch (112:13): [True: 10, False: 0]
  ------------------
  113|     10|            isASCII = true;
  114|  5.01k|            for (unsigned int i = 0; i < BufferSize; i++) {
  ------------------
  |  Branch (114:38): [True: 5.00k, False: 10]
  ------------------
  115|  5.00k|                if (buffer[i] > UnicodeBoundary) {
  ------------------
  |  Branch (115:21): [True: 0, False: 5.00k]
  ------------------
  116|      0|                    isASCII = false;
  117|      0|                    break;
  118|      0|                }
  119|  5.00k|            }
  120|     10|        }
  121|     10|    }
  122|     10|    return isASCII;
  123|     10|}

_ZNK6Assimp4STEP2DB9GetHeaderEv:
  792|      1|    const HeaderInfo &GetHeader() const {
  793|      1|        return header;
  794|      1|    }
_ZN6Assimp4STEP2DBD2Ev:
  778|      3|    ~DB() {
  779|      3|        for (ObjectMap::value_type &o : objects) {
  ------------------
  |  Branch (779:39): [True: 0, False: 3]
  ------------------
  780|      0|            delete o.second;
  781|      0|        }
  782|      3|    }
_ZNK6Assimp4STEP7EXPRESS4LIST7GetSizeEv:
  290|      4|    size_t GetSize() const {
  291|      4|        return members.size();
  292|      4|    }
_ZN6Assimp4STEP7EXPRESS16ConversionSchema11SchemaEntryC2EPKcPFPNS0_6ObjectERKNS0_2DBERKNS1_4LISTEE:
  321|  1.96k|        SchemaEntry(const char *name, ConvertObjectProc func) : mName(name), mFunc(func) {}
_ZN6Assimp4STEP2DBC2ERKNSt3__110shared_ptrINS_12StreamReaderILb0ELb0EEEEE:
  775|      3|            reader(reader), splitter(*reader, true, true), evaluated_count(), schema(nullptr) {}
_ZN6Assimp4STEP2DB11GetSplitterEv:
  867|      3|    LineSplitter &GetSplitter() {
  868|      3|        return splitter;
  869|      3|    }
_ZN6Assimp4STEP2DB9GetHeaderEv:
  898|      3|    HeaderInfo &GetHeader() {
  899|      3|        return header;
  900|      3|    }
_ZN6Assimp4STEP7EXPRESS17PrimitiveDataTypeINSt3__112basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEEEC2ERKS9_:
  235|      2|            val(val) {}
_ZN6Assimp4STEP7EXPRESS8DataTypeD2Ev:
  164|     21|    virtual ~DataType() = default;
_ZN6Assimp4STEP7EXPRESS17PrimitiveDataTypeIlEC2ERKl:
  235|     15|            val(val) {}

_ZN6Assimp16TerragenImporterC2Ev:
   72|    624|        configComputeUVs(false) {
   73|       |    // empty
   74|    624|}
_ZNK6Assimp16TerragenImporter7CanReadERKNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEPNS_8IOSystemEb:
   78|    289|bool TerragenImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool /*checkSig*/) const {
   79|    289|    static const char *tokens[] = { "terragen" };
   80|       |    return SearchFileHeaderForToken(pIOHandler, pFile, tokens, AI_COUNT_OF(tokens));
   81|    289|}
_ZNK6Assimp16TerragenImporter7GetInfoEv:
   85|    636|const aiImporterDesc *TerragenImporter::GetInfo() const {
   86|    636|    return &desc;
   87|    636|}
_ZN6Assimp16TerragenImporter15SetupPropertiesEPKNS_8ImporterE:
   91|      2|void TerragenImporter::SetupProperties(const Importer *pImp) {
   92|       |    // AI_CONFIG_IMPORT_TER_MAKE_UVS
   93|       |    configComputeUVs = (0 != pImp->GetPropertyInteger(AI_CONFIG_IMPORT_TER_MAKE_UVS, 0));
   94|      2|}
_ZN6Assimp16TerragenImporter14InternReadFileERKNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEP7aiScenePNS_8IOSystemE:
   99|      2|        aiScene *pScene, IOSystem *pIOHandler) {
  100|      2|    IOStream *file = pIOHandler->Open(pFile, "rb");
  101|       |
  102|       |    // Check whether we can read from the file
  103|      2|    if (file == nullptr)
  ------------------
  |  Branch (103:9): [True: 0, False: 2]
  ------------------
  104|      0|        throw DeadlyImportError("Failed to open TERRAGEN TERRAIN file ", pFile, ".");
  105|       |
  106|       |    // Construct a stream reader to read all data in the correct endianness
  107|      2|    StreamReaderLE reader(file);
  108|      2|    if (reader.GetRemainingSize() < 16)
  ------------------
  |  Branch (108:9): [True: 0, False: 2]
  ------------------
  109|      0|        throw DeadlyImportError("TER: file is too small");
  110|       |
  111|       |    // Check for the existence of the two magic strings 'TERRAGEN' and 'TERRAIN '
  112|      2|    if (::strncmp((const char *)reader.GetPtr(), AI_TERR_BASE_STRING, 8))
  ------------------
  |  |   54|      2|#define AI_TERR_BASE_STRING "TERRAGEN"
  ------------------
  |  Branch (112:9): [True: 0, False: 2]
  ------------------
  113|      0|        throw DeadlyImportError("TER: Magic string \'TERRAGEN\' not found");
  114|       |
  115|      2|    if (::strncmp((const char *)reader.GetPtr() + 8, AI_TERR_TERRAIN_STRING, 8))
  ------------------
  |  |   55|      2|#define AI_TERR_TERRAIN_STRING "TERRAIN "
  ------------------
  |  Branch (115:9): [True: 0, False: 2]
  ------------------
  116|      0|        throw DeadlyImportError("TER: Magic string \'TERRAIN\' not found");
  117|       |
  118|      2|    unsigned int x = 0, y = 0, mode = 0;
  119|       |
  120|      2|    aiNode *root = pScene->mRootNode = new aiNode();
  121|      2|    root->mName.Set("<TERRAGEN.TERRAIN>");
  122|       |
  123|       |    // Default scaling is 30
  124|      2|    root->mTransformation.a1 = root->mTransformation.b2 = root->mTransformation.c3 = 30.f;
  125|       |
  126|       |    // Now read all chunks until we're finished or an EOF marker is encountered
  127|      2|    reader.IncPtr(16);
  128|   164k|    while (reader.GetRemainingSize() >= 4) {
  ------------------
  |  Branch (128:12): [True: 164k, False: 0]
  ------------------
  129|   164k|        const char *head = (const char *)reader.GetPtr();
  130|   164k|        reader.IncPtr(4);
  131|       |
  132|       |        // EOF, break in every case
  133|   164k|        if (!::strncmp(head, AI_TERR_EOF_STRING, 4))
  ------------------
  |  |   56|   164k|#define AI_TERR_EOF_STRING "EOF "
  ------------------
  |  Branch (133:13): [True: 2, False: 164k]
  ------------------
  134|      2|            break;
  135|       |
  136|       |        // Number of x-data points
  137|   164k|        if (!::strncmp(head, AI_TERR_CHUNK_XPTS, 4)) {
  ------------------
  |  |   59|   164k|#define AI_TERR_CHUNK_XPTS "XPTS"
  ------------------
  |  Branch (137:13): [True: 2, False: 164k]
  ------------------
  138|      2|            x = (uint16_t)reader.GetI2();
  139|      2|        }
  140|       |        // Number of y-data points
  141|   164k|        else if (!::strncmp(head, AI_TERR_CHUNK_YPTS, 4)) {
  ------------------
  |  |   60|   164k|#define AI_TERR_CHUNK_YPTS "YPTS"
  ------------------
  |  Branch (141:18): [True: 2, False: 164k]
  ------------------
  142|      2|            y = (uint16_t)reader.GetI2();
  143|      2|        }
  144|       |        // Squared terrains width-1.
  145|   164k|        else if (!::strncmp(head, AI_TERR_CHUNK_SIZE, 4)) {
  ------------------
  |  |   61|   164k|#define AI_TERR_CHUNK_SIZE "SIZE"
  ------------------
  |  Branch (145:18): [True: 2, False: 164k]
  ------------------
  146|      2|            x = y = (uint16_t)reader.GetI2() + 1;
  147|      2|        }
  148|       |        // terrain scaling
  149|   164k|        else if (!::strncmp(head, AI_TERR_CHUNK_SCAL, 4)) {
  ------------------
  |  |   62|   164k|#define AI_TERR_CHUNK_SCAL "SCAL"
  ------------------
  |  Branch (149:18): [True: 2, False: 164k]
  ------------------
  150|      2|            root->mTransformation.a1 = reader.GetF4();
  151|      2|            root->mTransformation.b2 = reader.GetF4();
  152|      2|            root->mTransformation.c3 = reader.GetF4();
  153|      2|        }
  154|       |        // mapping == 1: earth radius
  155|   164k|        else if (!::strncmp(head, AI_TERR_CHUNK_CRAD, 4)) {
  ------------------
  |  |   63|   164k|#define AI_TERR_CHUNK_CRAD "CRAD"
  ------------------
  |  Branch (155:18): [True: 2, False: 164k]
  ------------------
  156|      2|            reader.GetF4();
  157|      2|        }
  158|       |        // mapping mode
  159|   164k|        else if (!::strncmp(head, AI_TERR_CHUNK_CRVM, 4)) {
  ------------------
  |  |   64|   164k|#define AI_TERR_CHUNK_CRVM "CRVM"
  ------------------
  |  Branch (159:18): [True: 2, False: 164k]
  ------------------
  160|      2|            mode = reader.GetI1();
  161|      2|            if (0 != mode)
  ------------------
  |  Branch (161:17): [True: 0, False: 2]
  ------------------
  162|      2|                ASSIMP_LOG_ERROR("TER: Unsupported mapping mode, a flat terrain is returned");
  163|      2|        }
  164|       |        // actual terrain data
  165|   164k|        else if (!::strncmp(head, AI_TERR_CHUNK_ALTW, 4)) {
  ------------------
  |  |   65|   164k|#define AI_TERR_CHUNK_ALTW "ALTW"
  ------------------
  |  Branch (165:18): [True: 2, False: 164k]
  ------------------
  166|      2|            float hscale = (float)reader.GetI2() / 65536;
  167|      2|            float bheight = (float)reader.GetI2();
  168|       |
  169|      2|            if (!hscale) hscale = 1;
  ------------------
  |  Branch (169:17): [True: 0, False: 2]
  ------------------
  170|       |
  171|       |            // Ensure we have enough data
  172|      2|            if (reader.GetRemainingSize() < x * y * 2)
  ------------------
  |  Branch (172:17): [True: 0, False: 2]
  ------------------
  173|      0|                throw DeadlyImportError("TER: ALTW chunk is too small");
  174|       |
  175|      2|            if (x <= 1 || y <= 1)
  ------------------
  |  Branch (175:17): [True: 0, False: 2]
  |  Branch (175:27): [True: 0, False: 2]
  ------------------
  176|      0|                throw DeadlyImportError("TER: Invalid terrain size");
  177|       |
  178|       |            // Allocate the output mesh
  179|      2|            pScene->mMeshes = new aiMesh *[pScene->mNumMeshes = 1];
  180|      2|            aiMesh *m = pScene->mMeshes[0] = new aiMesh();
  181|       |
  182|       |            // We return quads
  183|      2|            aiFace *f = m->mFaces = new aiFace[m->mNumFaces = (x - 1) * (y - 1)];
  184|      2|            aiVector3D *pv = m->mVertices = new aiVector3D[m->mNumVertices = m->mNumFaces * 4];
  185|       |
  186|      2|            aiVector3D *uv(nullptr);
  187|      2|            float step_y(0.0f), step_x(0.0f);
  188|      2|            if (configComputeUVs) {
  ------------------
  |  Branch (188:17): [True: 0, False: 2]
  ------------------
  189|      0|                uv = m->mTextureCoords[0] = new aiVector3D[m->mNumVertices];
  190|      0|                step_y = 1.f / y;
  191|      0|                step_x = 1.f / x;
  192|      0|            }
  193|      2|            const int16_t *data = (const int16_t *)reader.GetPtr();
  194|       |
  195|    770|            for (unsigned int yy = 0, t = 0; yy < y - 1; ++yy) {
  ------------------
  |  Branch (195:46): [True: 768, False: 2]
  ------------------
  196|   328k|                for (unsigned int xx = 0; xx < x - 1; ++xx, ++f) {
  ------------------
  |  Branch (196:43): [True: 327k, False: 768]
  ------------------
  197|       |
  198|       |                    // make verts
  199|   327k|                    const float fy = (float)yy, fx = (float)xx;
  200|   327k|                    unsigned tmp, tmp2;
  201|   327k|                    *pv++ = aiVector3D(fx, fy, (float)data[(tmp2 = x * yy) + xx] * hscale + bheight);
  202|   327k|                    *pv++ = aiVector3D(fx, fy + 1, (float)data[(tmp = x * (yy + 1)) + xx] * hscale + bheight);
  203|   327k|                    *pv++ = aiVector3D(fx + 1, fy + 1, (float)data[tmp + xx + 1] * hscale + bheight);
  204|   327k|                    *pv++ = aiVector3D(fx + 1, fy, (float)data[tmp2 + xx + 1] * hscale + bheight);
  205|       |
  206|       |                    // also make texture coordinates, if necessary
  207|   327k|                    if (configComputeUVs) {
  ------------------
  |  Branch (207:25): [True: 0, False: 327k]
  ------------------
  208|      0|                        *uv++ = aiVector3D(step_x * xx, step_y * yy, 0.f);
  209|      0|                        *uv++ = aiVector3D(step_x * xx, step_y * (yy + 1), 0.f);
  210|      0|                        *uv++ = aiVector3D(step_x * (xx + 1), step_y * (yy + 1), 0.f);
  211|      0|                        *uv++ = aiVector3D(step_x * (xx + 1), step_y * yy, 0.f);
  212|      0|                    }
  213|       |
  214|       |                    // make indices
  215|   327k|                    f->mIndices = new unsigned int[f->mNumIndices = 4];
  216|  1.63M|                    for (unsigned int i = 0; i < 4; ++i) {
  ------------------
  |  Branch (216:46): [True: 1.31M, False: 327k]
  ------------------
  217|  1.31M|                        f->mIndices[i] = t;
  218|  1.31M|                        t++;
  219|  1.31M|                    }
  220|   327k|                }
  221|    768|            }
  222|       |
  223|       |            // Add the mesh to the root node
  224|      2|            root->mMeshes = new unsigned int[root->mNumMeshes = 1];
  225|      2|            root->mMeshes[0] = 0;
  226|      2|        }
  227|       |
  228|       |        // Get to the next chunk (4 byte aligned)
  229|   164k|        unsigned dtt = reader.GetCurrentPos() & 0x3;
  230|   164k|        if (dtt) {
  ------------------
  |  Branch (230:13): [True: 8, False: 164k]
  ------------------
  231|      8|            reader.IncPtr(4 - dtt);
  232|      8|        }
  233|   164k|    }
  234|       |
  235|       |    // Check whether we have a mesh now
  236|      2|    if (pScene->mNumMeshes != 1)
  ------------------
  |  Branch (236:9): [True: 0, False: 2]
  ------------------
  237|      0|        throw DeadlyImportError("TER: Unable to load terrain");
  238|       |
  239|       |    // Set the AI_SCENE_FLAGS_TERRAIN bit
  240|      2|    pScene->mFlags |= AI_SCENE_FLAGS_TERRAIN;
  241|      2|}

_ZN6Assimp14UnrealImporterC2Ev:
  166|    624|        mConfigFrameID(0), mConfigHandleFlags(true) {
  167|       |    // empty
  168|    624|}
_ZNK6Assimp14UnrealImporter7CanReadERKNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEPNS_8IOSystemEb:
  172|    287|bool UnrealImporter::CanRead(const std::string &filename, IOSystem * /*pIOHandler*/, bool /*checkSig*/) const {
  173|    287|    return SimpleExtensionCheck(filename, "3d", "uc");
  174|    287|}
_ZNK6Assimp14UnrealImporter7GetInfoEv:
  178|    655|const aiImporterDesc *UnrealImporter::GetInfo() const {
  179|    655|    return &desc;
  180|    655|}
_ZN6Assimp14UnrealImporter15SetupPropertiesEPKNS_8ImporterE:
  184|     21|void UnrealImporter::SetupProperties(const Importer *pImp) {
  185|       |    // The
  186|       |    // AI_CONFIG_IMPORT_UNREAL_KEYFRAME option overrides the
  187|       |    // AI_CONFIG_IMPORT_GLOBAL_KEYFRAME option.
  188|     21|    mConfigFrameID = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_UNREAL_KEYFRAME, -1);
  189|     21|    if (static_cast<unsigned int>(-1) == mConfigFrameID) {
  ------------------
  |  Branch (189:9): [True: 21, False: 0]
  ------------------
  190|     21|        mConfigFrameID = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_GLOBAL_KEYFRAME, 0);
  191|     21|    }
  192|       |
  193|       |    // AI_CONFIG_IMPORT_UNREAL_HANDLE_FLAGS, default is true
  194|       |    mConfigHandleFlags = (0 != pImp->GetPropertyInteger(AI_CONFIG_IMPORT_UNREAL_HANDLE_FLAGS, 1));
  195|     21|}
_ZN6Assimp14UnrealImporter14InternReadFileERKNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEP7aiScenePNS_8IOSystemE:
  200|     21|        aiScene *pScene, IOSystem *pIOHandler) {
  201|       |    // For any of the 3 files being passed get the three correct paths
  202|       |    // First of all, determine file extension
  203|     21|    std::string::size_type pos = pFile.find_last_of('.');
  204|     21|    std::string extension = GetExtension(pFile);
  205|       |
  206|     21|    std::string d_path, a_path, uc_path;
  207|     21|    if (extension == "3d") {
  ------------------
  |  Branch (207:9): [True: 21, False: 0]
  ------------------
  208|       |        // jjjj_d.3d
  209|       |        // jjjj_a.3d
  210|     21|        pos = pFile.find_last_of('_');
  211|     21|        if (std::string::npos == pos) {
  ------------------
  |  Branch (211:13): [True: 0, False: 21]
  ------------------
  212|      0|            throw DeadlyImportError("UNREAL: Unexpected naming scheme");
  213|      0|        }
  214|     21|        extension = pFile.substr(0, pos);
  215|     21|    } else {
  216|      0|        extension = pFile.substr(0, pos);
  217|      0|    }
  218|       |
  219|       |    // build proper paths
  220|     21|    d_path = extension + "_d.3d";
  221|     21|    a_path = extension + "_a.3d";
  222|     21|    uc_path = extension + ".uc";
  223|       |
  224|     21|    ASSIMP_LOG_DEBUG("UNREAL: data file is ", d_path);
  225|     21|    ASSIMP_LOG_DEBUG("UNREAL: aniv file is ", a_path);
  226|     21|    ASSIMP_LOG_DEBUG("UNREAL: uc file is ", uc_path);
  227|       |
  228|       |    // and open the files ... we can't live without them
  229|     21|    std::unique_ptr<IOStream> p(pIOHandler->Open(d_path));
  230|     21|    if (!p)
  ------------------
  |  Branch (230:9): [True: 0, False: 21]
  ------------------
  231|      0|        throw DeadlyImportError("UNREAL: Unable to open _d file");
  232|     21|    StreamReaderLE d_reader(pIOHandler->Open(d_path));
  233|       |
  234|     21|    const uint16_t numTris = d_reader.GetI2();
  235|     21|    const uint16_t numVert = d_reader.GetI2();
  236|     21|    d_reader.IncPtr(44);
  237|     21|    if (!numTris || numVert < 3) {
  ------------------
  |  Branch (237:9): [True: 0, False: 21]
  |  Branch (237:21): [True: 0, False: 21]
  ------------------
  238|      0|        throw DeadlyImportError("UNREAL: Invalid number of vertices/triangles");
  239|      0|    }
  240|       |
  241|       |    // maximum texture index
  242|     21|    unsigned int maxTexIdx = 0;
  243|       |
  244|       |    // collect triangles
  245|     21|    std::vector<Unreal::Triangle> triangles(numTris);
  246|  51.4k|    for (auto &tri : triangles) {
  ------------------
  |  Branch (246:20): [True: 51.4k, False: 21]
  ------------------
  247|   205k|        for (unsigned int i = 0; i < 3; ++i) {
  ------------------
  |  Branch (247:34): [True: 154k, False: 51.4k]
  ------------------
  248|   154k|            tri.mVertex[i] = d_reader.GetI2();
  249|   154k|            if (tri.mVertex[i] >= numTris) {
  ------------------
  |  Branch (249:17): [True: 84.0k, False: 70.1k]
  ------------------
  250|  84.0k|                ASSIMP_LOG_WARN("UNREAL: vertex index out of range");
  251|  84.0k|                tri.mVertex[i] = 0;
  252|  84.0k|            }
  253|   154k|        }
  254|  51.4k|        tri.mType = d_reader.GetI1();
  255|       |
  256|       |        // handle mesh flagss?
  257|  51.4k|        if (mConfigHandleFlags) {
  ------------------
  |  Branch (257:13): [True: 51.3k, False: 20]
  ------------------
  258|  51.3k|            tri.mType = Unreal::MF_NORMAL_OS;
  259|  51.3k|        } else {
  260|       |            // ignore MOD and MASKED for the moment, treat them as two-sided
  261|     20|            if (tri.mType == Unreal::MF_NORMAL_MOD_TS || tri.mType == Unreal::MF_NORMAL_MASKED_TS)
  ------------------
  |  Branch (261:17): [True: 20, False: 0]
  |  Branch (261:58): [True: 0, False: 0]
  ------------------
  262|      0|                tri.mType = Unreal::MF_NORMAL_TS;
  263|     20|        }
  264|  51.4k|        d_reader.IncPtr(1);
  265|       |
  266|   205k|        for (unsigned int i = 0; i < 3; ++i) {
  ------------------
  |  Branch (266:34): [True: 154k, False: 51.4k]
  ------------------
  267|   462k|            for (unsigned int i2 = 0; i2 < 2; ++i2) {
  ------------------
  |  Branch (267:39): [True: 308k, False: 154k]
  ------------------
  268|   308k|                tri.mTex[i][i2] = d_reader.GetI1();
  269|   308k|            }
  270|   154k|        }
  271|       |
  272|  51.4k|        tri.mTextureNum = d_reader.GetI1();
  273|  51.4k|        maxTexIdx = std::max(maxTexIdx, (unsigned int)tri.mTextureNum);
  274|  51.4k|        d_reader.IncPtr(1);
  275|  51.4k|    }
  276|       |
  277|     21|    p.reset(pIOHandler->Open(a_path));
  278|     21|    if (!p) {
  ------------------
  |  Branch (278:9): [True: 0, False: 21]
  ------------------
  279|      0|        throw DeadlyImportError("UNREAL: Unable to open _a file");
  280|      0|    }
  281|     21|    StreamReaderLE a_reader(pIOHandler->Open(a_path));
  282|       |
  283|       |    // read number of frames
  284|     21|    const uint32_t numFrames = a_reader.GetI2();
  285|     21|    if (mConfigFrameID >= numFrames) {
  ------------------
  |  Branch (285:9): [True: 0, False: 21]
  ------------------
  286|      0|        throw DeadlyImportError("UNREAL: The requested frame does not exist");
  287|      0|    }
  288|       |
  289|       |    // read aniv file length
  290|     21|    if (uint32_t st = a_reader.GetI2(); st != numVert * 4u) {
  ------------------
  |  Branch (290:41): [True: 1, False: 20]
  ------------------
  291|      1|        throw DeadlyImportError("UNREAL: Unexpected aniv file length");
  292|      1|    }
  293|       |
  294|       |    // skip to our frame
  295|     20|    a_reader.IncPtr(mConfigFrameID * numVert * 4);
  296|       |
  297|       |    // collect vertices
  298|     20|    std::vector<aiVector3D> vertices(numVert);
  299|     20|    for (auto &vertex : vertices) {
  ------------------
  |  Branch (299:23): [True: 0, False: 20]
  ------------------
  300|      0|        int32_t val = a_reader.GetI4();
  301|      0|        Unreal::DecompressVertex(vertex, val);
  302|      0|    }
  303|       |
  304|       |    // list of textures.
  305|     20|    std::vector<std::pair<unsigned int, std::string>> textures;
  306|       |
  307|       |    // allocate the output scene
  308|     20|    aiNode *nd = pScene->mRootNode = new aiNode();
  309|     20|    nd->mName.Set("<UnrealRoot>");
  310|       |
  311|       |    // we can live without the uc file if necessary
  312|     20|    std::unique_ptr<IOStream> pb(pIOHandler->Open(uc_path));
  313|     20|    if (pb) {
  ------------------
  |  Branch (313:9): [True: 0, False: 20]
  ------------------
  314|       |
  315|      0|        std::vector<char> _data;
  316|      0|        TextFileToBuffer(pb.get(), _data);
  317|      0|        const char *data = &_data[0];
  318|      0|        const char *end = &_data[_data.size() - 1] + 1;
  319|       |
  320|      0|        std::vector<std::pair<std::string, std::string>> tempTextures;
  321|       |
  322|       |        // do a quick search in the UC file for some known, usually texture-related, tags
  323|      0|        for (; *data; ++data) {
  ------------------
  |  Branch (323:16): [True: 0, False: 0]
  ------------------
  324|      0|            if (TokenMatchI(data, "#exec", 5)) {
  ------------------
  |  Branch (324:17): [True: 0, False: 0]
  ------------------
  325|      0|                SkipSpacesAndLineEnd(&data, end);
  326|       |
  327|       |                // #exec TEXTURE IMPORT [...] NAME=jjjjj [...] FILE=jjjj.pcx [...]
  328|      0|                if (TokenMatchI(data, "TEXTURE", 7)) {
  ------------------
  |  Branch (328:21): [True: 0, False: 0]
  ------------------
  329|      0|                    SkipSpacesAndLineEnd(&data, end);
  330|       |
  331|      0|                    if (TokenMatchI(data, "IMPORT", 6)) {
  ------------------
  |  Branch (331:25): [True: 0, False: 0]
  ------------------
  332|      0|                        tempTextures.emplace_back();
  333|      0|                        std::pair<std::string, std::string> &me = tempTextures.back();
  334|      0|                        for (; !IsLineEnd(*data); ++data) {
  ------------------
  |  Branch (334:32): [True: 0, False: 0]
  ------------------
  335|      0|                            if (!ASSIMP_strincmp(data, "NAME=", 5)) {
  ------------------
  |  Branch (335:33): [True: 0, False: 0]
  ------------------
  336|      0|                                const char *d = data += 5;
  337|      0|                                for (; !IsSpaceOrNewLine(*data); ++data)
  ------------------
  |  Branch (337:40): [True: 0, False: 0]
  ------------------
  338|      0|                                    ;
  339|      0|                                me.first = std::string(d, (size_t)(data - d));
  340|      0|                            } else if (!ASSIMP_strincmp(data, "FILE=", 5)) {
  ------------------
  |  Branch (340:40): [True: 0, False: 0]
  ------------------
  341|      0|                                const char *d = data += 5;
  342|      0|                                for (; !IsSpaceOrNewLine(*data); ++data)
  ------------------
  |  Branch (342:40): [True: 0, False: 0]
  ------------------
  343|      0|                                    ;
  344|      0|                                me.second = std::string(d, (size_t)(data - d));
  345|      0|                            }
  346|      0|                        }
  347|      0|                        if (!me.first.length() || !me.second.length()) {
  ------------------
  |  Branch (347:29): [True: 0, False: 0]
  |  Branch (347:51): [True: 0, False: 0]
  ------------------
  348|      0|                            tempTextures.pop_back();
  349|      0|                        }
  350|      0|                    }
  351|      0|                }
  352|       |                // #exec MESHMAP SETTEXTURE MESHMAP=box NUM=1 TEXTURE=Jtex1
  353|       |                // #exec MESHMAP SCALE MESHMAP=box X=0.1 Y=0.1 Z=0.2
  354|      0|                else if (TokenMatchI(data, "MESHMAP", 7)) {
  ------------------
  |  Branch (354:26): [True: 0, False: 0]
  ------------------
  355|      0|                    SkipSpacesAndLineEnd(&data, end);
  356|       |
  357|      0|                    if (TokenMatchI(data, "SETTEXTURE", 10)) {
  ------------------
  |  Branch (357:25): [True: 0, False: 0]
  ------------------
  358|       |
  359|      0|                        textures.emplace_back();
  360|      0|                        std::pair<unsigned int, std::string> &me = textures.back();
  361|       |
  362|      0|                        for (; !IsLineEnd(*data); ++data) {
  ------------------
  |  Branch (362:32): [True: 0, False: 0]
  ------------------
  363|      0|                            if (!ASSIMP_strincmp(data, "NUM=", 4)) {
  ------------------
  |  Branch (363:33): [True: 0, False: 0]
  ------------------
  364|      0|                                data += 4;
  365|      0|                                me.first = strtoul10(data, &data);
  366|      0|                            } else if (!ASSIMP_strincmp(data, "TEXTURE=", 8)) {
  ------------------
  |  Branch (366:40): [True: 0, False: 0]
  ------------------
  367|      0|                                data += 8;
  368|      0|                                const char *d = data;
  369|      0|                                for (; !IsSpaceOrNewLine(*data); ++data);
  ------------------
  |  Branch (369:40): [True: 0, False: 0]
  ------------------
  370|      0|                                me.second = std::string(d, (size_t)(data - d));
  371|       |
  372|       |                                // try to find matching path names, doesn't care if we don't find them
  373|      0|                                for (std::vector<std::pair<std::string, std::string>>::const_iterator it = tempTextures.begin();
  374|      0|                                        it != tempTextures.end(); ++it) {
  ------------------
  |  Branch (374:41): [True: 0, False: 0]
  ------------------
  375|      0|                                    if ((*it).first == me.second) {
  ------------------
  |  Branch (375:41): [True: 0, False: 0]
  ------------------
  376|      0|                                        me.second = (*it).second;
  377|      0|                                        break;
  378|      0|                                    }
  379|      0|                                }
  380|      0|                            }
  381|      0|                        }
  382|      0|                    } else if (TokenMatchI(data, "SCALE", 5)) {
  ------------------
  |  Branch (382:32): [True: 0, False: 0]
  ------------------
  383|       |
  384|      0|                        for (; !IsLineEnd(*data); ++data) {
  ------------------
  |  Branch (384:32): [True: 0, False: 0]
  ------------------
  385|      0|                            if (data[0] == 'X' && data[1] == '=') {
  ------------------
  |  Branch (385:33): [True: 0, False: 0]
  |  Branch (385:51): [True: 0, False: 0]
  ------------------
  386|      0|                                data = fast_atoreal_move(data + 2, nd->mTransformation.a1);
  387|      0|                            } else if (data[0] == 'Y' && data[1] == '=') {
  ------------------
  |  Branch (387:40): [True: 0, False: 0]
  |  Branch (387:58): [True: 0, False: 0]
  ------------------
  388|      0|                                data = fast_atoreal_move(data + 2, nd->mTransformation.b2);
  389|      0|                            } else if (data[0] == 'Z' && data[1] == '=') {
  ------------------
  |  Branch (389:40): [True: 0, False: 0]
  |  Branch (389:58): [True: 0, False: 0]
  ------------------
  390|      0|                                data = fast_atoreal_move(data + 2, nd->mTransformation.c3);
  391|      0|                            }
  392|      0|                        }
  393|      0|                    }
  394|      0|                }
  395|      0|            }
  396|      0|        }
  397|     20|    } else {
  398|     20|        ASSIMP_LOG_ERROR("Unable to open .uc file");
  399|     20|    }
  400|       |
  401|     20|    std::vector<Unreal::TempMat> materials;
  402|     20|    materials.reserve(textures.size() * 2 + 5);
  403|       |
  404|       |    // find out how many output meshes and materials we'll have and build material indices
  405|     20|    for (auto &tri : triangles) {
  ------------------
  |  Branch (405:20): [True: 0, False: 20]
  ------------------
  406|      0|        Unreal::TempMat mat(tri);
  407|      0|        auto nt = std::find(materials.begin(), materials.end(), mat);
  408|      0|        if (nt == materials.end()) {
  ------------------
  |  Branch (408:13): [True: 0, False: 0]
  ------------------
  409|       |            // add material
  410|      0|            tri.matIndex = static_cast<unsigned int>(materials.size());
  411|      0|            mat.numFaces = 1;
  412|      0|            materials.push_back(mat);
  413|       |
  414|      0|            ++pScene->mNumMeshes;
  415|      0|        } else {
  416|      0|            tri.matIndex = static_cast<unsigned int>(nt - materials.begin());
  417|      0|            ++nt->numFaces;
  418|      0|        }
  419|      0|    }
  420|       |
  421|     20|    if (!pScene->mNumMeshes) {
  ------------------
  |  Branch (421:9): [True: 0, False: 20]
  ------------------
  422|      0|        throw DeadlyImportError("UNREAL: Unable to find valid mesh data");
  423|      0|    }
  424|       |
  425|       |    // allocate meshes and bind them to the node graph
  426|     20|    pScene->mMeshes = new aiMesh *[pScene->mNumMeshes];
  427|     20|    pScene->mMaterials = new aiMaterial *[pScene->mNumMaterials = pScene->mNumMeshes];
  428|       |
  429|     20|    nd->mNumMeshes = pScene->mNumMeshes;
  430|     20|    nd->mMeshes = new unsigned int[nd->mNumMeshes];
  431|     20|    for (unsigned int i = 0; i < pScene->mNumMeshes; ++i) {
  ------------------
  |  Branch (431:30): [True: 0, False: 20]
  ------------------
  432|      0|        aiMesh *m = pScene->mMeshes[i] = new aiMesh();
  433|      0|        m->mPrimitiveTypes = aiPrimitiveType_TRIANGLE;
  434|       |
  435|      0|        const unsigned int num = materials[i].numFaces;
  436|      0|        m->mFaces = new aiFace[num];
  437|      0|        m->mVertices = new aiVector3D[num * 3];
  438|      0|        m->mTextureCoords[0] = new aiVector3D[num * 3];
  439|       |
  440|      0|        nd->mMeshes[i] = i;
  441|       |
  442|       |        // create materials, too
  443|      0|        aiMaterial *mat = new aiMaterial();
  444|      0|        pScene->mMaterials[i] = mat;
  445|       |
  446|       |        // all white by default - texture rulez
  447|      0|        aiColor3D color(1.f, 1.f, 1.f);
  448|       |
  449|      0|        aiString s;
  450|      0|        ::ai_snprintf(s.data, AI_MAXLEN, "mat%u_tx%u_", i, materials[i].tex);
  451|       |
  452|       |        // set the two-sided flag
  453|      0|        if (materials[i].type == Unreal::MF_NORMAL_TS) {
  ------------------
  |  Branch (453:13): [True: 0, False: 0]
  ------------------
  454|      0|            const int twosided = 1;
  455|      0|            mat->AddProperty(&twosided, 1, AI_MATKEY_TWOSIDED);
  456|      0|            ::strcat(s.data, "ts_");
  457|      0|        } else
  458|      0|            ::strcat(s.data, "os_");
  459|       |
  460|       |        // make TRANS faces 90% opaque that RemRedundantMaterials won't catch us
  461|      0|        if (materials[i].type == Unreal::MF_NORMAL_TRANS_TS) {
  ------------------
  |  Branch (461:13): [True: 0, False: 0]
  ------------------
  462|      0|            const float opac = 0.9f;
  463|      0|            mat->AddProperty(&opac, 1, AI_MATKEY_OPACITY);
  464|      0|            ::strcat(s.data, "tran_");
  465|      0|        } else
  466|      0|            ::strcat(s.data, "opaq_");
  467|       |
  468|       |        // a special name for the weapon attachment point
  469|      0|        if (materials[i].type == Unreal::MF_WEAPON_PLACEHOLDER) {
  ------------------
  |  Branch (469:13): [True: 0, False: 0]
  ------------------
  470|      0|            s.length = ::ai_snprintf(s.data, AI_MAXLEN, "$WeaponTag$");
  471|      0|            color = aiColor3D(0.f, 0.f, 0.f);
  472|      0|        }
  473|       |
  474|       |        // set color and name
  475|      0|        mat->AddProperty(&color, 1, AI_MATKEY_COLOR_DIFFUSE);
  476|      0|        s.length = static_cast<ai_uint32>(::strlen(s.data));
  477|      0|        mat->AddProperty(&s, AI_MATKEY_NAME);
  478|       |
  479|       |        // set texture, if any
  480|      0|        const unsigned int tex = materials[i].tex;
  481|      0|        for (auto it = textures.begin(); it != textures.end(); ++it) {
  ------------------
  |  Branch (481:42): [True: 0, False: 0]
  ------------------
  482|      0|            if ((*it).first == tex) {
  ------------------
  |  Branch (482:17): [True: 0, False: 0]
  ------------------
  483|      0|                s.Set((*it).second);
  484|      0|                mat->AddProperty(&s, AI_MATKEY_TEXTURE_DIFFUSE(0));
  485|      0|                break;
  486|      0|            }
  487|      0|        }
  488|      0|    }
  489|       |
  490|       |    // fill them.
  491|     20|    for (const Unreal::Triangle &tri : triangles) {
  ------------------
  |  Branch (491:38): [True: 0, False: 20]
  ------------------
  492|      0|        Unreal::TempMat mat(tri);
  493|      0|        auto nt = std::find(materials.begin(), materials.end(), mat);
  494|       |
  495|      0|        aiMesh *mesh = pScene->mMeshes[nt - materials.begin()];
  496|      0|        aiFace &f = mesh->mFaces[mesh->mNumFaces++];
  497|      0|        f.mIndices = new unsigned int[f.mNumIndices = 3];
  498|       |
  499|      0|        for (unsigned int i = 0; i < 3; ++i, mesh->mNumVertices++) {
  ------------------
  |  Branch (499:34): [True: 0, False: 0]
  ------------------
  500|      0|            f.mIndices[i] = mesh->mNumVertices;
  501|       |
  502|      0|            mesh->mVertices[mesh->mNumVertices] = vertices[tri.mVertex[i]];
  503|      0|            mesh->mTextureCoords[0][mesh->mNumVertices] = aiVector3D(tri.mTex[i][0] / 255.f, 1.f - tri.mTex[i][1] / 255.f, 0.f);
  504|      0|        }
  505|      0|    }
  506|       |
  507|       |    // convert to RH
  508|     20|    MakeLeftHandedProcess hero;
  509|     20|    hero.Execute(pScene);
  510|       |
  511|     20|    FlipWindingOrderProcess flipper;
  512|     20|    flipper.Execute(pScene);
  513|     20|}

_ZN6Assimp18isFileWrlVrml97ExtERKNSt3__112basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEE:
   53|      5|bool isFileWrlVrml97Ext(const std::string &pFile) {
   54|      5|    size_t pos = pFile.find_last_of('.');
   55|      5|    if (pos == std::string::npos) {
  ------------------
  |  Branch (55:9): [True: 0, False: 5]
  ------------------
   56|      0|        return false;
   57|      0|    }
   58|      5|    std::string ext = pFile.substr(pos + 1);
   59|      5|    if (ext.size() != 3) {
  ------------------
  |  Branch (59:9): [True: 0, False: 5]
  ------------------
   60|      0|        return false;
   61|      0|    }
   62|      5|    return (ext[0] == 'w' || ext[0] == 'W') && (ext[1] == 'r' || ext[1] == 'R') && (ext[2] == 'l' || ext[2] == 'L');
  ------------------
  |  Branch (62:13): [True: 0, False: 5]
  |  Branch (62:30): [True: 0, False: 5]
  |  Branch (62:49): [True: 0, False: 0]
  |  Branch (62:66): [True: 0, False: 0]
  |  Branch (62:85): [True: 0, False: 0]
  |  Branch (62:102): [True: 0, False: 0]
  ------------------
   63|      5|}
_ZN6Assimp24isFileX3dvClassicVrmlExtERKNSt3__112basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEE:
   65|      5|bool isFileX3dvClassicVrmlExt(const std::string &pFile) {
   66|      5|    size_t pos = pFile.find_last_of('.');
   67|      5|    if (pos == std::string::npos) {
  ------------------
  |  Branch (67:9): [True: 0, False: 5]
  ------------------
   68|      0|        return false;
   69|      0|    }
   70|      5|    std::string ext = pFile.substr(pos + 1);
   71|      5|    if (ext.size() != 4) {
  ------------------
  |  Branch (71:9): [True: 5, False: 0]
  ------------------
   72|      5|        return false;
   73|      5|    }
   74|      0|    return (ext[0] == 'x' || ext[0] == 'X') && (ext[1] == '3') && (ext[2] == 'd' || ext[2] == 'D') && (ext[3] == 'v' || ext[3] == 'V');
  ------------------
  |  Branch (74:13): [True: 0, False: 0]
  |  Branch (74:30): [True: 0, False: 0]
  |  Branch (74:48): [True: 0, False: 0]
  |  Branch (74:68): [True: 0, False: 0]
  |  Branch (74:85): [True: 0, False: 0]
  |  Branch (74:104): [True: 0, False: 0]
  |  Branch (74:121): [True: 0, False: 0]
  ------------------
   75|      5|}
_ZN6Assimp27ConvertVrmlFileToX3dXmlFileERKNSt3__112basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEE:
   87|      5|std::stringstream ConvertVrmlFileToX3dXmlFile(const std::string &pFile) {
   88|      5|    std::stringstream ss;
   89|      5|    if (isFileWrlVrml97Ext(pFile) || isFileX3dvClassicVrmlExt(pFile)) {
  ------------------
  |  Branch (89:9): [True: 0, False: 5]
  |  Branch (89:38): [True: 0, False: 5]
  ------------------
   90|       |#if !defined(ASSIMP_BUILD_NO_VRML_IMPORTER)
   91|       |        VrmlTranslator::Scanner scanner = createScanner(pFile);
   92|       |        VrmlTranslator::Parser parser(&scanner);
   93|       |        parser.Parse();
   94|       |        ss.str("");
   95|       |        parser.doc_.save(ss);
   96|       |#endif // #if !defined(ASSIMP_BUILD_NO_VRML_IMPORTER)
   97|      0|    }
   98|      5|    return ss;
   99|      5|}

_ZN6Assimp5XFile8TexEntryC2ERKNSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEEb:
   73|      5|            mName(pName), mIsNormalMap(pIsNormalMap) {
   74|       |        // empty
   75|      5|    }
_ZN6Assimp5XFile8MaterialC2Ev:
   90|      6|            mIsReference(false),
   91|       |            mSpecularExponent(),
   92|      6|            sceneIndex(SIZE_MAX) {
   93|       |        // empty
   94|      6|    }
_ZN6Assimp5XFile4MeshC2ERKNSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEE:
  128|     15|            : mName(pName),
  129|     15|              mNumTextures(0),
  130|     15|              mNumColorSets(0) {
  131|       |        // empty
  132|     15|    }
_ZN6Assimp5XFile4NodeC2EPS1_:
  149|    188|            mTrafoMatrix(), mParent(pParent) {
  150|       |        // empty
  151|    188|    }
_ZN6Assimp5XFile4NodeD2Ev:
  153|    150|    ~Node() {
  154|    295|        for (unsigned int a = 0; a < mChildren.size(); ++a) {
  ------------------
  |  Branch (154:34): [True: 145, False: 150]
  ------------------
  155|    145|            delete mChildren[a];
  156|    145|        }
  157|    157|        for (unsigned int a = 0; a < mMeshes.size(); ++a) {
  ------------------
  |  Branch (157:34): [True: 7, False: 150]
  ------------------
  158|      7|            delete mMeshes[a];
  159|      7|        }
  160|    150|    }
_ZN6Assimp5XFile9AnimationD2Ev:
  182|      6|    ~Animation() {
  183|    229|        for (unsigned int a = 0; a < mAnims.size(); a++)
  ------------------
  |  Branch (183:34): [True: 223, False: 6]
  ------------------
  184|    223|            delete mAnims[a];
  185|      6|    }
_ZN6Assimp5XFile5SceneC2Ev:
  199|     14|            : mRootNode(nullptr),
  200|     14|              mAnimTicksPerSecond(0) {
  201|       |        // empty
  202|     14|    }
_ZN6Assimp5XFile5SceneD2Ev:
  203|      5|    ~Scene() {
  204|      5|        delete mRootNode;
  205|      5|        mRootNode = nullptr;
  206|      5|        for (unsigned int a = 0; a < mGlobalMeshes.size(); ++a) {
  ------------------
  |  Branch (206:34): [True: 0, False: 5]
  ------------------
  207|      0|            delete mGlobalMeshes[a];
  208|      0|        }
  209|     11|        for (unsigned int a = 0; a < mAnims.size(); ++a) {
  ------------------
  |  Branch (209:34): [True: 6, False: 5]
  ------------------
  210|      6|            delete mAnims[a];
  211|      6|        }
  212|      5|    }

_ZNK6Assimp13XFileImporter7CanReadERKNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEPNS_8IOSystemEb:
   79|    572|bool XFileImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool /*checkSig*/) const {
   80|    572|    static constexpr uint32_t token[] = { AI_MAKE_MAGIC("xof ") };
   81|       |    return CheckMagicToken(pIOHandler, pFile, token, AI_COUNT_OF(token));
   82|    572|}
_ZNK6Assimp13XFileImporter7GetInfoEv:
   86|    648|const aiImporterDesc *XFileImporter::GetInfo() const {
   87|    648|    return &desc;
   88|    648|}
_ZN6Assimp13XFileImporter14InternReadFileERKNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEP7aiScenePNS_8IOSystemE:
   92|     14|void XFileImporter::InternReadFile(const std::string &pFile, aiScene *pScene, IOSystem *pIOHandler) {
   93|       |    // read file into memory
   94|     14|    std::unique_ptr<IOStream> file(pIOHandler->Open(pFile));
   95|     14|    if (file == nullptr) {
  ------------------
  |  Branch (95:9): [True: 0, False: 14]
  ------------------
   96|      0|        throw DeadlyImportError("Failed to open file ", pFile, ".");
   97|      0|    }
   98|       |
   99|     14|    static const size_t MinSize = 16;
  100|     14|    size_t fileSize = file->FileSize();
  101|     14|    if (fileSize < MinSize) {
  ------------------
  |  Branch (101:9): [True: 0, False: 14]
  ------------------
  102|      0|        throw DeadlyImportError("XFile is too small.");
  103|      0|    }
  104|       |
  105|       |    // in the hope that binary files will never start with a BOM ...
  106|     14|    mBuffer.resize(fileSize + 1);
  107|     14|    file->Read(&mBuffer.front(), 1, fileSize);
  108|     14|    ConvertToUTF8(mBuffer);
  109|       |
  110|       |    // parse the file into a temporary representation
  111|     14|    XFileParser parser(mBuffer);
  112|       |
  113|       |    // and create the proper return structures out of it
  114|     14|    CreateDataRepresentationFromImport(pScene, parser.GetImportedData());
  115|       |
  116|       |    // if nothing came from it, report it as error
  117|     14|    if (!pScene->mRootNode) {
  ------------------
  |  Branch (117:9): [True: 0, False: 14]
  ------------------
  118|      0|        throw DeadlyImportError("XFile is ill-formatted - no content imported.");
  119|      0|    }
  120|     14|}
_ZN6Assimp13XFileImporter34CreateDataRepresentationFromImportEP7aiScenePNS_5XFile5SceneE:
  124|      5|void XFileImporter::CreateDataRepresentationFromImport(aiScene *pScene, XFile::Scene *pData) {
  125|       |    // Read the global materials first so that meshes referring to them can find them later
  126|      5|    ConvertMaterials(pScene, pData->mGlobalMaterials);
  127|       |
  128|       |    // copy nodes, extracting meshes and materials on the way
  129|      5|    pScene->mRootNode = CreateNodes(pScene, nullptr, pData->mRootNode);
  130|       |
  131|       |    // extract animations
  132|      5|    CreateAnimations(pScene, pData);
  133|       |
  134|       |    // read the global meshes that were stored outside of any node
  135|      5|    if (!pData->mGlobalMeshes.empty()) {
  ------------------
  |  Branch (135:9): [True: 0, False: 5]
  ------------------
  136|       |        // create a root node to hold them if there isn't any, yet
  137|      0|        if (pScene->mRootNode == nullptr) {
  ------------------
  |  Branch (137:13): [True: 0, False: 0]
  ------------------
  138|      0|            pScene->mRootNode = new aiNode;
  139|      0|            pScene->mRootNode->mName.Set("$dummy_node");
  140|      0|        }
  141|       |
  142|       |        // convert all global meshes and store them in the root node.
  143|       |        // If there was one before, the global meshes now suddenly have its transformation matrix...
  144|       |        // Don't know what to do there, I don't want to insert another node under the present root node
  145|       |        // just to avoid this.
  146|      0|        CreateMeshes(pScene, pScene->mRootNode, pData->mGlobalMeshes);
  147|      0|    }
  148|       |
  149|      5|    if (!pScene->mRootNode) {
  ------------------
  |  Branch (149:9): [True: 0, False: 5]
  ------------------
  150|      0|        throw DeadlyImportError("No root node");
  151|      0|    }
  152|       |
  153|       |    // Convert everything to OpenGL space... it's the same operation as the conversion back, so we can reuse the step directly
  154|      5|    MakeLeftHandedProcess convertProcess;
  155|      5|    convertProcess.Execute(pScene);
  156|       |
  157|      5|    FlipWindingOrderProcess flipper;
  158|      5|    flipper.Execute(pScene);
  159|       |
  160|       |    // finally: create a dummy material if not material was imported
  161|      5|    if (pScene->mNumMaterials == 0) {
  ------------------
  |  Branch (161:9): [True: 2, False: 3]
  ------------------
  162|      2|        pScene->mNumMaterials = 1;
  163|       |        // create the Material
  164|      2|        aiMaterial *mat = new aiMaterial;
  165|      2|        int shadeMode = (int)aiShadingMode_Gouraud;
  166|      2|        mat->AddProperty<int>(&shadeMode, 1, AI_MATKEY_SHADING_MODEL);
  167|       |        // material colours
  168|      2|        int specExp = 1;
  169|       |
  170|      2|        aiColor3D clr = aiColor3D(0, 0, 0);
  171|      2|        mat->AddProperty(&clr, 1, AI_MATKEY_COLOR_EMISSIVE);
  172|      2|        mat->AddProperty(&clr, 1, AI_MATKEY_COLOR_SPECULAR);
  173|       |
  174|      2|        clr = aiColor3D(0.5f, 0.5f, 0.5f);
  175|      2|        mat->AddProperty(&clr, 1, AI_MATKEY_COLOR_DIFFUSE);
  176|      2|        mat->AddProperty(&specExp, 1, AI_MATKEY_SHININESS);
  177|       |
  178|      2|        pScene->mMaterials = new aiMaterial *[1];
  179|      2|        pScene->mMaterials[0] = mat;
  180|      2|    }
  181|      5|}
_ZN6Assimp13XFileImporter11CreateNodesEP7aiSceneP6aiNodePKNS_5XFile4NodeE:
  185|    150|aiNode *XFileImporter::CreateNodes(aiScene *pScene, aiNode *pParent, const XFile::Node *pNode) {
  186|    150|    if (!pNode) {
  ------------------
  |  Branch (186:9): [True: 0, False: 150]
  ------------------
  187|      0|        return nullptr;
  188|      0|    }
  189|       |
  190|       |    // create node
  191|    150|    aiNode *node = new aiNode;
  192|    150|    node->mName.length = (ai_uint32)pNode->mName.length();
  193|    150|    node->mParent = pParent;
  194|    150|    memcpy(node->mName.data, pNode->mName.c_str(), pNode->mName.length());
  195|    150|    node->mName.data[node->mName.length] = 0;
  196|    150|    node->mTransformation = pNode->mTrafoMatrix;
  197|       |
  198|       |    // convert meshes from the source node
  199|    150|    CreateMeshes(pScene, node, pNode->mMeshes);
  200|       |
  201|       |    // handle children
  202|    150|    if (!pNode->mChildren.empty()) {
  ------------------
  |  Branch (202:9): [True: 100, False: 50]
  ------------------
  203|    100|        node->mNumChildren = (unsigned int)pNode->mChildren.size();
  204|    100|        node->mChildren = new aiNode *[node->mNumChildren];
  205|       |
  206|    245|        for (unsigned int a = 0; a < pNode->mChildren.size(); ++a) {
  ------------------
  |  Branch (206:34): [True: 145, False: 100]
  ------------------
  207|    145|            node->mChildren[a] = CreateNodes(pScene, node, pNode->mChildren[a]);
  208|    145|        }
  209|    100|    }
  210|       |
  211|    150|    return node;
  212|    150|}
_ZN6Assimp13XFileImporter12CreateMeshesEP7aiSceneP6aiNodeRKNSt3__16vectorIPNS_5XFile4MeshENS5_9allocatorIS9_EEEE:
  216|    150|void XFileImporter::CreateMeshes(aiScene *pScene, aiNode *pNode, const std::vector<XFile::Mesh *> &pMeshes) {
  217|    150|    if (pMeshes.empty()) {
  ------------------
  |  Branch (217:9): [True: 143, False: 7]
  ------------------
  218|    143|        return;
  219|    143|    }
  220|       |
  221|       |    // create a mesh for each mesh-material combination in the source node
  222|      7|    std::vector<aiMesh *> meshes;
  223|     14|    for (unsigned int a = 0; a < pMeshes.size(); ++a) {
  ------------------
  |  Branch (223:30): [True: 7, False: 7]
  ------------------
  224|      7|        XFile::Mesh *sourceMesh = pMeshes[a];
  225|      7|        if (nullptr == sourceMesh) {
  ------------------
  |  Branch (225:13): [True: 0, False: 7]
  ------------------
  226|      0|            continue;
  227|      0|        }
  228|       |
  229|       |        // first convert its materials so that we can find them with their index afterwards
  230|      7|        ConvertMaterials(pScene, sourceMesh->mMaterials);
  231|       |
  232|      7|        unsigned int numMaterials = std::max((unsigned int)sourceMesh->mMaterials.size(), 1u);
  233|     16|        for (unsigned int b = 0; b < numMaterials; ++b) {
  ------------------
  |  Branch (233:34): [True: 9, False: 7]
  ------------------
  234|       |            // collect the faces belonging to this material
  235|      9|            std::vector<unsigned int> faces;
  236|      9|            unsigned int numVertices = 0;
  237|      9|            if (!sourceMesh->mFaceMaterials.empty()) {
  ------------------
  |  Branch (237:17): [True: 5, False: 4]
  ------------------
  238|       |                // if there is a per-face material defined, select the faces with the corresponding material
  239|  13.1k|                for (unsigned int c = 0; c < sourceMesh->mFaceMaterials.size(); ++c) {
  ------------------
  |  Branch (239:42): [True: 13.1k, False: 5]
  ------------------
  240|  13.1k|                    if (sourceMesh->mFaceMaterials[c] == b) {
  ------------------
  |  Branch (240:25): [True: 9.39k, False: 3.79k]
  ------------------
  241|  9.39k|                        faces.push_back(c);
  242|  9.39k|                        numVertices += (unsigned int)sourceMesh->mPosFaces[c].mIndices.size();
  243|  9.39k|                    }
  244|  13.1k|                }
  245|      5|            } else {
  246|       |                // if there is no per-face material, place everything into one mesh
  247|  8.86k|                for (unsigned int c = 0; c < sourceMesh->mPosFaces.size(); ++c) {
  ------------------
  |  Branch (247:42): [True: 8.85k, False: 4]
  ------------------
  248|  8.85k|                    faces.push_back(c);
  249|  8.85k|                    numVertices += (unsigned int)sourceMesh->mPosFaces[c].mIndices.size();
  250|  8.85k|                }
  251|      4|            }
  252|       |
  253|       |            // no faces/vertices using this material? strange...
  254|      9|            if (numVertices == 0) {
  ------------------
  |  Branch (254:17): [True: 1, False: 8]
  ------------------
  255|      1|                continue;
  256|      1|            }
  257|       |
  258|       |            // create a submesh using this material
  259|      8|            aiMesh *mesh = new aiMesh;
  260|      8|            meshes.push_back(mesh);
  261|       |
  262|       |            // find the material in the scene's material list. Either own material
  263|       |            // or referenced material, it should already have a valid index
  264|      8|            if (!sourceMesh->mFaceMaterials.empty()) {
  ------------------
  |  Branch (264:17): [True: 4, False: 4]
  ------------------
  265|      4|                mesh->mMaterialIndex = static_cast<unsigned int>(sourceMesh->mMaterials[b].sceneIndex);
  266|      4|            } else {
  267|      4|                mesh->mMaterialIndex = 0;
  268|      4|            }
  269|       |
  270|       |            // Create properly sized data arrays in the mesh. We store unique vertices per face,
  271|       |            // as specified
  272|      8|            mesh->mNumVertices = numVertices;
  273|      8|            mesh->mVertices = new aiVector3D[numVertices];
  274|      8|            mesh->mNumFaces = (unsigned int)faces.size();
  275|      8|            mesh->mFaces = new aiFace[mesh->mNumFaces];
  276|       |
  277|       |            // name
  278|      8|            mesh->mName.Set(sourceMesh->mName);
  279|       |
  280|       |            // normals?
  281|      8|            if (sourceMesh->mNormals.size() > 0) {
  ------------------
  |  Branch (281:17): [True: 8, False: 0]
  ------------------
  282|      8|                mesh->mNormals = new aiVector3D[numVertices];
  283|      8|            }
  284|       |            // texture coords
  285|     72|            for (unsigned int c = 0; c < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++c) {
  ------------------
  |  Branch (285:38): [True: 64, False: 8]
  ------------------
  286|     64|                if (!sourceMesh->mTexCoords[c].empty()) {
  ------------------
  |  Branch (286:21): [True: 8, False: 56]
  ------------------
  287|      8|                    mesh->mTextureCoords[c] = new aiVector3D[numVertices];
  288|      8|                }
  289|     64|            }
  290|       |            // vertex colors
  291|     72|            for (unsigned int c = 0; c < AI_MAX_NUMBER_OF_COLOR_SETS; ++c) {
  ------------------
  |  Branch (291:38): [True: 64, False: 8]
  ------------------
  292|     64|                if (!sourceMesh->mColors[c].empty()) {
  ------------------
  |  Branch (292:21): [True: 0, False: 64]
  ------------------
  293|      0|                    mesh->mColors[c] = new aiColor4D[numVertices];
  294|      0|                }
  295|     64|            }
  296|       |
  297|       |            // now collect the vertex data of all data streams present in the imported mesh
  298|      8|            unsigned int newIndex(0);
  299|      8|            std::vector<unsigned int> orgPoints; // from which original point each new vertex stems
  300|      8|            orgPoints.resize(numVertices, 0);
  301|       |
  302|  18.2k|            for (unsigned int c = 0; c < faces.size(); ++c) {
  ------------------
  |  Branch (302:38): [True: 18.2k, False: 8]
  ------------------
  303|  18.2k|                unsigned int f = faces[c]; // index of the source face
  304|  18.2k|                const XFile::Face &pf = sourceMesh->mPosFaces[f]; // position source face
  305|       |
  306|       |                // create face. either triangle or triangle fan depending on the index count
  307|  18.2k|                aiFace &df = mesh->mFaces[c]; // destination face
  308|  18.2k|                df.mNumIndices = (unsigned int)pf.mIndices.size();
  309|  18.2k|                df.mIndices = new unsigned int[df.mNumIndices];
  310|       |
  311|       |                // collect vertex data for indices of this face
  312|  73.0k|                for (unsigned int d = 0; d < df.mNumIndices; ++d) {
  ------------------
  |  Branch (312:42): [True: 54.7k, False: 18.2k]
  ------------------
  313|  54.7k|                    df.mIndices[d] = newIndex;
  314|  54.7k|                    const unsigned int newIdx = pf.mIndices[d];
  315|  54.7k|                    if (newIdx >= sourceMesh->mPositions.size()) {
  ------------------
  |  Branch (315:25): [True: 0, False: 54.7k]
  ------------------
  316|      0|                        continue;
  317|      0|                    }
  318|       |
  319|  54.7k|                    orgPoints[newIndex] = pf.mIndices[d];
  320|       |
  321|       |                    // Position
  322|  54.7k|                    mesh->mVertices[newIndex] = sourceMesh->mPositions[pf.mIndices[d]];
  323|       |                    // Normal, if present
  324|  54.7k|                    if (mesh->HasNormals()) {
  ------------------
  |  Branch (324:25): [True: 54.7k, False: 0]
  ------------------
  325|  54.7k|                        if (sourceMesh->mNormFaces[f].mIndices.size() > d) {
  ------------------
  |  Branch (325:29): [True: 54.7k, False: 0]
  ------------------
  326|  54.7k|                            const size_t idx(sourceMesh->mNormFaces[f].mIndices[d]);
  327|  54.7k|                            if (idx < sourceMesh->mNormals.size()) {
  ------------------
  |  Branch (327:33): [True: 54.7k, False: 0]
  ------------------
  328|  54.7k|                                mesh->mNormals[newIndex] = sourceMesh->mNormals[idx];
  329|  54.7k|                            }
  330|  54.7k|                        }
  331|  54.7k|                    }
  332|       |
  333|       |                    // texture coord sets
  334|   492k|                    for (unsigned int e = 0; e < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++e) {
  ------------------
  |  Branch (334:46): [True: 438k, False: 54.7k]
  ------------------
  335|   438k|                        if (mesh->HasTextureCoords(e)) {
  ------------------
  |  Branch (335:29): [True: 54.7k, False: 383k]
  ------------------
  336|  54.7k|                            aiVector2D tex = sourceMesh->mTexCoords[e][pf.mIndices[d]];
  337|  54.7k|                            mesh->mTextureCoords[e][newIndex] = aiVector3D(tex.x, 1.0f - tex.y, 0.0f);
  338|  54.7k|                        }
  339|   438k|                    }
  340|       |                    // vertex color sets
  341|   492k|                    for (unsigned int e = 0; e < AI_MAX_NUMBER_OF_COLOR_SETS; ++e) {
  ------------------
  |  Branch (341:46): [True: 438k, False: 54.7k]
  ------------------
  342|   438k|                        if (mesh->HasVertexColors(e)) {
  ------------------
  |  Branch (342:29): [True: 0, False: 438k]
  ------------------
  343|      0|                            mesh->mColors[e][newIndex] = sourceMesh->mColors[e][pf.mIndices[d]];
  344|      0|                        }
  345|   438k|                    }
  346|       |
  347|  54.7k|                    newIndex++;
  348|  54.7k|                }
  349|  18.2k|            }
  350|       |
  351|       |            // there should be as much new vertices as we calculated before
  352|      8|            ai_assert(newIndex == numVertices);
  353|       |
  354|       |            // convert all bones of the source mesh which influence vertices in this newly created mesh
  355|      8|            const std::vector<XFile::Bone> &bones = sourceMesh->mBones;
  356|      8|            std::vector<aiBone *> newBones;
  357|    183|            for (unsigned int c = 0; c < bones.size(); ++c) {
  ------------------
  |  Branch (357:38): [True: 175, False: 8]
  ------------------
  358|    175|                const XFile::Bone &obone = bones[c];
  359|       |                // set up a vertex-linear array of the weights for quick searching if a bone influences a vertex
  360|    175|                std::vector<ai_real> oldWeights(sourceMesh->mPositions.size(), 0.0);
  361|  20.0k|                for (unsigned int d = 0; d < obone.mWeights.size(); ++d) {
  ------------------
  |  Branch (361:42): [True: 19.8k, False: 175]
  ------------------
  362|       |                    // TODO  The conditional against boneIdx which was added in commit f844c33
  363|       |                    // TODO      (https://github.com/assimp/assimp/commit/f844c3397d7726477ab0fdca8efd3df56c18366b)
  364|       |                    // TODO  causes massive breakage as detailed in:
  365|       |                    // TODO      https://github.com/assimp/assimp/issues/5332
  366|       |                    // TODO  In cases like this unit tests are less useful, since the model still has
  367|       |                    // TODO  meshes, textures, animations etc. and asserts against these values may pass;
  368|       |                    // TODO  when touching importer code, it is crucial that developers also run manual, visual
  369|       |                    // TODO  checks to ensure there's no obvious breakage _before_ commiting to main branch
  370|       |                    //const unsigned int boneIdx = obone.mWeights[d].mVertex;
  371|       |                    //if (boneIdx < obone.mWeights.size()) {
  372|  19.8k|                        oldWeights[obone.mWeights[d].mVertex] = obone.mWeights[d].mWeight;
  373|       |                    //}
  374|  19.8k|                }
  375|       |
  376|       |                // collect all vertex weights that influence a vertex in the new mesh
  377|    175|                std::vector<aiVertexWeight> newWeights;
  378|    175|                newWeights.reserve(numVertices);
  379|   949k|                for (unsigned int d = 0; d < orgPoints.size(); ++d) {
  ------------------
  |  Branch (379:42): [True: 949k, False: 175]
  ------------------
  380|       |                    // does the new vertex stem from an old vertex which was influenced by this bone?
  381|   949k|                    ai_real w = oldWeights[orgPoints[d]];
  382|   949k|                    if (w > 0.0) {
  ------------------
  |  Branch (382:25): [True: 57.6k, False: 891k]
  ------------------
  383|  57.6k|                        newWeights.emplace_back(d, w);
  384|  57.6k|                    }
  385|   949k|                }
  386|       |
  387|       |                // if the bone has no weights in the newly created mesh, ignore it
  388|    175|                if (newWeights.empty()) {
  ------------------
  |  Branch (388:21): [True: 40, False: 135]
  ------------------
  389|     40|                    continue;
  390|     40|                }
  391|       |
  392|       |                // create
  393|    135|                aiBone *nbone = new aiBone;
  394|    135|                newBones.push_back(nbone);
  395|       |                // copy name and matrix
  396|    135|                nbone->mName.Set(obone.mName);
  397|    135|                nbone->mOffsetMatrix = obone.mOffsetMatrix;
  398|    135|                nbone->mNumWeights = (unsigned int)newWeights.size();
  399|    135|                nbone->mWeights = new aiVertexWeight[nbone->mNumWeights];
  400|  57.7k|                for (unsigned int d = 0; d < newWeights.size(); ++d) {
  ------------------
  |  Branch (400:42): [True: 57.6k, False: 135]
  ------------------
  401|  57.6k|                    nbone->mWeights[d] = newWeights[d];
  402|  57.6k|                }
  403|    135|            }
  404|       |
  405|       |            // store the bones in the mesh
  406|      8|            mesh->mNumBones = (unsigned int)newBones.size();
  407|      8|            if (!newBones.empty()) {
  ------------------
  |  Branch (407:17): [True: 7, False: 1]
  ------------------
  408|      7|                mesh->mBones = new aiBone *[mesh->mNumBones];
  409|      7|                std::copy(newBones.begin(), newBones.end(), mesh->mBones);
  410|      7|            }
  411|      8|        }
  412|      7|    }
  413|       |
  414|       |    // reallocate scene mesh array to be large enough
  415|      7|    aiMesh **prevArray = pScene->mMeshes;
  416|      7|    pScene->mMeshes = new aiMesh *[pScene->mNumMeshes + meshes.size()];
  417|      7|    if (prevArray) {
  ------------------
  |  Branch (417:9): [True: 2, False: 5]
  ------------------
  418|      2|        memcpy(pScene->mMeshes, prevArray, pScene->mNumMeshes * sizeof(aiMesh *));
  419|      2|        delete[] prevArray;
  420|      2|    }
  421|       |
  422|       |    // allocate mesh index array in the node
  423|      7|    pNode->mNumMeshes = (unsigned int)meshes.size();
  424|      7|    pNode->mMeshes = new unsigned int[pNode->mNumMeshes];
  425|       |
  426|       |    // store all meshes in the mesh library of the scene and store their indices in the node
  427|     15|    for (unsigned int a = 0; a < meshes.size(); a++) {
  ------------------
  |  Branch (427:30): [True: 8, False: 7]
  ------------------
  428|      8|        pScene->mMeshes[pScene->mNumMeshes] = meshes[a];
  429|      8|        pNode->mMeshes[a] = pScene->mNumMeshes;
  430|      8|        pScene->mNumMeshes++;
  431|      8|    }
  432|      7|}
_ZN6Assimp13XFileImporter16CreateAnimationsEP7aiScenePKNS_5XFile5SceneE:
  436|      5|void XFileImporter::CreateAnimations(aiScene *pScene, const XFile::Scene *pData) {
  437|      5|    std::vector<aiAnimation *> newAnims;
  438|       |
  439|     11|    for (unsigned int a = 0; a < pData->mAnims.size(); ++a) {
  ------------------
  |  Branch (439:30): [True: 6, False: 5]
  ------------------
  440|      6|        const XFile::Animation *anim = pData->mAnims[a];
  441|       |        // some exporters mock me with empty animation tags.
  442|      6|        if (anim->mAnims.empty()) {
  ------------------
  |  Branch (442:13): [True: 0, False: 6]
  ------------------
  443|      0|            continue;
  444|      0|        }
  445|       |
  446|       |        // create a new animation to hold the data
  447|      6|        aiAnimation *nanim = new aiAnimation;
  448|      6|        newAnims.push_back(nanim);
  449|      6|        nanim->mName.Set(anim->mName);
  450|       |        // duration will be determined by the maximum length
  451|      6|        nanim->mDuration = 0;
  452|      6|        nanim->mTicksPerSecond = pData->mAnimTicksPerSecond;
  453|      6|        nanim->mNumChannels = (unsigned int)anim->mAnims.size();
  454|      6|        nanim->mChannels = new aiNodeAnim *[nanim->mNumChannels];
  455|       |
  456|    229|        for (unsigned int b = 0; b < anim->mAnims.size(); ++b) {
  ------------------
  |  Branch (456:34): [True: 223, False: 6]
  ------------------
  457|    223|            const XFile::AnimBone *bone = anim->mAnims[b];
  458|    223|            aiNodeAnim *nbone = new aiNodeAnim;
  459|    223|            nbone->mNodeName.Set(bone->mBoneName);
  460|    223|            nanim->mChannels[b] = nbone;
  461|       |
  462|       |            // key-frames are given as combined transformation matrix keys
  463|    223|            if (!bone->mTrafoKeys.empty()) {
  ------------------
  |  Branch (463:17): [True: 0, False: 223]
  ------------------
  464|      0|                nbone->mNumPositionKeys = (unsigned int)bone->mTrafoKeys.size();
  465|      0|                nbone->mPositionKeys = new aiVectorKey[nbone->mNumPositionKeys];
  466|      0|                nbone->mNumRotationKeys = (unsigned int)bone->mTrafoKeys.size();
  467|      0|                nbone->mRotationKeys = new aiQuatKey[nbone->mNumRotationKeys];
  468|      0|                nbone->mNumScalingKeys = (unsigned int)bone->mTrafoKeys.size();
  469|      0|                nbone->mScalingKeys = new aiVectorKey[nbone->mNumScalingKeys];
  470|       |
  471|      0|                for (unsigned int c = 0; c < bone->mTrafoKeys.size(); ++c) {
  ------------------
  |  Branch (471:42): [True: 0, False: 0]
  ------------------
  472|       |                    // deconstruct each matrix into separate position, rotation and scaling
  473|      0|                    double time = bone->mTrafoKeys[c].mTime;
  474|      0|                    aiMatrix4x4 trafo = bone->mTrafoKeys[c].mMatrix;
  475|       |
  476|       |                    // extract position
  477|      0|                    aiVector3D pos(trafo.a4, trafo.b4, trafo.c4);
  478|       |
  479|      0|                    nbone->mPositionKeys[c].mTime = time;
  480|      0|                    nbone->mPositionKeys[c].mValue = pos;
  481|       |
  482|       |                    // extract scaling
  483|      0|                    aiVector3D scale;
  484|      0|                    scale.x = aiVector3D(trafo.a1, trafo.b1, trafo.c1).Length();
  485|      0|                    scale.y = aiVector3D(trafo.a2, trafo.b2, trafo.c2).Length();
  486|      0|                    scale.z = aiVector3D(trafo.a3, trafo.b3, trafo.c3).Length();
  487|      0|                    nbone->mScalingKeys[c].mTime = time;
  488|      0|                    nbone->mScalingKeys[c].mValue = scale;
  489|       |
  490|       |                    // reconstruct rotation matrix without scaling
  491|      0|                    aiMatrix3x3 rotmat(
  492|      0|                            trafo.a1 / scale.x, trafo.a2 / scale.y, trafo.a3 / scale.z,
  493|      0|                            trafo.b1 / scale.x, trafo.b2 / scale.y, trafo.b3 / scale.z,
  494|      0|                            trafo.c1 / scale.x, trafo.c2 / scale.y, trafo.c3 / scale.z);
  495|       |
  496|       |                    // and convert it into a quaternion
  497|      0|                    nbone->mRotationKeys[c].mTime = time;
  498|      0|                    nbone->mRotationKeys[c].mValue = aiQuaternion(rotmat);
  499|      0|                }
  500|       |
  501|       |                // longest lasting key sequence determines duration
  502|      0|                nanim->mDuration = std::max(nanim->mDuration, bone->mTrafoKeys.back().mTime);
  503|    223|            } else {
  504|       |                // separate key sequences for position, rotation, scaling
  505|    223|                nbone->mNumPositionKeys = (unsigned int)bone->mPosKeys.size();
  506|    223|                if (nbone->mNumPositionKeys != 0) {
  ------------------
  |  Branch (506:21): [True: 223, False: 0]
  ------------------
  507|    223|                    nbone->mPositionKeys = new aiVectorKey[nbone->mNumPositionKeys];
  508|  1.67k|                    for (unsigned int c = 0; c < nbone->mNumPositionKeys; ++c) {
  ------------------
  |  Branch (508:46): [True: 1.44k, False: 223]
  ------------------
  509|  1.44k|                        aiVector3D pos = bone->mPosKeys[c].mValue;
  510|       |
  511|  1.44k|                        nbone->mPositionKeys[c].mTime = bone->mPosKeys[c].mTime;
  512|  1.44k|                        nbone->mPositionKeys[c].mValue = pos;
  513|  1.44k|                    }
  514|    223|                }
  515|       |
  516|       |                // rotation
  517|    223|                nbone->mNumRotationKeys = (unsigned int)bone->mRotKeys.size();
  518|    223|                if (nbone->mNumRotationKeys != 0) {
  ------------------
  |  Branch (518:21): [True: 223, False: 0]
  ------------------
  519|    223|                    nbone->mRotationKeys = new aiQuatKey[nbone->mNumRotationKeys];
  520|  7.29k|                    for (unsigned int c = 0; c < nbone->mNumRotationKeys; ++c) {
  ------------------
  |  Branch (520:46): [True: 7.06k, False: 223]
  ------------------
  521|  7.06k|                        aiMatrix3x3 rotmat = bone->mRotKeys[c].mValue.GetMatrix();
  522|       |
  523|  7.06k|                        nbone->mRotationKeys[c].mTime = bone->mRotKeys[c].mTime;
  524|  7.06k|                        nbone->mRotationKeys[c].mValue = aiQuaternion(rotmat);
  525|  7.06k|                        nbone->mRotationKeys[c].mValue.w *= -1.0f; // needs quat inversion
  526|  7.06k|                    }
  527|    223|                }
  528|       |
  529|       |                // scaling
  530|    223|                nbone->mNumScalingKeys = (unsigned int)bone->mScaleKeys.size();
  531|    223|                if (nbone->mNumScalingKeys != 0) {
  ------------------
  |  Branch (531:21): [True: 178, False: 45]
  ------------------
  532|    178|                    nbone->mScalingKeys = new aiVectorKey[nbone->mNumScalingKeys];
  533|    448|                    for (unsigned int c = 0; c < nbone->mNumScalingKeys; c++)
  ------------------
  |  Branch (533:46): [True: 270, False: 178]
  ------------------
  534|    270|                        nbone->mScalingKeys[c] = bone->mScaleKeys[c];
  535|    178|                }
  536|       |
  537|       |                // longest lasting key sequence determines duration
  538|    223|                if (bone->mPosKeys.size() > 0)
  ------------------
  |  Branch (538:21): [True: 223, False: 0]
  ------------------
  539|    223|                    nanim->mDuration = std::max(nanim->mDuration, bone->mPosKeys.back().mTime);
  540|    223|                if (bone->mRotKeys.size() > 0)
  ------------------
  |  Branch (540:21): [True: 223, False: 0]
  ------------------
  541|    223|                    nanim->mDuration = std::max(nanim->mDuration, bone->mRotKeys.back().mTime);
  542|    223|                if (bone->mScaleKeys.size() > 0)
  ------------------
  |  Branch (542:21): [True: 178, False: 45]
  ------------------
  543|    178|                    nanim->mDuration = std::max(nanim->mDuration, bone->mScaleKeys.back().mTime);
  544|    223|            }
  545|    223|        }
  546|      6|    }
  547|       |
  548|       |    // store all converted animations in the scene
  549|      5|    if (newAnims.size() > 0) {
  ------------------
  |  Branch (549:9): [True: 4, False: 1]
  ------------------
  550|      4|        pScene->mNumAnimations = (unsigned int)newAnims.size();
  551|      4|        pScene->mAnimations = new aiAnimation *[pScene->mNumAnimations];
  552|     10|        for (unsigned int a = 0; a < newAnims.size(); a++)
  ------------------
  |  Branch (552:34): [True: 6, False: 4]
  ------------------
  553|      6|            pScene->mAnimations[a] = newAnims[a];
  554|      4|    }
  555|      5|}
_ZN6Assimp13XFileImporter16ConvertMaterialsEP7aiSceneRNSt3__16vectorINS_5XFile8MaterialENS3_9allocatorIS6_EEEE:
  559|     12|void XFileImporter::ConvertMaterials(aiScene *pScene, std::vector<XFile::Material> &pMaterials) {
  560|       |    // count the non-referrer materials in the array
  561|     12|    unsigned int numNewMaterials(0);
  562|     17|    for (unsigned int a = 0; a < pMaterials.size(); ++a) {
  ------------------
  |  Branch (562:30): [True: 5, False: 12]
  ------------------
  563|      5|        if (!pMaterials[a].mIsReference) {
  ------------------
  |  Branch (563:13): [True: 5, False: 0]
  ------------------
  564|      5|            ++numNewMaterials;
  565|      5|        }
  566|      5|    }
  567|       |
  568|       |    // resize the scene's material list to offer enough space for the new materials
  569|     12|    if (numNewMaterials > 0) {
  ------------------
  |  Branch (569:9): [True: 3, False: 9]
  ------------------
  570|      3|        aiMaterial **prevMats = pScene->mMaterials;
  571|      3|        pScene->mMaterials = new aiMaterial *[pScene->mNumMaterials + numNewMaterials];
  572|      3|        if (nullptr != prevMats) {
  ------------------
  |  Branch (572:13): [True: 0, False: 3]
  ------------------
  573|      0|            ::memcpy(pScene->mMaterials, prevMats, pScene->mNumMaterials * sizeof(aiMaterial *));
  574|      0|            delete[] prevMats;
  575|      0|        }
  576|      3|    }
  577|       |
  578|       |    // convert all the materials given in the array
  579|     17|    for (unsigned int a = 0; a < pMaterials.size(); ++a) {
  ------------------
  |  Branch (579:30): [True: 5, False: 12]
  ------------------
  580|      5|        XFile::Material &oldMat = pMaterials[a];
  581|      5|        if (oldMat.mIsReference) {
  ------------------
  |  Branch (581:13): [True: 0, False: 5]
  ------------------
  582|       |            // find the material it refers to by name, and store its index
  583|      0|            for (size_t b = 0; b < pScene->mNumMaterials; ++b) {
  ------------------
  |  Branch (583:32): [True: 0, False: 0]
  ------------------
  584|      0|                aiString name;
  585|      0|                pScene->mMaterials[b]->Get(AI_MATKEY_NAME, name);
  586|      0|                if (strcmp(name.C_Str(), oldMat.mName.data()) == 0) {
  ------------------
  |  Branch (586:21): [True: 0, False: 0]
  ------------------
  587|      0|                    oldMat.sceneIndex = b;
  588|      0|                    break;
  589|      0|                }
  590|      0|            }
  591|       |
  592|      0|            if (oldMat.sceneIndex == SIZE_MAX) {
  ------------------
  |  Branch (592:17): [True: 0, False: 0]
  ------------------
  593|      0|                ASSIMP_LOG_WARN("Could not resolve global material reference \"", oldMat.mName, "\"");
  594|      0|                oldMat.sceneIndex = 0;
  595|      0|            }
  596|       |
  597|      0|            continue;
  598|      0|        }
  599|       |
  600|      5|        aiMaterial *mat = new aiMaterial;
  601|      5|        aiString name;
  602|      5|        name.Set(oldMat.mName);
  603|      5|        mat->AddProperty(&name, AI_MATKEY_NAME);
  604|       |
  605|       |        // Shading model: hard-coded to PHONG, there is no such information in an XFile
  606|       |        // FIX (aramis): If the specular exponent is 0, use gouraud shading. This is a bugfix
  607|       |        // for some models in the SDK (e.g. good old tiny.x)
  608|      5|        int shadeMode = (int)oldMat.mSpecularExponent == 0.0f ? aiShadingMode_Gouraud : aiShadingMode_Phong;
  ------------------
  |  Branch (608:25): [True: 4, False: 1]
  ------------------
  609|       |
  610|      5|        mat->AddProperty<int>(&shadeMode, 1, AI_MATKEY_SHADING_MODEL);
  611|       |        // material colours
  612|       |        // Unclear: there's no ambient colour, but emissive. What to put for ambient?
  613|       |        // Probably nothing at all, let the user select a suitable default.
  614|      5|        mat->AddProperty(&oldMat.mEmissive, 1, AI_MATKEY_COLOR_EMISSIVE);
  615|      5|        mat->AddProperty(&oldMat.mDiffuse, 1, AI_MATKEY_COLOR_DIFFUSE);
  616|      5|        mat->AddProperty(&oldMat.mSpecular, 1, AI_MATKEY_COLOR_SPECULAR);
  617|      5|        mat->AddProperty(&oldMat.mSpecularExponent, 1, AI_MATKEY_SHININESS);
  618|       |
  619|       |        // texture, if there is one
  620|      5|        if (1 == oldMat.mTextures.size()) {
  ------------------
  |  Branch (620:13): [True: 4, False: 1]
  ------------------
  621|      4|            const XFile::TexEntry &otex = oldMat.mTextures.back();
  622|      4|            if (otex.mName.length()) {
  ------------------
  |  Branch (622:17): [True: 3, False: 1]
  ------------------
  623|       |                // if there is only one texture assume it contains the diffuse color
  624|      3|                aiString tex(otex.mName);
  625|      3|                if (otex.mIsNormalMap) {
  ------------------
  |  Branch (625:21): [True: 0, False: 3]
  ------------------
  626|      0|                    mat->AddProperty(&tex, AI_MATKEY_TEXTURE_NORMALS(0));
  627|      3|                } else {
  628|      3|                    mat->AddProperty(&tex, AI_MATKEY_TEXTURE_DIFFUSE(0));
  629|      3|                }
  630|      3|            }
  631|      4|        } else {
  632|       |            // Otherwise ... try to search for typical strings in the
  633|       |            // texture's file name like 'bump' or 'diffuse'
  634|      1|            unsigned int iHM = 0, iNM = 0, iDM = 0, iSM = 0, iAM = 0, iEM = 0;
  635|      1|            for (unsigned int b = 0; b < oldMat.mTextures.size(); ++b) {
  ------------------
  |  Branch (635:38): [True: 0, False: 1]
  ------------------
  636|      0|                const XFile::TexEntry &otex = oldMat.mTextures[b];
  637|      0|                std::string sz = otex.mName;
  638|      0|                if (!sz.length()) {
  ------------------
  |  Branch (638:21): [True: 0, False: 0]
  ------------------
  639|      0|                    continue;
  640|      0|                }
  641|       |
  642|       |                // find the file name
  643|      0|                std::string::size_type s = sz.find_last_of("\\/");
  644|      0|                if (std::string::npos == s) {
  ------------------
  |  Branch (644:21): [True: 0, False: 0]
  ------------------
  645|      0|                    s = 0;
  646|      0|                }
  647|       |
  648|       |                // cut off the file extension
  649|      0|                std::string::size_type sExt = sz.find_last_of('.');
  650|      0|                if (std::string::npos != sExt) {
  ------------------
  |  Branch (650:21): [True: 0, False: 0]
  ------------------
  651|      0|                    sz[sExt] = '\0';
  652|      0|                }
  653|       |
  654|       |                // convert to lower case for easier comparison
  655|      0|                for (unsigned int c = 0; c < sz.length(); ++c) {
  ------------------
  |  Branch (655:42): [True: 0, False: 0]
  ------------------
  656|      0|                    sz[c] = (char)tolower((unsigned char)sz[c]);
  657|      0|                }
  658|       |
  659|       |                // Place texture filename property under the corresponding name
  660|      0|                aiString tex(oldMat.mTextures[b].mName);
  661|       |
  662|       |                // bump map
  663|      0|                if (std::string::npos != sz.find("bump", s) || std::string::npos != sz.find("height", s)) {
  ------------------
  |  Branch (663:21): [True: 0, False: 0]
  |  Branch (663:64): [True: 0, False: 0]
  ------------------
  664|      0|                    mat->AddProperty(&tex, AI_MATKEY_TEXTURE_HEIGHT(iHM++));
  665|      0|                } else if (otex.mIsNormalMap || std::string::npos != sz.find("normal", s) || std::string::npos != sz.find("nm", s)) {
  ------------------
  |  Branch (665:28): [True: 0, False: 0]
  |  Branch (665:49): [True: 0, False: 0]
  |  Branch (665:94): [True: 0, False: 0]
  ------------------
  666|      0|                    mat->AddProperty(&tex, AI_MATKEY_TEXTURE_NORMALS(iNM++));
  667|      0|                } else if (std::string::npos != sz.find("spec", s) || std::string::npos != sz.find("glanz", s)) {
  ------------------
  |  Branch (667:28): [True: 0, False: 0]
  |  Branch (667:71): [True: 0, False: 0]
  ------------------
  668|      0|                    mat->AddProperty(&tex, AI_MATKEY_TEXTURE_SPECULAR(iSM++));
  669|      0|                } else if (std::string::npos != sz.find("ambi", s) || std::string::npos != sz.find("env", s)) {
  ------------------
  |  Branch (669:28): [True: 0, False: 0]
  |  Branch (669:71): [True: 0, False: 0]
  ------------------
  670|      0|                    mat->AddProperty(&tex, AI_MATKEY_TEXTURE_AMBIENT(iAM++));
  671|      0|                } else if (std::string::npos != sz.find("emissive", s) || std::string::npos != sz.find("self", s)) {
  ------------------
  |  Branch (671:28): [True: 0, False: 0]
  |  Branch (671:75): [True: 0, False: 0]
  ------------------
  672|      0|                    mat->AddProperty(&tex, AI_MATKEY_TEXTURE_EMISSIVE(iEM++));
  673|      0|                } else {
  674|       |                    // Assume it is a diffuse texture
  675|      0|                    mat->AddProperty(&tex, AI_MATKEY_TEXTURE_DIFFUSE(iDM++));
  676|      0|                }
  677|      0|            }
  678|      1|        }
  679|       |
  680|      5|        pScene->mMaterials[pScene->mNumMaterials] = mat;
  681|      5|        oldMat.sceneIndex = pScene->mNumMaterials;
  682|      5|        pScene->mNumMaterials++;
  683|      5|    }
  684|     12|}

_ZN6Assimp13XFileImporterC2Ev:
   71|    624|    XFileImporter() = default;
_ZN6Assimp13XFileImporterD2Ev:
   72|    624|    ~XFileImporter() override = default;

_ZN6Assimp11XFileParserC2ERKNSt3__16vectorIcNS1_9allocatorIcEEEE:
   83|     14|        mMajorVersion(0), mMinorVersion(0), mIsBinaryFormat(false), mBinaryNumCount(0), mP(nullptr), mEnd(nullptr), mLineNumber(0), mScene(nullptr) {
   84|       |    // vector to store uncompressed file for INFLATE'd X files
   85|     14|    std::vector<char> uncompressed;
   86|       |
   87|       |    // set up memory pointers
   88|     14|    mP = &pBuffer.front();
   89|     14|    mEnd = mP + pBuffer.size() - 1;
   90|       |
   91|       |    // check header
   92|     14|    if (0 != strncmp(mP, "xof ", 4)) {
  ------------------
  |  Branch (92:9): [True: 0, False: 14]
  ------------------
   93|      0|        throw DeadlyImportError("Header mismatch, file is not an XFile.");
   94|      0|    }
   95|       |
   96|       |    // read version. It comes in a four byte format such as "0302"
   97|     14|    mMajorVersion = (unsigned int)(mP[4] - 48) * 10 + (unsigned int)(mP[5] - 48);
   98|     14|    mMinorVersion = (unsigned int)(mP[6] - 48) * 10 + (unsigned int)(mP[7] - 48);
   99|       |
  100|     14|    bool compressed = false;
  101|       |
  102|       |    // txt - pure ASCII text format
  103|     14|    if (strncmp(mP + 8, "txt ", 4) == 0)
  ------------------
  |  Branch (103:9): [True: 12, False: 2]
  ------------------
  104|     12|        mIsBinaryFormat = false;
  105|       |
  106|       |    // bin - Binary format
  107|      2|    else if (strncmp(mP + 8, "bin ", 4) == 0)
  ------------------
  |  Branch (107:14): [True: 2, False: 0]
  ------------------
  108|      2|        mIsBinaryFormat = true;
  109|       |
  110|       |    // tzip - Inflate compressed text format
  111|      0|    else if (strncmp(mP + 8, "tzip", 4) == 0) {
  ------------------
  |  Branch (111:14): [True: 0, False: 0]
  ------------------
  112|      0|        mIsBinaryFormat = false;
  113|      0|        compressed = true;
  114|      0|    }
  115|       |    // bzip - Inflate compressed binary format
  116|      0|    else if (strncmp(mP + 8, "bzip", 4) == 0) {
  ------------------
  |  Branch (116:14): [True: 0, False: 0]
  ------------------
  117|      0|        mIsBinaryFormat = true;
  118|      0|        compressed = true;
  119|      0|    } else
  120|      0|        ThrowException("Unsupported x-file format '", mP[8], mP[9], mP[10], mP[11], "'");
  121|       |
  122|       |    // float size
  123|     14|    mBinaryFloatSize = (unsigned int)(mP[12] - 48) * 1000 + (unsigned int)(mP[13] - 48) * 100 + (unsigned int)(mP[14] - 48) * 10 + (unsigned int)(mP[15] - 48);
  124|       |
  125|     14|    if (mBinaryFloatSize != 32 && mBinaryFloatSize != 64)
  ------------------
  |  Branch (125:9): [True: 0, False: 14]
  |  Branch (125:35): [True: 0, False: 0]
  ------------------
  126|      0|        ThrowException("Unknown float size ", mBinaryFloatSize, " specified in x-file header.");
  127|       |
  128|       |    // The x format specifies size in bits, but we work in bytes
  129|     14|    mBinaryFloatSize /= 8;
  130|       |
  131|     14|    mP += 16;
  132|       |
  133|       |    // If this is a compressed X file, apply the inflate algorithm to it
  134|     14|    if (compressed) {
  ------------------
  |  Branch (134:9): [True: 0, False: 14]
  ------------------
  135|       |#ifdef ASSIMP_BUILD_NO_COMPRESSED_X
  136|       |        throw DeadlyImportError("Assimp was built without compressed X support");
  137|       |#else
  138|       |        /* ///////////////////////////////////////////////////////////////////////
  139|       |         * COMPRESSED X FILE FORMAT
  140|       |         * ///////////////////////////////////////////////////////////////////////
  141|       |         *    [xhead]
  142|       |         *    2 major
  143|       |         *    2 minor
  144|       |         *    4 type    // bzip,tzip
  145|       |         *    [mszip_master_head]
  146|       |         *    4 unkn    // checksum?
  147|       |         *    2 unkn    // flags? (seems to be constant)
  148|       |         *    [mszip_head]
  149|       |         *    2 ofs     // offset to next section
  150|       |         *    2 magic   // 'CK'
  151|       |         *    ... ofs bytes of data
  152|       |         *    ... next mszip_head
  153|       |         *
  154|       |         *  http://www.kdedevelopers.org/node/3181 has been very helpful.
  155|       |         * ///////////////////////////////////////////////////////////////////////
  156|       |         */
  157|       |
  158|       |        // skip unknown data (checksum, flags?)
  159|      0|        mP += 6;
  160|       |
  161|       |        // First find out how much storage we'll need. Count sections.
  162|      0|        const char *P1 = mP;
  163|      0|        unsigned int est_out = 0;
  164|       |
  165|      0|        while (P1 + 3 < mEnd) {
  ------------------
  |  Branch (165:16): [True: 0, False: 0]
  ------------------
  166|       |            // read next offset
  167|      0|            uint16_t ofs = *((uint16_t *)P1);
  168|      0|            AI_SWAP2(ofs);
  169|      0|            P1 += 2;
  170|       |
  171|      0|            if (ofs >= MSZIP_BLOCK)
  ------------------
  |  Branch (171:17): [True: 0, False: 0]
  ------------------
  172|      0|                throw DeadlyImportError("X: Invalid offset to next MSZIP compressed block");
  173|       |
  174|       |            // check magic word
  175|      0|            uint16_t magic = *((uint16_t *)P1);
  176|      0|            AI_SWAP2(magic);
  177|      0|            P1 += 2;
  178|       |
  179|      0|            if (magic != MSZIP_MAGIC)
  ------------------
  |  Branch (179:17): [True: 0, False: 0]
  ------------------
  180|      0|                throw DeadlyImportError("X: Unsupported compressed format, expected MSZIP header");
  181|       |
  182|       |            // and advance to the next offset
  183|      0|            P1 += ofs;
  184|      0|            est_out += MSZIP_BLOCK; // one decompressed block is 327861 in size
  185|      0|        }
  186|       |
  187|       |        // Allocate storage and terminating zero and do the actual uncompressing
  188|      0|        Compression compression;
  189|      0|        uncompressed.resize(est_out + 1);
  190|      0|        char *out = &uncompressed.front();
  191|      0|        if (compression.open(mIsBinaryFormat ? Compression::Format::Binary : Compression::Format::ASCII,
  ------------------
  |  Branch (191:13): [True: 0, False: 0]
  |  Branch (191:30): [True: 0, False: 0]
  ------------------
  192|      0|                Compression::FlushMode::SyncFlush, -Compression::MaxWBits)) {
  193|      0|            while (mP + 3 < mEnd) {
  ------------------
  |  Branch (193:20): [True: 0, False: 0]
  ------------------
  194|      0|                uint16_t ofs = *((uint16_t *)mP);
  195|      0|                AI_SWAP2(ofs);
  196|      0|                mP += 4;
  197|       |
  198|      0|                if (mP + ofs > mEnd + 2) {
  ------------------
  |  Branch (198:21): [True: 0, False: 0]
  ------------------
  199|      0|                    throw DeadlyImportError("X: Unexpected EOF in compressed chunk");
  200|      0|                }
  201|      0|                out += compression.decompressBlock(mP, ofs, out, MSZIP_BLOCK);
  202|      0|                mP += ofs;
  203|      0|            }
  204|      0|            compression.close();
  205|      0|        }
  206|       |
  207|       |        // ok, update pointers to point to the uncompressed file data
  208|      0|        mP = &uncompressed[0];
  209|      0|        mEnd = out;
  210|       |
  211|       |        // FIXME: we don't need the compressed data anymore, could release
  212|       |        // it already for better memory usage. Consider breaking const-co.
  213|      0|        ASSIMP_LOG_INFO("Successfully decompressed MSZIP-compressed file");
  214|      0|#endif // !! ASSIMP_BUILD_NO_COMPRESSED_X
  215|     14|    } else {
  216|       |        // start reading here
  217|     14|        ReadUntilEndOfLine();
  218|     14|    }
  219|       |
  220|     14|    mScene = new Scene;
  221|     14|    ParseFile();
  222|       |
  223|       |    // filter the imported hierarchy for some degenerated cases
  224|     14|    if (mScene->mRootNode) {
  ------------------
  |  Branch (224:9): [True: 5, False: 9]
  ------------------
  225|      5|        FilterHierarchy(mScene->mRootNode);
  226|      5|    }
  227|     14|}
_ZN6Assimp11XFileParserD2Ev:
  231|      5|XFileParser::~XFileParser() {
  232|       |    // kill everything we created
  233|      5|    delete mScene;
  234|      5|}
_ZN6Assimp11XFileParser9ParseFileEv:
  237|     14|void XFileParser::ParseFile() {
  238|     14|    bool running = true;
  239|    222|    while (running) {
  ------------------
  |  Branch (239:12): [True: 213, False: 9]
  ------------------
  240|       |        // read name of next object
  241|    213|        std::string objectName = GetNextToken();
  242|    213|        if (objectName.length() == 0) {
  ------------------
  |  Branch (242:13): [True: 5, False: 208]
  ------------------
  243|      5|            break;
  244|      5|        }
  245|       |
  246|       |        // parse specific object
  247|    208|        if (objectName == "template") {
  ------------------
  |  Branch (247:13): [True: 146, False: 62]
  ------------------
  248|    146|            ParseDataObjectTemplate();
  249|    146|        } else if (objectName == "Frame") {
  ------------------
  |  Branch (249:20): [True: 20, False: 42]
  ------------------
  250|     20|            ParseDataObjectFrame(nullptr);
  251|     42|        } else if (objectName == "Mesh") {
  ------------------
  |  Branch (251:20): [True: 0, False: 42]
  ------------------
  252|       |            // some meshes have no frames at all
  253|      0|            Mesh *mesh = new Mesh;
  254|      0|            ParseDataObjectMesh(mesh);
  255|      0|            mScene->mGlobalMeshes.push_back(mesh);
  256|     42|        } else if (objectName == "AnimTicksPerSecond")
  ------------------
  |  Branch (256:20): [True: 6, False: 36]
  ------------------
  257|      6|            ParseDataObjectAnimTicksPerSecond();
  258|     36|        else if (objectName == "AnimationSet")
  ------------------
  |  Branch (258:18): [True: 6, False: 30]
  ------------------
  259|      6|            ParseDataObjectAnimationSet();
  260|     30|        else if (objectName == "Material") {
  ------------------
  |  Branch (260:18): [True: 0, False: 30]
  ------------------
  261|       |            // Material outside of a mesh or node
  262|      0|            Material material;
  263|      0|            ParseDataObjectMaterial(&material);
  264|      0|            mScene->mGlobalMaterials.push_back(material);
  265|     30|        } else if (objectName == "}") {
  ------------------
  |  Branch (265:20): [True: 0, False: 30]
  ------------------
  266|       |            // whatever?
  267|      0|            ASSIMP_LOG_WARN("} found in dataObject");
  268|     30|        } else {
  269|       |            // unknown format
  270|       |            ASSIMP_LOG_WARN("Unknown data object in animation of .x file");
  271|     30|            ParseUnknownDataObject();
  272|     30|        }
  273|    208|    }
  274|     14|}
_ZN6Assimp11XFileParser23ParseDataObjectTemplateEv:
  277|    146|void XFileParser::ParseDataObjectTemplate() {
  278|       |    // parse a template data object. Currently not stored.
  279|    146|    std::string name;
  280|    146|    readHeadOfDataObject(&name);
  281|       |
  282|       |    // read GUID
  283|    146|    std::string guid = GetNextToken();
  284|       |
  285|       |    // read and ignore data members
  286|    146|    bool running = true;
  287|  1.17k|    while (running) {
  ------------------
  |  Branch (287:12): [True: 1.17k, False: 0]
  ------------------
  288|  1.17k|        std::string s = GetNextToken();
  289|       |
  290|  1.17k|        if (s == "}") {
  ------------------
  |  Branch (290:13): [True: 146, False: 1.02k]
  ------------------
  291|    146|            break;
  292|    146|        }
  293|       |
  294|  1.02k|        if (s.length() == 0) {
  ------------------
  |  Branch (294:13): [True: 0, False: 1.02k]
  ------------------
  295|      0|            ThrowException("Unexpected end of file reached while parsing template definition");
  296|      0|        }
  297|  1.02k|    }
  298|    146|}
_ZN6Assimp11XFileParser20ParseDataObjectFrameEPNS_5XFile4NodeE:
  301|    185|void XFileParser::ParseDataObjectFrame(Node *pParent) {
  302|       |    // A coordinate frame, or "frame of reference." The Frame template
  303|       |    // is open and can contain any object. The Direct3D extensions (D3DX)
  304|       |    // mesh-loading functions recognize Mesh, FrameTransformMatrix, and
  305|       |    // Frame template instances as child objects when loading a Frame
  306|       |    // instance.
  307|    185|    std::string name;
  308|    185|    readHeadOfDataObject(&name);
  309|       |
  310|       |    // create a named node and place it at its parent, if given
  311|    185|    Node *node = new Node(pParent);
  312|    185|    node->mName = name;
  313|    185|    if (pParent) {
  ------------------
  |  Branch (313:9): [True: 165, False: 20]
  ------------------
  314|    165|        pParent->mChildren.push_back(node);
  315|    165|    } else {
  316|       |        // there might be multiple root nodes
  317|     20|        if (mScene->mRootNode != nullptr) {
  ------------------
  |  Branch (317:13): [True: 6, False: 14]
  ------------------
  318|       |            // place a dummy root if not there
  319|      6|            if (mScene->mRootNode->mName != "$dummy_root") {
  ------------------
  |  Branch (319:17): [True: 3, False: 3]
  ------------------
  320|      3|                Node *exroot = mScene->mRootNode;
  321|      3|                mScene->mRootNode = new Node(nullptr);
  322|      3|                mScene->mRootNode->mName = "$dummy_root";
  323|      3|                mScene->mRootNode->mChildren.push_back(exroot);
  324|      3|                exroot->mParent = mScene->mRootNode;
  325|      3|            }
  326|       |            // put the new node as its child instead
  327|      6|            mScene->mRootNode->mChildren.push_back(node);
  328|      6|            node->mParent = mScene->mRootNode;
  329|     14|        } else {
  330|       |            // it's the first node imported. place it as root
  331|     14|            mScene->mRootNode = node;
  332|     14|        }
  333|     20|    }
  334|       |
  335|       |    // Now inside a frame.
  336|       |    // read tokens until closing brace is reached.
  337|    185|    bool running = true;
  338|    652|    while (running) {
  ------------------
  |  Branch (338:12): [True: 634, False: 18]
  ------------------
  339|    634|        std::string objectName = GetNextToken();
  340|    634|        if (objectName.size() == 0)
  ------------------
  |  Branch (340:13): [True: 1, False: 633]
  ------------------
  341|      1|            ThrowException("Unexpected end of file reached while parsing frame");
  342|       |
  343|    634|        if (objectName == "}")
  ------------------
  |  Branch (343:13): [True: 167, False: 467]
  ------------------
  344|    167|            break; // frame finished
  345|    467|        else if (objectName == "Frame")
  ------------------
  |  Branch (345:18): [True: 165, False: 302]
  ------------------
  346|    165|            ParseDataObjectFrame(node); // child frame
  347|    302|        else if (objectName == "FrameTransformMatrix")
  ------------------
  |  Branch (347:18): [True: 185, False: 117]
  ------------------
  348|    185|            ParseDataObjectTransformationMatrix(node->mTrafoMatrix);
  349|    117|        else if (objectName == "Mesh") {
  ------------------
  |  Branch (349:18): [True: 15, False: 102]
  ------------------
  350|     15|            Mesh *mesh = new Mesh(name);
  351|     15|            node->mMeshes.push_back(mesh);
  352|     15|            ParseDataObjectMesh(mesh);
  353|    102|        } else {
  354|       |            ASSIMP_LOG_WARN("Unknown data object in frame in x file");
  355|    102|            ParseUnknownDataObject();
  356|    102|        }
  357|    634|    }
  358|    185|}
_ZN6Assimp11XFileParser35ParseDataObjectTransformationMatrixER12aiMatrix4x4tIfE:
  361|    185|void XFileParser::ParseDataObjectTransformationMatrix(aiMatrix4x4 &pMatrix) {
  362|       |    // read header, we're not interested if it has a name
  363|    185|    readHeadOfDataObject();
  364|       |
  365|       |    // read its components
  366|    185|    pMatrix.a1 = ReadFloat();
  367|    185|    pMatrix.b1 = ReadFloat();
  368|    185|    pMatrix.c1 = ReadFloat();
  369|    185|    pMatrix.d1 = ReadFloat();
  370|    185|    pMatrix.a2 = ReadFloat();
  371|    185|    pMatrix.b2 = ReadFloat();
  372|    185|    pMatrix.c2 = ReadFloat();
  373|    185|    pMatrix.d2 = ReadFloat();
  374|    185|    pMatrix.a3 = ReadFloat();
  375|    185|    pMatrix.b3 = ReadFloat();
  376|    185|    pMatrix.c3 = ReadFloat();
  377|    185|    pMatrix.d3 = ReadFloat();
  378|    185|    pMatrix.a4 = ReadFloat();
  379|    185|    pMatrix.b4 = ReadFloat();
  380|    185|    pMatrix.c4 = ReadFloat();
  381|    185|    pMatrix.d4 = ReadFloat();
  382|       |
  383|       |    // trailing symbols
  384|    185|    CheckForSemicolon();
  385|    185|    CheckForClosingBrace();
  386|    185|}
_ZN6Assimp11XFileParser19ParseDataObjectMeshEPNS_5XFile4MeshE:
  389|     15|void XFileParser::ParseDataObjectMesh(Mesh *pMesh) {
  390|     15|    std::string name;
  391|     15|    readHeadOfDataObject(&name);
  392|       |
  393|       |    // read vertex count
  394|     15|    unsigned int numVertices = ReadInt();
  395|     15|    pMesh->mPositions.resize(numVertices);
  396|       |
  397|       |    // read vertices
  398|  30.5k|    for (unsigned int a = 0; a < numVertices; a++)
  ------------------
  |  Branch (398:30): [True: 30.5k, False: 15]
  ------------------
  399|  30.5k|        pMesh->mPositions[a] = ReadVector3();
  400|       |
  401|       |    // read position faces
  402|     15|    unsigned int numPosFaces = ReadInt();
  403|     15|    pMesh->mPosFaces.resize(numPosFaces);
  404|  34.9k|    for (unsigned int a = 0; a < numPosFaces; ++a) {
  ------------------
  |  Branch (404:30): [True: 34.9k, False: 15]
  ------------------
  405|       |        // read indices
  406|  34.9k|        unsigned int numIndices = ReadInt();
  407|  34.9k|        Face &face = pMesh->mPosFaces[a];
  408|   122k|        for (unsigned int b = 0; b < numIndices; ++b) {
  ------------------
  |  Branch (408:34): [True: 87.7k, False: 34.9k]
  ------------------
  409|  87.7k|            const int idx(ReadInt());
  410|  87.7k|            if (static_cast<unsigned int>(idx) <= numVertices) {
  ------------------
  |  Branch (410:17): [True: 87.7k, False: 1]
  ------------------
  411|  87.7k|                face.mIndices.push_back(idx);
  412|  87.7k|            }
  413|  87.7k|        }
  414|  34.9k|        TestForSeparator();
  415|  34.9k|    }
  416|       |
  417|       |    // here, other data objects may follow
  418|     15|    bool running = true;
  419|    208|    while (running) {
  ------------------
  |  Branch (419:12): [True: 201, False: 7]
  ------------------
  420|    201|        std::string objectName = GetNextToken();
  421|       |
  422|    201|        if (objectName.empty())
  ------------------
  |  Branch (422:13): [True: 1, False: 200]
  ------------------
  423|      1|            ThrowException("Unexpected end of file while parsing mesh structure");
  424|    200|        else if (objectName == "}")
  ------------------
  |  Branch (424:18): [True: 8, False: 192]
  ------------------
  425|      8|            break; // mesh finished
  426|    192|        else if (objectName == "MeshNormals")
  ------------------
  |  Branch (426:18): [True: 10, False: 182]
  ------------------
  427|     10|            ParseDataObjectMeshNormals(pMesh);
  428|    182|        else if (objectName == "MeshTextureCoords")
  ------------------
  |  Branch (428:18): [True: 9, False: 173]
  ------------------
  429|      9|            ParseDataObjectMeshTextureCoords(pMesh);
  430|    173|        else if (objectName == "MeshVertexColors")
  ------------------
  |  Branch (430:18): [True: 0, False: 173]
  ------------------
  431|      0|            ParseDataObjectMeshVertexColors(pMesh);
  432|    173|        else if (objectName == "MeshMaterialList")
  ------------------
  |  Branch (432:18): [True: 4, False: 169]
  ------------------
  433|      4|            ParseDataObjectMeshMaterialList(pMesh);
  434|    169|        else if (objectName == "VertexDuplicationIndices")
  ------------------
  |  Branch (434:18): [True: 3, False: 166]
  ------------------
  435|      3|            ParseUnknownDataObject(); // we'll ignore vertex duplication indices
  436|    166|        else if (objectName == "XSkinMeshHeader")
  ------------------
  |  Branch (436:18): [True: 7, False: 159]
  ------------------
  437|      7|            ParseDataObjectSkinMeshHeader(pMesh);
  438|    159|        else if (objectName == "SkinWeights")
  ------------------
  |  Branch (438:18): [True: 157, False: 2]
  ------------------
  439|    157|            ParseDataObjectSkinWeights(pMesh);
  440|      2|        else {
  441|       |            ASSIMP_LOG_WARN("Unknown data object in mesh in x file");
  442|      2|            ParseUnknownDataObject();
  443|      2|        }
  444|    201|    }
  445|     15|}
_ZN6Assimp11XFileParser26ParseDataObjectSkinWeightsEPNS_5XFile4MeshE:
  448|    157|void XFileParser::ParseDataObjectSkinWeights(Mesh *pMesh) {
  449|    157|    if (nullptr == pMesh) {
  ------------------
  |  Branch (449:9): [True: 0, False: 157]
  ------------------
  450|      0|        return;
  451|      0|    }
  452|    157|    readHeadOfDataObject();
  453|       |
  454|    157|    std::string transformNodeName;
  455|    157|    GetNextTokenAsString(transformNodeName);
  456|       |
  457|    157|    pMesh->mBones.emplace_back();
  458|    157|    Bone &bone = pMesh->mBones.back();
  459|    157|    bone.mName = transformNodeName;
  460|       |
  461|       |    // read vertex weights
  462|    157|    unsigned int numWeights = ReadInt();
  463|    157|    bone.mWeights.reserve(numWeights);
  464|       |
  465|  22.3k|    for (unsigned int a = 0; a < numWeights; a++) {
  ------------------
  |  Branch (465:30): [True: 22.1k, False: 157]
  ------------------
  466|  22.1k|        BoneWeight weight = {};
  467|  22.1k|        weight.mVertex = ReadInt();
  468|  22.1k|        bone.mWeights.push_back(weight);
  469|  22.1k|    }
  470|       |
  471|       |    // read vertex weights
  472|  22.1k|    for (unsigned int a = 0; a < numWeights; a++)
  ------------------
  |  Branch (472:30): [True: 22.0k, False: 157]
  ------------------
  473|  22.0k|        bone.mWeights[a].mWeight = ReadFloat();
  474|       |
  475|       |    // read matrix offset
  476|    157|    bone.mOffsetMatrix.a1 = ReadFloat();
  477|    157|    bone.mOffsetMatrix.b1 = ReadFloat();
  478|    157|    bone.mOffsetMatrix.c1 = ReadFloat();
  479|    157|    bone.mOffsetMatrix.d1 = ReadFloat();
  480|    157|    bone.mOffsetMatrix.a2 = ReadFloat();
  481|    157|    bone.mOffsetMatrix.b2 = ReadFloat();
  482|    157|    bone.mOffsetMatrix.c2 = ReadFloat();
  483|    157|    bone.mOffsetMatrix.d2 = ReadFloat();
  484|    157|    bone.mOffsetMatrix.a3 = ReadFloat();
  485|    157|    bone.mOffsetMatrix.b3 = ReadFloat();
  486|    157|    bone.mOffsetMatrix.c3 = ReadFloat();
  487|    157|    bone.mOffsetMatrix.d3 = ReadFloat();
  488|    157|    bone.mOffsetMatrix.a4 = ReadFloat();
  489|    157|    bone.mOffsetMatrix.b4 = ReadFloat();
  490|    157|    bone.mOffsetMatrix.c4 = ReadFloat();
  491|    157|    bone.mOffsetMatrix.d4 = ReadFloat();
  492|       |
  493|    157|    CheckForSemicolon();
  494|    157|    CheckForClosingBrace();
  495|    157|}
_ZN6Assimp11XFileParser29ParseDataObjectSkinMeshHeaderEPNS_5XFile4MeshE:
  498|      7|void XFileParser::ParseDataObjectSkinMeshHeader(Mesh * /*pMesh*/) {
  499|      7|    readHeadOfDataObject();
  500|       |
  501|       |    /*unsigned int maxSkinWeightsPerVertex =*/ReadInt();
  502|      7|    /*unsigned int maxSkinWeightsPerFace =*/ReadInt();
  503|      7|    /*unsigned int numBonesInMesh = */ ReadInt();
  504|       |
  505|      7|    CheckForClosingBrace();
  506|      7|}
_ZN6Assimp11XFileParser26ParseDataObjectMeshNormalsEPNS_5XFile4MeshE:
  509|     10|void XFileParser::ParseDataObjectMeshNormals(Mesh *pMesh) {
  510|     10|    readHeadOfDataObject();
  511|       |
  512|       |    // read count
  513|     10|    unsigned int numNormals = ReadInt();
  514|     10|    pMesh->mNormals.resize(numNormals);
  515|       |
  516|       |    // read normal vectors
  517|  18.7k|    for (unsigned int a = 0; a < numNormals; ++a) {
  ------------------
  |  Branch (517:30): [True: 18.7k, False: 10]
  ------------------
  518|  18.7k|        pMesh->mNormals[a] = ReadVector3();
  519|  18.7k|    }
  520|       |
  521|       |    // read normal indices
  522|     10|    unsigned int numFaces = ReadInt();
  523|     10|    if (numFaces != pMesh->mPosFaces.size()) {
  ------------------
  |  Branch (523:9): [True: 0, False: 10]
  ------------------
  524|      0|        ThrowException("Normal face count does not match vertex face count.");
  525|      0|    }
  526|       |
  527|       |    // do not crah when no face definitions are there
  528|     10|    if (numFaces > 0) {
  ------------------
  |  Branch (528:9): [True: 9, False: 1]
  ------------------
  529|       |        // normal face creation
  530|      9|        pMesh->mNormFaces.resize(numFaces);
  531|  22.0k|        for (unsigned int a = 0; a < numFaces; ++a) {
  ------------------
  |  Branch (531:34): [True: 21.9k, False: 9]
  ------------------
  532|  21.9k|            unsigned int numIndices = ReadInt();
  533|  21.9k|            pMesh->mNormFaces[a] = Face();
  534|  21.9k|            Face &face = pMesh->mNormFaces[a];
  535|  87.9k|            for (unsigned int b = 0; b < numIndices; ++b) {
  ------------------
  |  Branch (535:38): [True: 65.9k, False: 21.9k]
  ------------------
  536|  65.9k|                face.mIndices.push_back(ReadInt());
  537|  65.9k|            }
  538|       |
  539|  21.9k|            TestForSeparator();
  540|  21.9k|        }
  541|      9|    }
  542|       |
  543|     10|    CheckForClosingBrace();
  544|     10|}
_ZN6Assimp11XFileParser32ParseDataObjectMeshTextureCoordsEPNS_5XFile4MeshE:
  547|      9|void XFileParser::ParseDataObjectMeshTextureCoords(Mesh *pMesh) {
  548|      9|    readHeadOfDataObject();
  549|      9|    if (pMesh->mNumTextures + 1 > AI_MAX_NUMBER_OF_TEXTURECOORDS)
  ------------------
  |  Branch (549:9): [True: 0, False: 9]
  ------------------
  550|      0|        ThrowException("Too many sets of texture coordinates");
  551|       |
  552|      9|    std::vector<aiVector2D> &coords = pMesh->mTexCoords[pMesh->mNumTextures++];
  553|       |
  554|      9|    unsigned int numCoords = ReadInt();
  555|      9|    if (numCoords != pMesh->mPositions.size())
  ------------------
  |  Branch (555:9): [True: 0, False: 9]
  ------------------
  556|      0|        ThrowException("Texture coord count does not match vertex count");
  557|       |
  558|      9|    coords.resize(numCoords);
  559|  16.7k|    for (unsigned int a = 0; a < numCoords; a++)
  ------------------
  |  Branch (559:30): [True: 16.7k, False: 9]
  ------------------
  560|  16.7k|        coords[a] = ReadVector2();
  561|       |
  562|      9|    CheckForClosingBrace();
  563|      9|}
_ZN6Assimp11XFileParser31ParseDataObjectMeshMaterialListEPNS_5XFile4MeshE:
  596|      4|void XFileParser::ParseDataObjectMeshMaterialList(Mesh *pMesh) {
  597|      4|    readHeadOfDataObject();
  598|       |
  599|       |    // read material count
  600|       |    /*unsigned int numMaterials =*/ReadInt();
  601|       |    // read non triangulated face material index count
  602|      4|    unsigned int numMatIndices = ReadInt();
  603|       |
  604|       |    // some models have a material index count of 1... to be able to read them we
  605|       |    // replicate this single material index on every face
  606|      4|    if (numMatIndices != pMesh->mPosFaces.size() && numMatIndices != 1)
  ------------------
  |  Branch (606:9): [True: 0, False: 4]
  |  Branch (606:53): [True: 0, False: 0]
  ------------------
  607|      0|        ThrowException("Per-Face material index count does not match face count.");
  608|       |
  609|       |    // read per-face material indices
  610|  9.40k|    for (unsigned int a = 0; a < numMatIndices; a++)
  ------------------
  |  Branch (610:30): [True: 9.40k, False: 4]
  ------------------
  611|  9.40k|        pMesh->mFaceMaterials.push_back(ReadInt());
  612|       |
  613|       |    // in version 03.02, the face indices end with two semicolons.
  614|       |    // commented out version check, as version 03.03 exported from blender also has 2 semicolons
  615|      4|    if (!mIsBinaryFormat) // && MajorVersion == 3 && MinorVersion <= 2)
  ------------------
  |  Branch (615:9): [True: 3, False: 1]
  ------------------
  616|      3|    {
  617|      3|        if (mP < mEnd && *mP == ';')
  ------------------
  |  Branch (617:13): [True: 3, False: 0]
  |  Branch (617:26): [True: 0, False: 3]
  ------------------
  618|      0|            ++mP;
  619|      3|    }
  620|       |
  621|       |    // if there was only a single material index, replicate it on all faces
  622|      4|    while (pMesh->mFaceMaterials.size() < pMesh->mPosFaces.size())
  ------------------
  |  Branch (622:12): [True: 0, False: 4]
  ------------------
  623|      0|        pMesh->mFaceMaterials.push_back(pMesh->mFaceMaterials.front());
  624|       |
  625|       |    // read following data objects
  626|      4|    bool running = true;
  627|     10|    while (running) {
  ------------------
  |  Branch (627:12): [True: 10, False: 0]
  ------------------
  628|     10|        std::string objectName = GetNextToken();
  629|     10|        if (objectName.size() == 0)
  ------------------
  |  Branch (629:13): [True: 0, False: 10]
  ------------------
  630|      0|            ThrowException("Unexpected end of file while parsing mesh material list.");
  631|     10|        else if (objectName == "}")
  ------------------
  |  Branch (631:18): [True: 4, False: 6]
  ------------------
  632|      4|            break; // material list finished
  633|      6|        else if (objectName == "{") {
  ------------------
  |  Branch (633:18): [True: 0, False: 6]
  ------------------
  634|       |            // template materials
  635|      0|            std::string matName = GetNextToken();
  636|      0|            Material material;
  637|      0|            material.mIsReference = true;
  638|      0|            material.mName = matName;
  639|      0|            pMesh->mMaterials.push_back(material);
  640|       |
  641|      0|            CheckForClosingBrace(); // skip }
  642|      6|        } else if (objectName == "Material") {
  ------------------
  |  Branch (642:20): [True: 6, False: 0]
  ------------------
  643|      6|            pMesh->mMaterials.emplace_back();
  644|      6|            ParseDataObjectMaterial(&pMesh->mMaterials.back());
  645|      6|        } else if (objectName == ";") {
  ------------------
  |  Branch (645:20): [True: 0, False: 0]
  ------------------
  646|       |            // ignore
  647|      0|        } else {
  648|       |            ASSIMP_LOG_WARN("Unknown data object in material list in x file");
  649|      0|            ParseUnknownDataObject();
  650|      0|        }
  651|     10|    }
  652|      4|}
_ZN6Assimp11XFileParser23ParseDataObjectMaterialEPNS_5XFile8MaterialE:
  655|      6|void XFileParser::ParseDataObjectMaterial(Material *pMaterial) {
  656|      6|    std::string matName;
  657|      6|    readHeadOfDataObject(&matName);
  658|      6|    if (matName.empty())
  ------------------
  |  Branch (658:9): [True: 2, False: 4]
  ------------------
  659|      2|        matName = std::string("material") + ai_to_string(mLineNumber);
  660|      6|    pMaterial->mName = matName;
  661|      6|    pMaterial->mIsReference = false;
  662|       |
  663|       |    // read material values
  664|      6|    pMaterial->mDiffuse = ReadRGBA();
  665|      6|    pMaterial->mSpecularExponent = ReadFloat();
  666|      6|    pMaterial->mSpecular = ReadRGB();
  667|      6|    pMaterial->mEmissive = ReadRGB();
  668|       |
  669|       |    // read other data objects
  670|      6|    bool running = true;
  671|     11|    while (running) {
  ------------------
  |  Branch (671:12): [True: 11, False: 0]
  ------------------
  672|     11|        std::string objectName = GetNextToken();
  673|     11|        if (objectName.size() == 0)
  ------------------
  |  Branch (673:13): [True: 0, False: 11]
  ------------------
  674|      0|            ThrowException("Unexpected end of file while parsing mesh material");
  675|     11|        else if (objectName == "}")
  ------------------
  |  Branch (675:18): [True: 6, False: 5]
  ------------------
  676|      6|            break; // material finished
  677|      5|        else if (objectName == "TextureFilename" || objectName == "TextureFileName") {
  ------------------
  |  Branch (677:18): [True: 0, False: 5]
  |  Branch (677:53): [True: 5, False: 0]
  ------------------
  678|       |            // some exporters write "TextureFileName" instead.
  679|      5|            std::string texname;
  680|      5|            ParseDataObjectTextureFilename(texname);
  681|      5|            pMaterial->mTextures.emplace_back(texname);
  682|      5|        } else if (objectName == "NormalmapFilename" || objectName == "NormalmapFileName") {
  ------------------
  |  Branch (682:20): [True: 0, False: 0]
  |  Branch (682:57): [True: 0, False: 0]
  ------------------
  683|       |            // one exporter writes out the normal map in a separate filename tag
  684|      0|            std::string texname;
  685|      0|            ParseDataObjectTextureFilename(texname);
  686|      0|            pMaterial->mTextures.emplace_back(texname, true);
  687|      0|        } else {
  688|       |            ASSIMP_LOG_WARN("Unknown data object in material in x file");
  689|      0|            ParseUnknownDataObject();
  690|      0|        }
  691|     11|    }
  692|      6|}
_ZN6Assimp11XFileParser33ParseDataObjectAnimTicksPerSecondEv:
  695|      6|void XFileParser::ParseDataObjectAnimTicksPerSecond() {
  696|      6|    readHeadOfDataObject();
  697|      6|    mScene->mAnimTicksPerSecond = ReadInt();
  698|      6|    CheckForClosingBrace();
  699|      6|}
_ZN6Assimp11XFileParser27ParseDataObjectAnimationSetEv:
  702|      6|void XFileParser::ParseDataObjectAnimationSet() {
  703|      6|    std::string animName;
  704|      6|    readHeadOfDataObject(&animName);
  705|       |
  706|      6|    Animation *anim = new Animation;
  707|      6|    mScene->mAnims.push_back(anim);
  708|      6|    anim->mName = animName;
  709|       |
  710|      6|    bool running = true;
  711|    229|    while (running) {
  ------------------
  |  Branch (711:12): [True: 229, False: 0]
  ------------------
  712|    229|        std::string objectName = GetNextToken();
  713|    229|        if (objectName.length() == 0)
  ------------------
  |  Branch (713:13): [True: 0, False: 229]
  ------------------
  714|      0|            ThrowException("Unexpected end of file while parsing animation set.");
  715|    229|        else if (objectName == "}")
  ------------------
  |  Branch (715:18): [True: 6, False: 223]
  ------------------
  716|      6|            break; // animation set finished
  717|    223|        else if (objectName == "Animation")
  ------------------
  |  Branch (717:18): [True: 223, False: 0]
  ------------------
  718|    223|            ParseDataObjectAnimation(anim);
  719|      0|        else {
  720|       |            ASSIMP_LOG_WARN("Unknown data object in animation set in x file");
  721|      0|            ParseUnknownDataObject();
  722|      0|        }
  723|    229|    }
  724|      6|}
_ZN6Assimp11XFileParser24ParseDataObjectAnimationEPNS_5XFile9AnimationE:
  727|    223|void XFileParser::ParseDataObjectAnimation(Animation *pAnim) {
  728|    223|    readHeadOfDataObject();
  729|    223|    AnimBone *banim = new AnimBone;
  730|    223|    pAnim->mAnims.push_back(banim);
  731|       |
  732|    223|    bool running = true;
  733|  1.33k|    while (running) {
  ------------------
  |  Branch (733:12): [True: 1.33k, False: 0]
  ------------------
  734|  1.33k|        std::string objectName = GetNextToken();
  735|       |
  736|  1.33k|        if (objectName.length() == 0)
  ------------------
  |  Branch (736:13): [True: 0, False: 1.33k]
  ------------------
  737|      0|            ThrowException("Unexpected end of file while parsing animation.");
  738|  1.33k|        else if (objectName == "}")
  ------------------
  |  Branch (738:18): [True: 223, False: 1.11k]
  ------------------
  739|    223|            break; // animation finished
  740|  1.11k|        else if (objectName == "AnimationKey")
  ------------------
  |  Branch (740:18): [True: 624, False: 487]
  ------------------
  741|    624|            ParseDataObjectAnimationKey(banim);
  742|    487|        else if (objectName == "AnimationOptions")
  ------------------
  |  Branch (742:18): [True: 264, False: 223]
  ------------------
  743|    264|            ParseUnknownDataObject(); // not interested
  744|    223|        else if (objectName == "{") {
  ------------------
  |  Branch (744:18): [True: 223, False: 0]
  ------------------
  745|       |            // read frame name
  746|    223|            banim->mBoneName = GetNextToken();
  747|    223|            CheckForClosingBrace();
  748|    223|        } else {
  749|       |            ASSIMP_LOG_WARN("Unknown data object in animation in x file");
  750|      0|            ParseUnknownDataObject();
  751|      0|        }
  752|  1.33k|    }
  753|    223|}
_ZN6Assimp11XFileParser27ParseDataObjectAnimationKeyEPNS_5XFile8AnimBoneE:
  756|    624|void XFileParser::ParseDataObjectAnimationKey(AnimBone *pAnimBone) {
  757|    624|    readHeadOfDataObject();
  758|       |
  759|       |    // read key type
  760|    624|    unsigned int keyType = ReadInt();
  761|       |
  762|       |    // read number of keys
  763|    624|    unsigned int numKeys = ReadInt();
  764|       |
  765|  9.41k|    for (unsigned int a = 0; a < numKeys; a++) {
  ------------------
  |  Branch (765:30): [True: 8.78k, False: 624]
  ------------------
  766|       |        // read time
  767|  8.78k|        unsigned int time = ReadInt();
  768|       |
  769|       |        // read keys
  770|  8.78k|        switch (keyType) {
  771|  7.06k|        case 0: // rotation quaternion
  ------------------
  |  Branch (771:9): [True: 7.06k, False: 1.71k]
  ------------------
  772|  7.06k|        {
  773|       |            // read count
  774|  7.06k|            if (ReadInt() != 4)
  ------------------
  |  Branch (774:17): [True: 0, False: 7.06k]
  ------------------
  775|      0|                ThrowException("Invalid number of arguments for quaternion key in animation");
  776|       |
  777|  7.06k|            aiQuatKey key;
  778|  7.06k|            key.mTime = double(time);
  779|  7.06k|            key.mValue.w = ReadFloat();
  780|  7.06k|            key.mValue.x = ReadFloat();
  781|  7.06k|            key.mValue.y = ReadFloat();
  782|  7.06k|            key.mValue.z = ReadFloat();
  783|  7.06k|            pAnimBone->mRotKeys.push_back(key);
  784|       |
  785|  7.06k|            CheckForSemicolon();
  786|  7.06k|            break;
  787|      0|        }
  788|       |
  789|    270|        case 1: // scale vector
  ------------------
  |  Branch (789:9): [True: 270, False: 8.51k]
  ------------------
  790|  1.71k|        case 2: // position vector
  ------------------
  |  Branch (790:9): [True: 1.44k, False: 7.33k]
  ------------------
  791|  1.71k|        {
  792|       |            // read count
  793|  1.71k|            if (ReadInt() != 3)
  ------------------
  |  Branch (793:17): [True: 0, False: 1.71k]
  ------------------
  794|      0|                ThrowException("Invalid number of arguments for vector key in animation");
  795|       |
  796|  1.71k|            aiVectorKey key;
  797|  1.71k|            key.mTime = double(time);
  798|  1.71k|            key.mValue = ReadVector3();
  799|       |
  800|  1.71k|            if (keyType == 2)
  ------------------
  |  Branch (800:17): [True: 1.44k, False: 270]
  ------------------
  801|  1.44k|                pAnimBone->mPosKeys.push_back(key);
  802|    270|            else
  803|    270|                pAnimBone->mScaleKeys.push_back(key);
  804|       |
  805|  1.71k|            break;
  806|    270|        }
  807|       |
  808|      0|        case 3: // combined transformation matrix
  ------------------
  |  Branch (808:9): [True: 0, False: 8.78k]
  ------------------
  809|      0|        case 4: // denoted both as 3 or as 4
  ------------------
  |  Branch (809:9): [True: 0, False: 8.78k]
  ------------------
  810|      0|        {
  811|       |            // read count
  812|      0|            if (ReadInt() != 16)
  ------------------
  |  Branch (812:17): [True: 0, False: 0]
  ------------------
  813|      0|                ThrowException("Invalid number of arguments for matrix key in animation");
  814|       |
  815|       |            // read matrix
  816|      0|            MatrixKey key;
  817|      0|            key.mTime = double(time);
  818|      0|            key.mMatrix.a1 = ReadFloat();
  819|      0|            key.mMatrix.b1 = ReadFloat();
  820|      0|            key.mMatrix.c1 = ReadFloat();
  821|      0|            key.mMatrix.d1 = ReadFloat();
  822|      0|            key.mMatrix.a2 = ReadFloat();
  823|      0|            key.mMatrix.b2 = ReadFloat();
  824|      0|            key.mMatrix.c2 = ReadFloat();
  825|      0|            key.mMatrix.d2 = ReadFloat();
  826|      0|            key.mMatrix.a3 = ReadFloat();
  827|      0|            key.mMatrix.b3 = ReadFloat();
  828|      0|            key.mMatrix.c3 = ReadFloat();
  829|      0|            key.mMatrix.d3 = ReadFloat();
  830|      0|            key.mMatrix.a4 = ReadFloat();
  831|      0|            key.mMatrix.b4 = ReadFloat();
  832|      0|            key.mMatrix.c4 = ReadFloat();
  833|      0|            key.mMatrix.d4 = ReadFloat();
  834|      0|            pAnimBone->mTrafoKeys.push_back(key);
  835|       |
  836|      0|            CheckForSemicolon();
  837|      0|            break;
  838|      0|        }
  839|       |
  840|      0|        default:
  ------------------
  |  Branch (840:9): [True: 0, False: 8.78k]
  ------------------
  841|      0|            ThrowException("Unknown key type ", keyType, " in animation.");
  842|  8.78k|        } // end switch
  843|       |
  844|       |        // key separator
  845|  8.78k|        CheckForSeparator();
  846|  8.78k|    }
  847|       |
  848|    624|    CheckForClosingBrace();
  849|    624|}
_ZN6Assimp11XFileParser30ParseDataObjectTextureFilenameERNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEE:
  852|      5|void XFileParser::ParseDataObjectTextureFilename(std::string &pName) {
  853|      5|    readHeadOfDataObject();
  854|      5|    GetNextTokenAsString(pName);
  855|      5|    CheckForClosingBrace();
  856|       |
  857|       |    // FIX: some files (e.g. AnimationTest.x) have "" as texture file name
  858|      5|    if (!pName.length()) {
  ------------------
  |  Branch (858:9): [True: 1, False: 4]
  ------------------
  859|      1|        ASSIMP_LOG_WARN("Length of texture file name is zero. Skipping this texture.");
  860|      1|    }
  861|       |
  862|       |    // some exporters write double backslash paths out. We simply replace them if we find them
  863|      6|    while (pName.find("\\\\") != std::string::npos)
  ------------------
  |  Branch (863:12): [True: 1, False: 5]
  ------------------
  864|      1|        pName.replace(pName.find("\\\\"), 2, "\\");
  865|      5|}
_ZN6Assimp11XFileParser22ParseUnknownDataObjectEv:
  868|    400|void XFileParser::ParseUnknownDataObject() {
  869|       |    // find opening delimiter
  870|    400|    bool running = true;
  871|    501|    while (running) {
  ------------------
  |  Branch (871:12): [True: 501, False: 0]
  ------------------
  872|    501|        std::string t = GetNextToken();
  873|    501|        if (t.length() == 0)
  ------------------
  |  Branch (873:13): [True: 0, False: 501]
  ------------------
  874|      0|            ThrowException("Unexpected end of file while parsing unknown segment.");
  875|       |
  876|    501|        if (t == "{")
  ------------------
  |  Branch (876:13): [True: 400, False: 101]
  ------------------
  877|    400|            break;
  878|    501|    }
  879|       |
  880|    400|    unsigned int counter = 1;
  881|       |
  882|       |    // parse until closing delimiter
  883|  33.6k|    while (counter > 0) {
  ------------------
  |  Branch (883:12): [True: 33.2k, False: 400]
  ------------------
  884|  33.2k|        std::string t = GetNextToken();
  885|       |
  886|  33.2k|        if (t.length() == 0)
  ------------------
  |  Branch (886:13): [True: 0, False: 33.2k]
  ------------------
  887|      0|            ThrowException("Unexpected end of file while parsing unknown segment.");
  888|       |
  889|  33.2k|        if (t == "{")
  ------------------
  |  Branch (889:13): [True: 7, False: 33.1k]
  ------------------
  890|      7|            ++counter;
  891|  33.1k|        else if (t == "}")
  ------------------
  |  Branch (891:18): [True: 407, False: 32.7k]
  ------------------
  892|    407|            --counter;
  893|  33.2k|    }
  894|    400|}
_ZN6Assimp11XFileParser20CheckForClosingBraceEv:
  898|  1.22k|void XFileParser::CheckForClosingBrace() {
  899|  1.22k|    if (GetNextToken() != "}")
  ------------------
  |  Branch (899:9): [True: 1, False: 1.22k]
  ------------------
  900|      1|        ThrowException("Closing brace expected.");
  901|  1.22k|}
_ZN6Assimp11XFileParser17CheckForSemicolonEv:
  905|  7.41k|void XFileParser::CheckForSemicolon() {
  906|  7.41k|    if (mIsBinaryFormat)
  ------------------
  |  Branch (906:9): [True: 2, False: 7.40k]
  ------------------
  907|      2|        return;
  908|       |
  909|  7.40k|    if (GetNextToken() != ";")
  ------------------
  |  Branch (909:9): [True: 0, False: 7.40k]
  ------------------
  910|      0|        ThrowException("Semicolon expected.");
  911|  7.40k|}
_ZN6Assimp11XFileParser17CheckForSeparatorEv:
  915|   397k|void XFileParser::CheckForSeparator() {
  916|   397k|    if (mIsBinaryFormat)
  ------------------
  |  Branch (916:9): [True: 0, False: 397k]
  ------------------
  917|      0|        return;
  918|       |
  919|   397k|    std::string token = GetNextToken();
  920|   397k|    if (token != "," && token != ";")
  ------------------
  |  Branch (920:9): [True: 238k, False: 158k]
  |  Branch (920:25): [True: 2, False: 238k]
  ------------------
  921|      2|        ThrowException("Separator character (';' or ',') expected.");
  922|   397k|}
_ZN6Assimp11XFileParser16TestForSeparatorEv:
  926|   124k|void XFileParser::TestForSeparator() {
  927|   124k|    if (mIsBinaryFormat)
  ------------------
  |  Branch (927:9): [True: 36.4k, False: 88.1k]
  ------------------
  928|  36.4k|        return;
  929|       |
  930|  88.1k|    FindNextNoneWhiteSpace();
  931|  88.1k|    if (mP >= mEnd)
  ------------------
  |  Branch (931:9): [True: 1, False: 88.1k]
  ------------------
  932|      1|        return;
  933|       |
  934|       |    // test and skip
  935|  88.1k|    if (*mP == ';' || *mP == ',')
  ------------------
  |  Branch (935:9): [True: 1.77k, False: 86.3k]
  |  Branch (935:23): [True: 86.3k, False: 1]
  ------------------
  936|  88.1k|        mP++;
  937|  88.1k|}
_ZN6Assimp11XFileParser20readHeadOfDataObjectEPNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEE:
  940|  1.58k|void XFileParser::readHeadOfDataObject(std::string *poName) {
  941|  1.58k|    std::string nameOrBrace = GetNextToken();
  942|  1.58k|    if (nameOrBrace != "{") {
  ------------------
  |  Branch (942:9): [True: 1.32k, False: 262]
  ------------------
  943|  1.32k|        if (poName)
  ------------------
  |  Branch (943:13): [True: 356, False: 970]
  ------------------
  944|    356|            *poName = nameOrBrace;
  945|       |
  946|  1.32k|        if (GetNextToken() != "{") {
  ------------------
  |  Branch (946:13): [True: 0, False: 1.32k]
  ------------------
  947|      0|            delete mScene;
  948|      0|            ThrowException("Opening brace expected.");
  949|      0|        }
  950|  1.32k|    }
  951|  1.58k|}
_ZN6Assimp11XFileParser12GetNextTokenEv:
  954|   446k|std::string XFileParser::GetNextToken() {
  955|   446k|    std::string s;
  956|       |
  957|       |    // process binary-formatted file
  958|   446k|    if (mIsBinaryFormat) {
  ------------------
  |  Branch (958:9): [True: 43, False: 446k]
  ------------------
  959|       |        // in binary mode it will only return NAME and STRING token
  960|       |        // and (correctly) skip over other tokens.
  961|     43|        if (mEnd - mP < 2) {
  ------------------
  |  Branch (961:13): [True: 2, False: 41]
  ------------------
  962|      2|            return s;
  963|      2|        }
  964|     41|        unsigned int tok = ReadBinWord();
  965|     41|        unsigned int len;
  966|       |
  967|       |        // standalone tokens
  968|     41|        switch (tok) {
  ------------------
  |  Branch (968:17): [True: 41, False: 0]
  ------------------
  969|     17|        case 1: {
  ------------------
  |  Branch (969:9): [True: 17, False: 24]
  ------------------
  970|       |            // name token
  971|     17|            if (mEnd - mP < 4) {
  ------------------
  |  Branch (971:17): [True: 0, False: 17]
  ------------------
  972|      0|                return s;
  973|      0|            }
  974|     17|            len = ReadBinDWord();
  975|     17|            const int bounds = int(mEnd - mP);
  976|     17|            const int iLen = int(len);
  977|     17|            if (iLen < 0) {
  ------------------
  |  Branch (977:17): [True: 0, False: 17]
  ------------------
  978|      0|                return s;
  979|      0|            }
  980|     17|            if (bounds < iLen) {
  ------------------
  |  Branch (980:17): [True: 0, False: 17]
  ------------------
  981|      0|                return s;
  982|      0|            }
  983|     17|            s = std::string(mP, len);
  984|     17|            mP += len;
  985|     17|        }
  986|      0|            return s;
  987|       |
  988|      0|        case 2:
  ------------------
  |  Branch (988:9): [True: 0, False: 41]
  ------------------
  989|       |            // string token
  990|      0|            if (mEnd - mP < 4) return s;
  ------------------
  |  Branch (990:17): [True: 0, False: 0]
  ------------------
  991|      0|            len = ReadBinDWord();
  992|      0|            if (mEnd - mP < int(len)) return s;
  ------------------
  |  Branch (992:17): [True: 0, False: 0]
  ------------------
  993|      0|            s = std::string(mP, len);
  994|      0|            mP += (len + 2);
  995|      0|            return s;
  996|      0|        case 3:
  ------------------
  |  Branch (996:9): [True: 0, False: 41]
  ------------------
  997|       |            // integer token
  998|      0|            mP += 4;
  999|      0|            return "<integer>";
 1000|      0|        case 5:
  ------------------
  |  Branch (1000:9): [True: 0, False: 41]
  ------------------
 1001|       |            // GUID token
 1002|      0|            mP += 16;
 1003|      0|            return "<guid>";
 1004|      2|        case 6:
  ------------------
  |  Branch (1004:9): [True: 2, False: 39]
  ------------------
 1005|      2|            if (mEnd - mP < 4) return s;
  ------------------
  |  Branch (1005:17): [True: 0, False: 2]
  ------------------
 1006|      2|            len = ReadBinDWord();
 1007|      2|            mP += (len * 4);
 1008|      2|            return "<int_list>";
 1009|      0|        case 7:
  ------------------
  |  Branch (1009:9): [True: 0, False: 41]
  ------------------
 1010|      0|            if (mEnd - mP < 4) return s;
  ------------------
  |  Branch (1010:17): [True: 0, False: 0]
  ------------------
 1011|      0|            len = ReadBinDWord();
 1012|      0|            mP += (len * mBinaryFloatSize);
 1013|      0|            return "<flt_list>";
 1014|     12|        case 0x0a:
  ------------------
  |  Branch (1014:9): [True: 12, False: 29]
  ------------------
 1015|     12|            return "{";
 1016|     10|        case 0x0b:
  ------------------
  |  Branch (1016:9): [True: 10, False: 31]
  ------------------
 1017|     10|            return "}";
 1018|      0|        case 0x0c:
  ------------------
  |  Branch (1018:9): [True: 0, False: 41]
  ------------------
 1019|      0|            return "(";
 1020|      0|        case 0x0d:
  ------------------
  |  Branch (1020:9): [True: 0, False: 41]
  ------------------
 1021|      0|            return ")";
 1022|      0|        case 0x0e:
  ------------------
  |  Branch (1022:9): [True: 0, False: 41]
  ------------------
 1023|      0|            return "[";
 1024|      0|        case 0x0f:
  ------------------
  |  Branch (1024:9): [True: 0, False: 41]
  ------------------
 1025|      0|            return "]";
 1026|      0|        case 0x10:
  ------------------
  |  Branch (1026:9): [True: 0, False: 41]
  ------------------
 1027|      0|            return "<";
 1028|      0|        case 0x11:
  ------------------
  |  Branch (1028:9): [True: 0, False: 41]
  ------------------
 1029|      0|            return ">";
 1030|      0|        case 0x12:
  ------------------
  |  Branch (1030:9): [True: 0, False: 41]
  ------------------
 1031|      0|            return ".";
 1032|      0|        case 0x13:
  ------------------
  |  Branch (1032:9): [True: 0, False: 41]
  ------------------
 1033|      0|            return ",";
 1034|      0|        case 0x14:
  ------------------
  |  Branch (1034:9): [True: 0, False: 41]
  ------------------
 1035|      0|            return ";";
 1036|      0|        case 0x1f:
  ------------------
  |  Branch (1036:9): [True: 0, False: 41]
  ------------------
 1037|      0|            return "template";
 1038|      0|        case 0x28:
  ------------------
  |  Branch (1038:9): [True: 0, False: 41]
  ------------------
 1039|      0|            return "WORD";
 1040|      0|        case 0x29:
  ------------------
  |  Branch (1040:9): [True: 0, False: 41]
  ------------------
 1041|      0|            return "DWORD";
 1042|      0|        case 0x2a:
  ------------------
  |  Branch (1042:9): [True: 0, False: 41]
  ------------------
 1043|      0|            return "FLOAT";
 1044|      0|        case 0x2b:
  ------------------
  |  Branch (1044:9): [True: 0, False: 41]
  ------------------
 1045|      0|            return "DOUBLE";
 1046|      0|        case 0x2c:
  ------------------
  |  Branch (1046:9): [True: 0, False: 41]
  ------------------
 1047|      0|            return "CHAR";
 1048|      0|        case 0x2d:
  ------------------
  |  Branch (1048:9): [True: 0, False: 41]
  ------------------
 1049|      0|            return "UCHAR";
 1050|      0|        case 0x2e:
  ------------------
  |  Branch (1050:9): [True: 0, False: 41]
  ------------------
 1051|      0|            return "SWORD";
 1052|      0|        case 0x2f:
  ------------------
  |  Branch (1052:9): [True: 0, False: 41]
  ------------------
 1053|      0|            return "SDWORD";
 1054|      0|        case 0x30:
  ------------------
  |  Branch (1054:9): [True: 0, False: 41]
  ------------------
 1055|      0|            return "void";
 1056|      0|        case 0x31:
  ------------------
  |  Branch (1056:9): [True: 0, False: 41]
  ------------------
 1057|      0|            return "string";
 1058|      0|        case 0x32:
  ------------------
  |  Branch (1058:9): [True: 0, False: 41]
  ------------------
 1059|      0|            return "unicode";
 1060|      0|        case 0x33:
  ------------------
  |  Branch (1060:9): [True: 0, False: 41]
  ------------------
 1061|      0|            return "cstring";
 1062|      0|        case 0x34:
  ------------------
  |  Branch (1062:9): [True: 0, False: 41]
  ------------------
 1063|      0|            return "array";
 1064|     41|        }
 1065|     41|    }
 1066|       |    // process text-formatted file
 1067|   446k|    else {
 1068|   446k|        FindNextNoneWhiteSpace();
 1069|   446k|        if (mP >= mEnd)
  ------------------
  |  Branch (1069:13): [True: 7, False: 446k]
  ------------------
 1070|      7|            return s;
 1071|       |
 1072|   627k|        while ((mP < mEnd) && !isspace((unsigned char)*mP)) {
  ------------------
  |  Branch (1072:16): [True: 627k, False: 0]
  |  Branch (1072:31): [True: 622k, False: 4.16k]
  ------------------
 1073|       |            // either keep token delimiters when already holding a token, or return if first valid char
 1074|   622k|            if (*mP == ';' || *mP == '}' || *mP == '{' || *mP == ',') {
  ------------------
  |  Branch (1074:17): [True: 248k, False: 374k]
  |  Branch (1074:31): [True: 2.22k, False: 371k]
  |  Branch (1074:45): [True: 2.20k, False: 369k]
  |  Branch (1074:59): [True: 189k, False: 180k]
  ------------------
 1075|   442k|                if (!s.size())
  ------------------
  |  Branch (1075:21): [True: 425k, False: 16.6k]
  ------------------
 1076|   425k|                    s.append(mP++, 1);
 1077|   442k|                break; // stop for delimiter
 1078|   442k|            }
 1079|   180k|            s.append(mP++, 1);
 1080|   180k|        }
 1081|   446k|    }
 1082|   446k|    return s;
 1083|   446k|}
_ZN6Assimp11XFileParser22FindNextNoneWhiteSpaceEv:
 1086|   923k|void XFileParser::FindNextNoneWhiteSpace() {
 1087|   923k|    if (mIsBinaryFormat)
  ------------------
  |  Branch (1087:9): [True: 0, False: 923k]
  ------------------
 1088|      0|        return;
 1089|       |
 1090|   923k|    bool running = true;
 1091|   923k|    while (running) {
  ------------------
  |  Branch (1091:12): [True: 923k, False: 0]
  ------------------
 1092|  2.08M|        while (mP < mEnd && isspace((unsigned char)*mP)) {
  ------------------
  |  Branch (1092:16): [True: 2.08M, False: 11]
  |  Branch (1092:29): [True: 1.15M, False: 923k]
  ------------------
 1093|  1.15M|            if (*mP == '\n')
  ------------------
  |  Branch (1093:17): [True: 166k, False: 991k]
  ------------------
 1094|   166k|                mLineNumber++;
 1095|  1.15M|            ++mP;
 1096|  1.15M|        }
 1097|       |
 1098|   923k|        if (mP >= mEnd)
  ------------------
  |  Branch (1098:13): [True: 11, False: 923k]
  ------------------
 1099|     11|            return;
 1100|       |
 1101|       |        // check if this is a comment
 1102|   923k|        if ((mP[0] == '/' && mP[1] == '/') || mP[0] == '#')
  ------------------
  |  Branch (1102:14): [True: 2, False: 923k]
  |  Branch (1102:30): [True: 2, False: 0]
  |  Branch (1102:47): [True: 1, False: 923k]
  ------------------
 1103|      3|            ReadUntilEndOfLine();
 1104|   923k|        else
 1105|   923k|            break;
 1106|   923k|    }
 1107|   923k|}
_ZN6Assimp11XFileParser20GetNextTokenAsStringERNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEE:
 1110|    162|void XFileParser::GetNextTokenAsString(std::string &poString) {
 1111|    162|    if (mIsBinaryFormat) {
  ------------------
  |  Branch (1111:9): [True: 0, False: 162]
  ------------------
 1112|      0|        poString = GetNextToken();
 1113|      0|        return;
 1114|      0|    }
 1115|       |
 1116|    162|    FindNextNoneWhiteSpace();
 1117|    162|    if (mP >= mEnd) {
  ------------------
  |  Branch (1117:9): [True: 0, False: 162]
  ------------------
 1118|      0|        delete mScene;
 1119|      0|        ThrowException("Unexpected end of file while parsing string");
 1120|      0|    }
 1121|       |
 1122|    162|    if (*mP != '"') {
  ------------------
  |  Branch (1122:9): [True: 0, False: 162]
  ------------------
 1123|      0|        delete mScene;
 1124|      0|        ThrowException("Expected quotation mark.");
 1125|      0|    }
 1126|    162|    ++mP;
 1127|       |
 1128|  1.76k|    while (mP < mEnd && *mP != '"')
  ------------------
  |  Branch (1128:12): [True: 1.76k, False: 0]
  |  Branch (1128:25): [True: 1.60k, False: 162]
  ------------------
 1129|  1.60k|        poString.append(mP++, 1);
 1130|       |
 1131|    162|    if (mP >= mEnd - 1) {
  ------------------
  |  Branch (1131:9): [True: 0, False: 162]
  ------------------
 1132|      0|        delete mScene;
 1133|      0|        ThrowException("Unexpected end of file while parsing string");
 1134|      0|    }
 1135|       |
 1136|    162|    if (mP[1] != ';' || mP[0] != '"') {
  ------------------
  |  Branch (1136:9): [True: 0, False: 162]
  |  Branch (1136:25): [True: 0, False: 162]
  ------------------
 1137|      0|        delete mScene;
 1138|      0|        ThrowException("Expected quotation mark and semicolon at the end of a string.");
 1139|      0|    }
 1140|    162|    mP += 2;
 1141|    162|}
_ZN6Assimp11XFileParser18ReadUntilEndOfLineEv:
 1144|     17|void XFileParser::ReadUntilEndOfLine() {
 1145|     17|    if (mIsBinaryFormat)
  ------------------
  |  Branch (1145:9): [True: 2, False: 15]
  ------------------
 1146|      2|        return;
 1147|       |
 1148|     74|    while (mP < mEnd) {
  ------------------
  |  Branch (1148:12): [True: 74, False: 0]
  ------------------
 1149|     74|        if (*mP == '\n' || *mP == '\r') {
  ------------------
  |  Branch (1149:13): [True: 15, False: 59]
  |  Branch (1149:28): [True: 0, False: 59]
  ------------------
 1150|     15|            ++mP;
 1151|     15|            mLineNumber++;
 1152|     15|            return;
 1153|     15|        }
 1154|       |
 1155|     59|        ++mP;
 1156|     59|    }
 1157|     15|}
_ZN6Assimp11XFileParser11ReadBinWordEv:
 1160|     56|unsigned short XFileParser::ReadBinWord() {
 1161|       |    ai_assert(mEnd - mP >= 2);
 1162|     56|    const unsigned char *q = (const unsigned char *)mP;
 1163|     56|    unsigned short tmp = q[0] | (q[1] << 8);
 1164|     56|    mP += 2;
 1165|     56|    return tmp;
 1166|     56|}
_ZN6Assimp11XFileParser12ReadBinDWordEv:
 1169|  63.8k|unsigned int XFileParser::ReadBinDWord() {
 1170|  63.8k|    ai_assert(mEnd - mP >= 4);
 1171|       |
 1172|  63.8k|    const unsigned char *q = (const unsigned char *)mP;
 1173|  63.8k|    unsigned int tmp = q[0] | (q[1] << 8) | (q[2] << 16) | (q[3] << 24);
 1174|  63.8k|    mP += 4;
 1175|  63.8k|    return tmp;
 1176|  63.8k|}
_ZN6Assimp11XFileParser7ReadIntEv:
 1179|   261k|unsigned int XFileParser::ReadInt() {
 1180|   261k|    if (mIsBinaryFormat) {
  ------------------
  |  Branch (1180:9): [True: 69.5k, False: 191k]
  ------------------
 1181|  69.5k|        if (mBinaryNumCount == 0 && mEnd - mP >= 2) {
  ------------------
  |  Branch (1181:13): [True: 8, False: 69.5k]
  |  Branch (1181:37): [True: 8, False: 0]
  ------------------
 1182|      8|            unsigned short tmp = ReadBinWord(); // 0x06 or 0x03
 1183|      8|            if (tmp == 0x06 && mEnd - mP >= 4) // array of ints follows
  ------------------
  |  Branch (1183:17): [True: 8, False: 0]
  |  Branch (1183:32): [True: 8, False: 0]
  ------------------
 1184|      8|                mBinaryNumCount = ReadBinDWord();
 1185|      0|            else // single int follows
 1186|      0|                mBinaryNumCount = 1;
 1187|      8|        }
 1188|       |
 1189|  69.5k|        --mBinaryNumCount;
 1190|  69.5k|        const size_t len(mEnd - mP);
 1191|  69.5k|        if (len >= 4) {
  ------------------
  |  Branch (1191:13): [True: 63.8k, False: 5.67k]
  ------------------
 1192|  63.8k|            return ReadBinDWord();
 1193|  63.8k|        } else {
 1194|  5.67k|            mP = mEnd;
 1195|  5.67k|            return 0;
 1196|  5.67k|        }
 1197|   191k|    } else {
 1198|   191k|        FindNextNoneWhiteSpace();
 1199|       |
 1200|       |        // TODO: consider using strtol10 instead???
 1201|       |
 1202|       |        // check preceding minus sign
 1203|   191k|        bool isNegative = false;
 1204|   191k|        if (*mP == '-') {
  ------------------
  |  Branch (1204:13): [True: 0, False: 191k]
  ------------------
 1205|      0|            isNegative = true;
 1206|      0|            mP++;
 1207|      0|        }
 1208|       |
 1209|       |        // at least one digit expected
 1210|   191k|        if (!isdigit((unsigned char)*mP))
  ------------------
  |  Branch (1210:13): [True: 2, False: 191k]
  ------------------
 1211|      2|            ThrowException("Number expected.");
 1212|       |
 1213|       |        // read digits
 1214|   191k|        unsigned int number = 0;
 1215|   717k|        while (mP < mEnd) {
  ------------------
  |  Branch (1215:16): [True: 717k, False: 2]
  ------------------
 1216|   717k|            if (!isdigit((unsigned char)*mP))
  ------------------
  |  Branch (1216:17): [True: 191k, False: 525k]
  ------------------
 1217|   191k|                break;
 1218|   525k|            number = number * 10 + (*mP - 48);
 1219|   525k|            mP++;
 1220|   525k|        }
 1221|       |
 1222|   191k|        CheckForSeparator();
 1223|       |
 1224|   191k|        return isNegative ? ((unsigned int)-int(number)) : number;
  ------------------
  |  Branch (1224:16): [True: 0, False: 191k]
  ------------------
 1225|   191k|    }
 1226|   261k|}
_ZN6Assimp11XFileParser9ReadFloatEv:
 1229|   242k|ai_real XFileParser::ReadFloat() {
 1230|   242k|    if (mIsBinaryFormat) {
  ------------------
  |  Branch (1230:9): [True: 45.4k, False: 196k]
  ------------------
 1231|  45.4k|        if (mBinaryNumCount == 0 && mEnd - mP >= 2) {
  ------------------
  |  Branch (1231:13): [True: 7, False: 45.4k]
  |  Branch (1231:37): [True: 7, False: 0]
  ------------------
 1232|      7|            unsigned short tmp = ReadBinWord(); // 0x07 or 0x42
 1233|      7|            if (tmp == 0x07 && mEnd - mP >= 4) // array of floats following
  ------------------
  |  Branch (1233:17): [True: 7, False: 0]
  |  Branch (1233:32): [True: 7, False: 0]
  ------------------
 1234|      7|                mBinaryNumCount = ReadBinDWord();
 1235|      0|            else // single float following
 1236|      0|                mBinaryNumCount = 1;
 1237|      7|        }
 1238|       |
 1239|  45.4k|        --mBinaryNumCount;
 1240|  45.4k|        if (mBinaryFloatSize == 8) {
  ------------------
  |  Branch (1240:13): [True: 0, False: 45.4k]
  ------------------
 1241|      0|            if (mEnd - mP >= 8) {
  ------------------
  |  Branch (1241:17): [True: 0, False: 0]
  ------------------
 1242|      0|                double res;
 1243|      0|                ::memcpy(&res, mP, 8);
 1244|      0|                mP += 8;
 1245|      0|                const ai_real result(static_cast<ai_real>(res));
 1246|      0|                return result;
 1247|      0|            } else {
 1248|      0|                mP = mEnd;
 1249|      0|                return 0;
 1250|      0|            }
 1251|  45.4k|        } else {
 1252|  45.4k|            if (mEnd - mP >= 4) {
  ------------------
  |  Branch (1252:17): [True: 45.4k, False: 0]
  ------------------
 1253|  45.4k|                ai_real result;
 1254|  45.4k|                ::memcpy(&result, mP, 4);
 1255|  45.4k|                mP += 4;
 1256|  45.4k|                return result;
 1257|  45.4k|            } else {
 1258|      0|                mP = mEnd;
 1259|      0|                return 0;
 1260|      0|            }
 1261|  45.4k|        }
 1262|  45.4k|    }
 1263|       |
 1264|       |    // text version
 1265|   196k|    FindNextNoneWhiteSpace();
 1266|       |    // check for various special strings to allow reading files from faulty exporters
 1267|       |    // I mean you, Blender!
 1268|       |    // Reading is safe because of the terminating zero
 1269|   196k|    if (strncmp(mP, "-1.#IND00", 9) == 0 || strncmp(mP, "1.#IND00", 8) == 0) {
  ------------------
  |  Branch (1269:9): [True: 0, False: 196k]
  |  Branch (1269:45): [True: 0, False: 196k]
  ------------------
 1270|      0|        mP += 9;
 1271|      0|        CheckForSeparator();
 1272|      0|        return 0.0;
 1273|   196k|    } else if (strncmp(mP, "1.#QNAN0", 8) == 0) {
  ------------------
  |  Branch (1273:16): [True: 0, False: 196k]
  ------------------
 1274|      0|        mP += 8;
 1275|      0|        CheckForSeparator();
 1276|      0|        return 0.0;
 1277|      0|    }
 1278|       |
 1279|   196k|    ai_real result = 0.0;
 1280|   196k|    mP = fast_atoreal_move(mP, result);
 1281|       |
 1282|   196k|    CheckForSeparator();
 1283|       |
 1284|   196k|    return result;
 1285|   196k|}
_ZN6Assimp11XFileParser11ReadVector2Ev:
 1288|  16.7k|aiVector2D XFileParser::ReadVector2() {
 1289|  16.7k|    aiVector2D vector;
 1290|  16.7k|    vector.x = ReadFloat();
 1291|  16.7k|    vector.y = ReadFloat();
 1292|  16.7k|    TestForSeparator();
 1293|       |
 1294|  16.7k|    return vector;
 1295|  16.7k|}
_ZN6Assimp11XFileParser11ReadVector3Ev:
 1298|  50.9k|aiVector3D XFileParser::ReadVector3() {
 1299|  50.9k|    aiVector3D vector;
 1300|  50.9k|    vector.x = ReadFloat();
 1301|  50.9k|    vector.y = ReadFloat();
 1302|  50.9k|    vector.z = ReadFloat();
 1303|  50.9k|    TestForSeparator();
 1304|       |
 1305|  50.9k|    return vector;
 1306|  50.9k|}
_ZN6Assimp11XFileParser8ReadRGBAEv:
 1309|      6|aiColor4D XFileParser::ReadRGBA() {
 1310|      6|    aiColor4D color;
 1311|      6|    color.r = ReadFloat();
 1312|      6|    color.g = ReadFloat();
 1313|      6|    color.b = ReadFloat();
 1314|      6|    color.a = ReadFloat();
 1315|      6|    TestForSeparator();
 1316|       |
 1317|      6|    return color;
 1318|      6|}
_ZN6Assimp11XFileParser7ReadRGBEv:
 1321|     12|aiColor3D XFileParser::ReadRGB() {
 1322|     12|    aiColor3D color;
 1323|     12|    color.r = ReadFloat();
 1324|     12|    color.g = ReadFloat();
 1325|     12|    color.b = ReadFloat();
 1326|     12|    TestForSeparator();
 1327|       |
 1328|     12|    return color;
 1329|     12|}
_ZN6Assimp11XFileParser15FilterHierarchyEPNS_5XFile4NodeE:
 1333|    150|void XFileParser::FilterHierarchy(XFile::Node *pNode) {
 1334|       |    // if the node has just a single unnamed child containing a mesh, remove
 1335|       |    // the anonymous node between. The 3DSMax kwXport plugin seems to produce this
 1336|       |    // mess in some cases
 1337|    150|    if (pNode->mChildren.size() == 1 && pNode->mMeshes.empty()) {
  ------------------
  |  Branch (1337:9): [True: 81, False: 69]
  |  Branch (1337:41): [True: 81, False: 0]
  ------------------
 1338|     81|        XFile::Node *child = pNode->mChildren.front();
 1339|     81|        if (child->mName.length() == 0 && child->mMeshes.size() > 0) {
  ------------------
  |  Branch (1339:13): [True: 0, False: 81]
  |  Branch (1339:43): [True: 0, False: 0]
  ------------------
 1340|       |            // transfer its meshes to us
 1341|      0|            for (unsigned int a = 0; a < child->mMeshes.size(); a++)
  ------------------
  |  Branch (1341:38): [True: 0, False: 0]
  ------------------
 1342|      0|                pNode->mMeshes.push_back(child->mMeshes[a]);
 1343|      0|            child->mMeshes.clear();
 1344|       |
 1345|       |            // transfer the transform as well
 1346|      0|            pNode->mTrafoMatrix = pNode->mTrafoMatrix * child->mTrafoMatrix;
 1347|       |
 1348|       |            // then kill it
 1349|      0|            delete child;
 1350|      0|            pNode->mChildren.clear();
 1351|      0|        }
 1352|     81|    }
 1353|       |
 1354|       |    // recurse
 1355|    295|    for (unsigned int a = 0; a < pNode->mChildren.size(); a++)
  ------------------
  |  Branch (1355:30): [True: 145, False: 150]
  ------------------
 1356|    145|        FilterHierarchy(pNode->mChildren[a]);
 1357|    150|}
_ZN6Assimp11XFileParser14ThrowExceptionIJRA51_KcEEEvDpOT_:
   72|      1|AI_WONT_RETURN void XFileParser::ThrowException(T&&... args) {
   73|      1|    if (mIsBinaryFormat) {
  ------------------
  |  Branch (73:9): [True: 0, False: 1]
  ------------------
   74|      0|        throw DeadlyImportError(args...);
   75|      1|    } else {
   76|      1|        throw DeadlyImportError("Line ", mLineNumber, ": ", args...);
   77|      1|    }
   78|      1|}
_ZN6Assimp11XFileParser14ThrowExceptionIJRA52_KcEEEvDpOT_:
   72|      1|AI_WONT_RETURN void XFileParser::ThrowException(T&&... args) {
   73|      1|    if (mIsBinaryFormat) {
  ------------------
  |  Branch (73:9): [True: 1, False: 0]
  ------------------
   74|      1|        throw DeadlyImportError(args...);
   75|      1|    } else {
   76|      0|        throw DeadlyImportError("Line ", mLineNumber, ": ", args...);
   77|      0|    }
   78|      1|}
_ZN6Assimp11XFileParser14ThrowExceptionIJRA24_KcEEEvDpOT_:
   72|      1|AI_WONT_RETURN void XFileParser::ThrowException(T&&... args) {
   73|      1|    if (mIsBinaryFormat) {
  ------------------
  |  Branch (73:9): [True: 0, False: 1]
  ------------------
   74|      0|        throw DeadlyImportError(args...);
   75|      1|    } else {
   76|      1|        throw DeadlyImportError("Line ", mLineNumber, ": ", args...);
   77|      1|    }
   78|      1|}
_ZN6Assimp11XFileParser14ThrowExceptionIJRA43_KcEEEvDpOT_:
   72|      2|AI_WONT_RETURN void XFileParser::ThrowException(T&&... args) {
   73|      2|    if (mIsBinaryFormat) {
  ------------------
  |  Branch (73:9): [True: 0, False: 2]
  ------------------
   74|      0|        throw DeadlyImportError(args...);
   75|      2|    } else {
   76|      2|        throw DeadlyImportError("Line ", mLineNumber, ": ", args...);
   77|      2|    }
   78|      2|}
_ZN6Assimp11XFileParser14ThrowExceptionIJRA17_KcEEEvDpOT_:
   72|      2|AI_WONT_RETURN void XFileParser::ThrowException(T&&... args) {
   73|      2|    if (mIsBinaryFormat) {
  ------------------
  |  Branch (73:9): [True: 0, False: 2]
  ------------------
   74|      0|        throw DeadlyImportError(args...);
   75|      2|    } else {
   76|      2|        throw DeadlyImportError("Line ", mLineNumber, ": ", args...);
   77|      2|    }
   78|      2|}

_ZNK6Assimp11XFileParser15GetImportedDataEv:
   75|      5|    XFile::Scene* GetImportedData() const { return mScene; }

_ZN6Assimp11X3DImporterC2Ev:
  192|    624|        mNodeElementCur(nullptr),
  193|    624|        mScene(nullptr),
  194|    624|        mpIOHandler(nullptr) {
  195|       |    // empty
  196|    624|}
_ZN6Assimp11X3DImporterD2Ev:
  198|    624|X3DImporter::~X3DImporter() {
  199|       |    // Clear() is accounting if data already is deleted. So, just check again if all data is deleted.
  200|    624|    Clear();
  201|    624|}
_ZN6Assimp11X3DImporter5ClearEv:
  203|    629|void X3DImporter::Clear() {
  204|    629|    mNodeElementCur = nullptr;
  205|       |    // Delete all elements
  206|    629|    if (!NodeElement_List.empty()) {
  ------------------
  |  Branch (206:9): [True: 0, False: 629]
  ------------------
  207|      0|        for (std::list<X3DNodeElementBase *>::iterator it = NodeElement_List.begin(); it != NodeElement_List.end(); ++it) {
  ------------------
  |  Branch (207:87): [True: 0, False: 0]
  ------------------
  208|      0|            delete *it;
  209|      0|        }
  210|      0|        NodeElement_List.clear();
  211|      0|    }
  212|    629|}
_ZN6Assimp11X3DImporter9ParseFileERKNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEPNS_8IOSystemE:
  214|      5|void X3DImporter::ParseFile(const std::string &file, IOSystem *pIOHandler) {
  215|      5|    ai_assert(nullptr != pIOHandler);
  ------------------
  |  |   67|      5|#   define ai_assert(expression) (void)((!!(expression)) || (Assimp::aiAssertViolation(#expression, __FILE__, __LINE__), 0))
  |  |  ------------------
  |  |  |  Branch (67:41): [True: 5, False: 0]
  |  |  |  Branch (67:61): [True: 0, False: 0]
  |  |  ------------------
  ------------------
  216|       |
  217|      5|    static const std::string mode = "rb";
  218|      5|    std::unique_ptr<IOStream> fileStream(pIOHandler->Open(file, mode));
  219|      5|    if (!fileStream) {
  ------------------
  |  Branch (219:9): [True: 0, False: 5]
  ------------------
  220|      0|        throw DeadlyImportError("Failed to open file " + file + ".");
  221|      0|    }
  222|       |
  223|      5|    XmlParser theParser;
  224|      5|    if (!theParser.parse(fileStream.get())) {
  ------------------
  |  Branch (224:9): [True: 5, False: 0]
  ------------------
  225|      5|        return;
  226|      5|    }
  227|      0|    ParseFile(theParser);
  228|      0|}
_ZNK6Assimp11X3DImporter7CanReadERKNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEPNS_8IOSystemEb:
  257|     43|bool X3DImporter::CanRead(const std::string &pFile, IOSystem * /*pIOHandler*/, bool checkSig) const {
  258|     43|    if (checkSig) {
  ------------------
  |  Branch (258:9): [True: 43, False: 0]
  ------------------
  259|     43|        if (GetExtension(pFile) == "x3d")
  ------------------
  |  Branch (259:13): [True: 0, False: 43]
  ------------------
  260|      0|            return true;
  261|     43|    }
  262|       |
  263|     43|    return false;
  264|     43|}
_ZN6Assimp11X3DImporter14InternReadFileERKNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEP7aiScenePNS_8IOSystemE:
  266|      5|void X3DImporter::InternReadFile(const std::string &pFile, aiScene *pScene, IOSystem *pIOHandler) {
  267|      5|    mpIOHandler = pIOHandler;
  268|       |
  269|      5|    Clear();
  270|      5|    std::stringstream ss = ConvertVrmlFileToX3dXmlFile(pFile);
  271|      5|    const bool isReadFromMem{ ss.str().length() > 0 };
  272|      5|    if (!isReadFromMem) {
  ------------------
  |  Branch (272:9): [True: 5, False: 0]
  ------------------
  273|      5|        std::shared_ptr<IOStream> stream(pIOHandler->Open(pFile, "rb"));
  274|      5|        if (!stream) {
  ------------------
  |  Branch (274:13): [True: 0, False: 5]
  ------------------
  275|      0|            throw DeadlyImportError("Could not open file for reading");
  276|      0|        }
  277|      5|    }
  278|      5|    std::string::size_type slashPos = pFile.find_last_of("\\/");
  279|       |
  280|      5|    mScene = pScene;
  281|      5|    pScene->mRootNode = new aiNode(pFile);
  282|      5|    pScene->mRootNode->mParent = nullptr;
  283|      5|    pScene->mFlags |= AI_SCENE_FLAGS_ALLOW_SHARED;
  284|       |
  285|      5|    if (isReadFromMem) {
  ------------------
  |  Branch (285:9): [True: 0, False: 5]
  ------------------
  286|      0|        ParseFile(ss);
  287|      5|    } else {
  288|      5|        pIOHandler->PushDirectory(slashPos == std::string::npos ? std::string() : pFile.substr(0, slashPos + 1));
  ------------------
  |  Branch (288:35): [True: 0, False: 5]
  ------------------
  289|      5|        ParseFile(pFile, pIOHandler);
  290|      5|        pIOHandler->PopDirectory();
  291|      5|    }
  292|       |
  293|       |    //search for root node element
  294|       |
  295|      5|    mNodeElementCur = NodeElement_List.front();
  296|      5|    if (mNodeElementCur == nullptr) {
  ------------------
  |  Branch (296:9): [True: 5, False: 0]
  ------------------
  297|      5|        return;
  298|      5|    }
  299|      0|    while (mNodeElementCur->Parent != nullptr) {
  ------------------
  |  Branch (299:12): [True: 0, False: 0]
  ------------------
  300|      0|        mNodeElementCur = mNodeElementCur->Parent;
  301|      0|    }
  302|       |
  303|      0|    { // fill aiScene with objects.
  304|      0|        std::list<aiMesh *> mesh_list;
  305|      0|        std::list<aiMaterial *> mat_list;
  306|      0|        std::list<aiLight *> light_list;
  307|       |
  308|       |        // create nodes tree
  309|      0|        Postprocess_BuildNode(*mNodeElementCur, *pScene->mRootNode, mesh_list, mat_list, light_list);
  310|       |        // copy needed data to scene
  311|      0|        if (!mesh_list.empty()) {
  ------------------
  |  Branch (311:13): [True: 0, False: 0]
  ------------------
  312|      0|            std::list<aiMesh *>::const_iterator it = mesh_list.begin();
  313|       |
  314|      0|            pScene->mNumMeshes = static_cast<unsigned int>(mesh_list.size());
  315|      0|            pScene->mMeshes = new aiMesh *[pScene->mNumMeshes];
  316|      0|            for (size_t i = 0; i < pScene->mNumMeshes; i++)
  ------------------
  |  Branch (316:32): [True: 0, False: 0]
  ------------------
  317|      0|                pScene->mMeshes[i] = *it++;
  318|      0|        }
  319|       |
  320|      0|        if (!mat_list.empty()) {
  ------------------
  |  Branch (320:13): [True: 0, False: 0]
  ------------------
  321|      0|            std::list<aiMaterial *>::const_iterator it = mat_list.begin();
  322|       |
  323|      0|            pScene->mNumMaterials = static_cast<unsigned int>(mat_list.size());
  324|      0|            pScene->mMaterials = new aiMaterial *[pScene->mNumMaterials];
  325|      0|            for (size_t i = 0; i < pScene->mNumMaterials; i++)
  ------------------
  |  Branch (325:32): [True: 0, False: 0]
  ------------------
  326|      0|                pScene->mMaterials[i] = *it++;
  327|      0|        }
  328|       |
  329|      0|        if (!light_list.empty()) {
  ------------------
  |  Branch (329:13): [True: 0, False: 0]
  ------------------
  330|      0|            std::list<aiLight *>::const_iterator it = light_list.begin();
  331|       |
  332|      0|            pScene->mNumLights = static_cast<unsigned int>(light_list.size());
  333|      0|            pScene->mLights = new aiLight *[pScene->mNumLights];
  334|      0|            for (size_t i = 0; i < pScene->mNumLights; i++)
  ------------------
  |  Branch (334:32): [True: 0, False: 0]
  ------------------
  335|      0|                pScene->mLights[i] = *it++;
  336|      0|        }
  337|      0|    }
  338|      0|}
_ZNK6Assimp11X3DImporter7GetInfoEv:
  340|    639|const aiImporterDesc *X3DImporter::GetInfo() const {
  341|    639|    return &Description;
  342|    639|}

_ZN6Assimp11XGLImporterC2Ev:
   75|    624|XGLImporter::XGLImporter() : mXmlParser(nullptr), m_scene(nullptr) {
   76|       |    // empty
   77|    624|}
_ZN6Assimp11XGLImporterD2Ev:
   80|    624|XGLImporter::~XGLImporter() {
   81|    624|    clear();
   82|    624|}
_ZNK6Assimp11XGLImporter7CanReadERKNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEPNS_8IOSystemEb:
   85|     51|bool XGLImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool /*checkSig*/) const {
   86|     51|	static const char *tokens[] = { "<world>", "<World>", "<WORLD>" };
   87|       |	return SearchFileHeaderForToken(pIOHandler, pFile, tokens, AI_COUNT_OF(tokens));
   88|     51|}
_ZNK6Assimp11XGLImporter7GetInfoEv:
   91|    636|const aiImporterDesc *XGLImporter::GetInfo() const {
   92|    636|	return &desc;
   93|    636|}
_ZN6Assimp11XGLImporter14InternReadFileERKNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEP7aiScenePNS_8IOSystemE:
   96|      2|void XGLImporter::InternReadFile(const std::string &pFile, aiScene *pScene, IOSystem *pIOHandler) {
   97|      2|    clear();
   98|      2|#ifndef ASSIMP_BUILD_NO_COMPRESSED_XGL
   99|      2|	std::vector<char> uncompressed;
  100|      2|#endif
  101|       |
  102|      2|	m_scene = pScene;
  103|      2|	std::shared_ptr<IOStream> stream(pIOHandler->Open(pFile, "rb"));
  104|       |
  105|       |	// check whether we can read from the file
  106|      2|    if (stream == nullptr) {
  ------------------
  |  Branch (106:9): [True: 0, False: 2]
  ------------------
  107|      0|        throw DeadlyImportError("Failed to open XGL/ZGL file " + pFile);
  108|      0|    }
  109|       |
  110|       |    // see if its compressed, if so uncompress it
  111|      2|	if (GetExtension(pFile) == "zgl") {
  ------------------
  |  Branch (111:6): [True: 0, False: 2]
  ------------------
  112|       |#ifdef ASSIMP_BUILD_NO_COMPRESSED_XGL
  113|       |		ThrowException("Cannot read ZGL file since Assimp was built without compression support");
  114|       |#else
  115|      0|		std::unique_ptr<StreamReaderLE> raw_reader(new StreamReaderLE(stream));
  116|       |
  117|      0|        Compression compression;
  118|      0|        size_t total = 0l;
  119|      0|        if (compression.open(Compression::Format::Binary, Compression::FlushMode::NoFlush, -Compression::MaxWBits)) {
  ------------------
  |  Branch (119:13): [True: 0, False: 0]
  ------------------
  120|       |            // skip two extra bytes, zgl files do carry a crc16 upfront (I think)
  121|      0|            raw_reader->IncPtr(2);
  122|      0|            total = compression.decompress((unsigned char *)raw_reader->GetPtr(), raw_reader->GetRemainingSize(), uncompressed);
  123|      0|            compression.close();
  124|      0|        }
  125|       |		// replace the input stream with a memory stream
  126|      0|        stream = std::make_shared<MemoryIOStream>(reinterpret_cast<uint8_t *>(uncompressed.data()), total);
  127|      0|#endif
  128|      0|	}
  129|       |
  130|       |	// parse the XML file
  131|      2|    mXmlParser = new XmlParser;
  132|      2|    if (!mXmlParser->parse(stream.get())) {
  ------------------
  |  Branch (132:9): [True: 2, False: 0]
  ------------------
  133|      2|        throw DeadlyImportError("XML parse error while loading XGL file ", pFile);
  134|      2|	}
  135|       |
  136|      0|	TempScope scope;
  137|      0|    XmlNode *worldNode = mXmlParser->findNode("WORLD");
  138|      0|    if (nullptr != worldNode) {
  ------------------
  |  Branch (138:9): [True: 0, False: 0]
  ------------------
  139|      0|		ReadWorld(*worldNode, scope);
  140|      0|	}
  141|       |
  142|      0|	std::vector<aiMesh *> &meshes = scope.meshes_linear;
  143|      0|	std::vector<aiMaterial *> &materials = scope.materials_linear;
  144|      0|	if (meshes.empty() || materials.empty()) {
  ------------------
  |  Branch (144:6): [True: 0, False: 0]
  |  Branch (144:24): [True: 0, False: 0]
  ------------------
  145|      0|		ThrowException("failed to extract data from XGL file, no meshes loaded");
  146|      0|	}
  147|       |
  148|       |	// copy meshes
  149|      0|	m_scene->mNumMeshes = static_cast<unsigned int>(meshes.size());
  150|      0|	m_scene->mMeshes = new aiMesh *[m_scene->mNumMeshes]();
  151|      0|	std::copy(meshes.begin(), meshes.end(), m_scene->mMeshes);
  152|       |
  153|       |	// copy materials
  154|      0|	m_scene->mNumMaterials = static_cast<unsigned int>(materials.size());
  155|      0|	m_scene->mMaterials = new aiMaterial *[m_scene->mNumMaterials]();
  156|      0|	std::copy(materials.begin(), materials.end(), m_scene->mMaterials);
  157|       |
  158|      0|	if (scope.light) {
  ------------------
  |  Branch (158:6): [True: 0, False: 0]
  ------------------
  159|      0|		m_scene->mNumLights = 1;
  160|      0|		m_scene->mLights = new aiLight *[1];
  161|      0|		m_scene->mLights[0] = scope.light;
  162|       |
  163|      0|		scope.light->mName = m_scene->mRootNode->mName;
  164|      0|	}
  165|       |
  166|      0|	scope.dismiss();
  167|      0|}
_ZN6Assimp11XGLImporter5clearEv:
  170|    626|void XGLImporter::clear() {
  171|    626|    delete mXmlParser;
  172|    626|    mXmlParser = nullptr;
  173|    626|}

_ZN4glTF6ObjectD2Ev:
  312|     36|    virtual ~Object() = default;
_ZN4glTF6ObjectC2Ev:
  311|     43|    Object() = default;
_ZN4glTF6Buffer13MarkAsSpecialEv:
  484|      1|    void MarkAsSpecial() { mIsSpecial = true; }
_ZN4glTF10AttribType16GetNumComponentsENS0_5ValueE:
  274|      5|    inline static unsigned int GetNumComponents(Value type) {
  275|      5|        return data<0>::infos[static_cast<size_t>(type)].numComponents;
  276|      5|    }
_ZN4glTF17ComponentTypeSizeENS_13ComponentTypeE:
  177|      4|inline unsigned int ComponentTypeSize(ComponentType t) {
  178|      4|    switch (t) {
  179|      0|    case ComponentType_SHORT:
  ------------------
  |  Branch (179:5): [True: 0, False: 4]
  ------------------
  180|      1|    case ComponentType_UNSIGNED_SHORT:
  ------------------
  |  Branch (180:5): [True: 1, False: 3]
  ------------------
  181|      1|        return 2;
  182|       |
  183|      0|    case ComponentType_UNSIGNED_INT:
  ------------------
  |  Branch (183:5): [True: 0, False: 4]
  ------------------
  184|      3|    case ComponentType_FLOAT:
  ------------------
  |  Branch (184:5): [True: 3, False: 1]
  ------------------
  185|      3|        return 4;
  186|       |
  187|      0|    case ComponentType_BYTE:
  ------------------
  |  Branch (187:5): [True: 0, False: 4]
  ------------------
  188|      0|    case ComponentType_UNSIGNED_BYTE:
  ------------------
  |  Branch (188:5): [True: 0, False: 4]
  ------------------
  189|      0|        return 1;
  190|      0|    default:
  ------------------
  |  Branch (190:5): [True: 0, False: 4]
  ------------------
  191|      0|        std::string err = "GLTF: Unsupported Component Type ";
  192|      0|        err += std::to_string(t);
  193|      0|        throw DeadlyImportError(err);
  194|      4|    }
  195|      4|}
_ZN4glTF8AccessorC2Ev:
  380|      9|    Accessor() = default;
_ZN4glTF6Buffer10GetPointerEv:
  482|      4|    uint8_t *GetPointer() { return mData.get(); }
_ZN4glTF6Object11TranslateIdERNS_5AssetEPKc:
  315|     43|    static const char *TranslateId(Asset & /*r*/, const char *id) { return id; }
_ZN4glTF4NodeC2Ev:
  701|     11|    Node() = default;
_ZN4glTF4MeshC2Ev:
  661|      3|    Mesh() = default;
_ZN4glTF4MeshD2Ev:
  664|      2|    ~Mesh() {
  665|      2|        for (std::list<SExtension *>::iterator it = Extension.begin(), it_end = Extension.end(); it != it_end; it++) {
  ------------------
  |  Branch (665:98): [True: 0, False: 2]
  ------------------
  666|      0|            delete *it;
  667|      0|        };
  668|      2|    }
_ZN4glTF10AttribType10FromStringEPKc:
  261|      8|    inline static Value FromString(const char *str) {
  262|     18|        for (size_t i = 0; i < NUM_VALUES; ++i) {
  ------------------
  |  Branch (262:28): [True: 18, False: 0]
  ------------------
  263|     18|            if (strcmp(data<0>::infos[i].name, str) == 0) {
  ------------------
  |  Branch (263:17): [True: 8, False: 10]
  ------------------
  264|      8|                return static_cast<Value>(i);
  265|      8|            }
  266|     18|        }
  267|      0|        return SCALAR;
  268|      8|    }
_ZN4glTF8MaterialC2Ev:
  586|      2|    Material() { SetDefaults(); }
_ZN4glTF7TextureC2Ev:
  762|      2|    Texture() = default;
_ZN4glTF7SamplerC2Ev:
  716|      2|    Sampler() = default;
_ZN4glTF5AssetC2EPN6Assimp8IOSystemE:
  966|     50|            mIOSystem(io),
  967|     50|            asset(),
  968|     50|            accessors(*this, "accessors"),
  969|     50|            animations(*this, "animations"),
  970|     50|            buffers(*this, "buffers"),
  971|     50|            bufferViews(*this, "bufferViews"),
  972|     50|            cameras(*this, "cameras"),
  973|     50|            images(*this, "images"),
  974|     50|            materials(*this, "materials"),
  975|     50|            meshes(*this, "meshes"),
  976|     50|            nodes(*this, "nodes"),
  977|     50|            samplers(*this, "samplers"),
  978|     50|            scenes(*this, "scenes"),
  979|     50|            skins(*this, "skins"),
  980|     50|            textures(*this, "textures"),
  981|     50|            lights(*this, "lights", "KHR_materials_common") {
  982|     50|        memset(&extensionsUsed, 0, sizeof(extensionsUsed));
  983|     50|    }
_ZN4glTF13AssetMetadataC2Ev:
  898|     50|            premultipliedAlpha(false) {
  899|     50|    }
_ZN4glTF12LazyDictBaseD2Ev:
  825|    700|    virtual ~LazyDictBase() = default;
_ZNK4glTF5Image7HasDataEv:
  543|      2|    inline bool HasData() const { return mDataLength > 0; }
_ZNK4glTF5Image13GetDataLengthEv:
  544|      1|    inline size_t GetDataLength() const { return mDataLength; }
_ZN4glTF5SceneC2Ev:
  724|      3|    Scene() = default;
_ZN4glTF8Accessor7Indexer7GetUIntEi:
  367|     36|        inline unsigned int GetUInt(int i) {
  368|     36|            return GetValue<unsigned int>(i);
  369|     36|        }
_ZNK4glTF8Accessor7Indexer7IsValidEv:
  371|      1|        inline bool IsValid() const {
  372|      1|            return data != nullptr;
  373|      1|        }
_ZN4glTF8Accessor10GetIndexerEv:
  376|      1|    inline Indexer GetIndexer() {
  377|      1|        return Indexer(*this);
  378|      1|    }
_ZNK4glTF13AssetMetadatacvbEv:
  901|     14|    operator bool() const { return version.size() && version[0] == '1'; }
  ------------------
  |  Branch (901:36): [True: 14, False: 0]
  |  Branch (901:54): [True: 4, False: 10]
  ------------------
_ZNK4glTF8LazyDictINS_8MaterialEE4SizeEv:
  878|      1|    inline unsigned int Size() const { return unsigned(mObjs.size()); }
_ZN4glTF8LazyDictINS_8MaterialEEixEm:
  880|      1|    inline T &operator[](size_t i) { return *mObjs[i]; }
_ZNK4glTF8LazyDictINS_4MeshEE4SizeEv:
  878|      2|    inline unsigned int Size() const { return unsigned(mObjs.size()); }
_ZN4glTF8LazyDictINS_4MeshEEixEm:
  880|      1|    inline T &operator[](size_t i) { return *mObjs[i]; }
_ZNK4glTF8LazyDictINS_6CameraEE4SizeEv:
  878|      1|    inline unsigned int Size() const { return unsigned(mObjs.size()); }
_ZNK4glTF8LazyDictINS_5LightEE4SizeEv:
  878|      1|    inline unsigned int Size() const { return unsigned(mObjs.size()); }
_ZNK4glTF8LazyDictINS_5ImageEE4SizeEv:
  878|      5|    inline unsigned int Size() const { return unsigned(mObjs.size()); }
_ZN4glTF8LazyDictINS_5ImageEEixEm:
  880|      2|    inline T &operator[](size_t i) { return *mObjs[i]; }

_ZN4glTF6BufferD2Ev:
  166|      3|inline Buffer::~Buffer() {
  167|      3|    for (SEncodedRegion *reg : EncodedRegion_List)
  ------------------
  |  Branch (167:30): [True: 0, False: 3]
  ------------------
  168|      0|        delete reg;
  169|      3|}
_ZN4glTF5Asset11SetAsBinaryEv:
 1245|      1|inline void Asset::SetAsBinary() {
 1246|      1|    if (!extensionsUsed.KHR_binary_glTF) {
  ------------------
  |  Branch (1246:9): [True: 1, False: 0]
  ------------------
 1247|      1|        extensionsUsed.KHR_binary_glTF = true;
 1248|      1|        mBodyBuffer = buffers.Create("binary_glTF");
 1249|      1|        mBodyBuffer->MarkAsSpecial();
 1250|      1|    }
 1251|      1|}
_ZN4glTF8LazyDictINS_6BufferEE6CreateEPKc:
  149|      1|Ref<T> LazyDict<T>::Create(const char *id) {
  150|      1|    Asset::IdMap::iterator it = mAsset.mUsedIds.find(id);
  151|      1|    if (it != mAsset.mUsedIds.end()) {
  ------------------
  |  Branch (151:9): [True: 0, False: 1]
  ------------------
  152|      0|        throw DeadlyImportError("GLTF: two objects with the same ID exist");
  153|      0|    }
  154|      1|    T *inst = new T();
  155|      1|    inst->id = id;
  156|      1|    return Add(inst);
  157|      1|}
_ZN4glTF6BufferC2Ev:
  164|      4|        byteLength(0), type(Type_arraybuffer), EncodedRegion_Current(nullptr), mIsSpecial(false) {}
_ZN4glTF8LazyDictINS_6BufferEE3AddEPS1_:
  140|      3|Ref<T> LazyDict<T>::Add(T *obj) {
  141|      3|    unsigned int idx = unsigned(mObjs.size());
  142|      3|    mObjs.push_back(obj);
  143|      3|    mObjsById[obj->id] = idx;
  144|      3|    mAsset.mUsedIds[obj->id] = true;
  145|      3|    return Ref<T>(mObjs, idx);
  146|      3|}
_ZN4glTF5Asset8OpenFileERKNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEPKcb:
 1271|     51|inline IOStream *Asset::OpenFile(const std::string &path, const char *mode, bool absolute) {
 1272|     51|#ifdef ASSIMP_API
 1273|     51|    (void)absolute;
 1274|     51|    return mIOSystem->Open(path, mode);
 1275|       |#else
 1276|       |    if (path.size() < 2) return 0;
 1277|       |    if (!absolute && path[1] != ':' && path[0] != '/') { // relative?
 1278|       |        path = mCurrentAssetDir + path;
 1279|       |    }
 1280|       |    FILE *f = fopen(path.c_str(), mode);
 1281|       |    return f ? new IOStream(f) : 0;
 1282|       |#endif
 1283|     51|}
_ZN4glTF8LazyDictINS_10BufferViewEE3AddEPS1_:
  140|      4|Ref<T> LazyDict<T>::Add(T *obj) {
  141|      4|    unsigned int idx = unsigned(mObjs.size());
  142|      4|    mObjs.push_back(obj);
  143|      4|    mObjsById[obj->id] = idx;
  144|      4|    mAsset.mUsedIds[obj->id] = true;
  145|      4|    return Ref<T>(mObjs, idx);
  146|      4|}
_ZN4glTF8LazyDictINS_8AccessorEE3AddEPS1_:
  140|      8|Ref<T> LazyDict<T>::Add(T *obj) {
  141|      8|    unsigned int idx = unsigned(mObjs.size());
  142|      8|    mObjs.push_back(obj);
  143|      8|    mObjsById[obj->id] = idx;
  144|      8|    mAsset.mUsedIds[obj->id] = true;
  145|      8|    return Ref<T>(mObjs, idx);
  146|      8|}
_ZN4glTF8Accessor16GetNumComponentsEv:
  373|      5|inline unsigned int Accessor::GetNumComponents() {
  374|      5|    return AttribType::GetNumComponents(type);
  375|      5|}
_ZN4glTF8Accessor20GetBytesPerComponentEv:
  377|      4|inline unsigned int Accessor::GetBytesPerComponent() {
  378|      4|    return int(ComponentTypeSize(componentType));
  379|      4|}
_ZN4glTF8LazyDictINS_4NodeEE3GetEPKc:
  110|     11|Ref<T> LazyDict<T>::Get(const char *id) {
  111|     11|    id = T::TranslateId(mAsset, id);
  112|       |
  113|     11|    typename Dict::iterator it = mObjsById.find(id);
  114|     11|    if (it != mObjsById.end()) { // already created?
  ------------------
  |  Branch (114:9): [True: 0, False: 11]
  ------------------
  115|      0|        return Ref<T>(mObjs, it->second);
  116|      0|    }
  117|       |
  118|       |    // read it from the JSON object
  119|     11|    if (!mDict) {
  ------------------
  |  Branch (119:9): [True: 0, False: 11]
  ------------------
  120|      0|        throw DeadlyImportError("GLTF: Missing section \"", mDictId, "\"");
  121|      0|    }
  122|       |
  123|     11|    Value::MemberIterator obj = mDict->FindMember(id);
  124|     11|    if (obj == mDict->MemberEnd()) {
  ------------------
  |  Branch (124:9): [True: 0, False: 11]
  ------------------
  125|      0|        throw DeadlyImportError("GLTF: Missing object with id \"", id, "\" in \"", mDictId, "\"");
  126|      0|    }
  127|     11|    if (!obj->value.IsObject()) {
  ------------------
  |  Branch (127:9): [True: 0, False: 11]
  ------------------
  128|      0|        throw DeadlyImportError("GLTF: Object with id \"", id, "\" is not a JSON object");
  129|      0|    }
  130|       |
  131|       |    // create an instance of the given type
  132|     11|    T *inst = new T();
  133|     11|    inst->id = id;
  134|     11|    ReadMember(obj->value, "name", inst->name);
  135|     11|    inst->Read(obj->value, mAsset);
  136|     11|    return Add(inst);
  137|     11|}
_ZN4glTF4Node4ReadERN9rapidjson12GenericValueINS1_4UTF8IcEENS1_19MemoryPoolAllocatorINS1_12CrtAllocatorEEEEERNS_5AssetE:
 1015|     11|inline void Node::Read(Value &obj, Asset &r) {
 1016|     11|    if (name.empty()) {
  ------------------
  |  Branch (1016:9): [True: 0, False: 11]
  ------------------
 1017|      0|        name = id;
 1018|      0|    }
 1019|       |
 1020|     11|    Value *curChildren = FindArray(obj, "children");
 1021|     11|    if (nullptr != curChildren) {
  ------------------
  |  Branch (1021:9): [True: 11, False: 0]
  ------------------
 1022|     11|        this->children.reserve(curChildren->Size());
 1023|     18|        for (unsigned int i = 0; i < curChildren->Size(); ++i) {
  ------------------
  |  Branch (1023:34): [True: 7, False: 11]
  ------------------
 1024|      7|            Value &child = (*curChildren)[i];
 1025|      7|            if (child.IsString()) {
  ------------------
  |  Branch (1025:17): [True: 7, False: 0]
  ------------------
 1026|       |                // get/create the child node
 1027|      7|                Ref<Node> chn = r.nodes.Get(child.GetString());
 1028|      7|                if (chn) this->children.push_back(chn);
  ------------------
  |  Branch (1028:21): [True: 6, False: 1]
  ------------------
 1029|      7|            }
 1030|      7|        }
 1031|     11|    }
 1032|       |
 1033|     11|    Value *curMatrix = FindArray(obj, "matrix");
 1034|     11|    if (nullptr != curMatrix) {
  ------------------
  |  Branch (1034:9): [True: 9, False: 2]
  ------------------
 1035|      9|        ReadValue(*curMatrix, this->matrix);
 1036|      9|    } else {
 1037|      2|        ReadMember(obj, "translation", translation);
 1038|      2|        ReadMember(obj, "scale", scale);
 1039|      2|        ReadMember(obj, "rotation", rotation);
 1040|      2|    }
 1041|       |
 1042|     11|    Value *curMeshes = FindArray(obj, "meshes");
 1043|     11|    if (nullptr != curMeshes) {
  ------------------
  |  Branch (1043:9): [True: 3, False: 8]
  ------------------
 1044|      3|        unsigned int numMeshes = (unsigned int)curMeshes->Size();
 1045|       |
 1046|      3|        std::vector<unsigned int> meshList;
 1047|       |
 1048|      3|        this->meshes.reserve(numMeshes);
 1049|      6|        for (unsigned i = 0; i < numMeshes; ++i) {
  ------------------
  |  Branch (1049:30): [True: 3, False: 3]
  ------------------
 1050|      3|            if ((*curMeshes)[i].IsString()) {
  ------------------
  |  Branch (1050:17): [True: 3, False: 0]
  ------------------
 1051|      3|                Ref<Mesh> mesh = r.meshes.Get((*curMeshes)[i].GetString());
 1052|      3|                if (mesh) {
  ------------------
  |  Branch (1052:21): [True: 2, False: 1]
  ------------------
 1053|      2|                    this->meshes.push_back(mesh);
 1054|      2|                }
 1055|      3|            }
 1056|      3|        }
 1057|      3|    }
 1058|       |
 1059|     11|    Value *curCamera = FindString(obj, "camera");
 1060|     11|    if (nullptr != curCamera) {
  ------------------
  |  Branch (1060:9): [True: 0, False: 11]
  ------------------
 1061|      0|        this->camera = r.cameras.Get(curCamera->GetString());
 1062|      0|        if (this->camera) {
  ------------------
  |  Branch (1062:13): [True: 0, False: 0]
  ------------------
 1063|      0|            this->camera->id = this->id;
 1064|      0|        }
 1065|      0|    }
 1066|       |
 1067|       |    // TODO load "skeletons", "skin", "jointName"
 1068|       |
 1069|     11|    if (Value *extensions = FindObject(obj, "extensions")) {
  ------------------
  |  Branch (1069:16): [True: 0, False: 11]
  ------------------
 1070|      0|        if (r.extensionsUsed.KHR_materials_common) {
  ------------------
  |  Branch (1070:13): [True: 0, False: 0]
  ------------------
 1071|       |
 1072|      0|            if (Value *ext = FindObject(*extensions, "KHR_materials_common")) {
  ------------------
  |  Branch (1072:24): [True: 0, False: 0]
  ------------------
 1073|      0|                Value *curLight = FindString(*ext, "light");
 1074|      0|                if (nullptr != curLight) {
  ------------------
  |  Branch (1074:21): [True: 0, False: 0]
  ------------------
 1075|      0|                    this->light = r.lights.Get(curLight->GetString());
 1076|      0|                }
 1077|      0|            }
 1078|      0|        }
 1079|      0|    }
 1080|     11|}
_ZN4glTF8LazyDictINS_4MeshEE3GetEPKc:
  110|      3|Ref<T> LazyDict<T>::Get(const char *id) {
  111|      3|    id = T::TranslateId(mAsset, id);
  112|       |
  113|      3|    typename Dict::iterator it = mObjsById.find(id);
  114|      3|    if (it != mObjsById.end()) { // already created?
  ------------------
  |  Branch (114:9): [True: 0, False: 3]
  ------------------
  115|      0|        return Ref<T>(mObjs, it->second);
  116|      0|    }
  117|       |
  118|       |    // read it from the JSON object
  119|      3|    if (!mDict) {
  ------------------
  |  Branch (119:9): [True: 0, False: 3]
  ------------------
  120|      0|        throw DeadlyImportError("GLTF: Missing section \"", mDictId, "\"");
  121|      0|    }
  122|       |
  123|      3|    Value::MemberIterator obj = mDict->FindMember(id);
  124|      3|    if (obj == mDict->MemberEnd()) {
  ------------------
  |  Branch (124:9): [True: 0, False: 3]
  ------------------
  125|      0|        throw DeadlyImportError("GLTF: Missing object with id \"", id, "\" in \"", mDictId, "\"");
  126|      0|    }
  127|      3|    if (!obj->value.IsObject()) {
  ------------------
  |  Branch (127:9): [True: 0, False: 3]
  ------------------
  128|      0|        throw DeadlyImportError("GLTF: Object with id \"", id, "\" is not a JSON object");
  129|      0|    }
  130|       |
  131|       |    // create an instance of the given type
  132|      3|    T *inst = new T();
  133|      3|    inst->id = id;
  134|      3|    ReadMember(obj->value, "name", inst->name);
  135|      3|    inst->Read(obj->value, mAsset);
  136|      3|    return Add(inst);
  137|      3|}
_ZN4glTF4Mesh4ReadERN9rapidjson12GenericValueINS1_4UTF8IcEENS1_19MemoryPoolAllocatorINS1_12CrtAllocatorEEEEERNS_5AssetE:
  682|      3|inline void Mesh::Read(Value &pJSON_Object, Asset &pAsset_Root) {
  683|       |    /****************** Mesh primitives ******************/
  684|      3|    Value *curPrimitives = FindArray(pJSON_Object, "primitives");
  685|      3|    if (nullptr != curPrimitives) {
  ------------------
  |  Branch (685:9): [True: 3, False: 0]
  ------------------
  686|      3|        this->primitives.resize(curPrimitives->Size());
  687|      6|        for (unsigned int i = 0; i < curPrimitives->Size(); ++i) {
  ------------------
  |  Branch (687:34): [True: 3, False: 3]
  ------------------
  688|      3|            Value &primitive = (*curPrimitives)[i];
  689|       |
  690|      3|            Primitive &prim = this->primitives[i];
  691|      3|            prim.mode = MemberOrDefault(primitive, "mode", PrimitiveMode_TRIANGLES);
  692|       |
  693|      3|            if (Value *attrs = FindObject(primitive, "attributes")) {
  ------------------
  |  Branch (693:24): [True: 3, False: 0]
  ------------------
  694|     10|                for (Value::MemberIterator it = attrs->MemberBegin(); it != attrs->MemberEnd(); ++it) {
  ------------------
  |  Branch (694:71): [True: 7, False: 3]
  ------------------
  695|      7|                    if (!it->value.IsString()) continue;
  ------------------
  |  Branch (695:25): [True: 0, False: 7]
  ------------------
  696|      7|                    const char *attr = it->name.GetString();
  697|       |                    // Valid attribute semantics include POSITION, NORMAL, TEXCOORD, COLOR, JOINT, JOINTMATRIX,
  698|       |                    // and WEIGHT.Attribute semantics can be of the form[semantic]_[set_index], e.g., TEXCOORD_0, TEXCOORD_1, etc.
  699|       |
  700|      7|                    int undPos = 0;
  701|      7|                    Mesh::AccessorList *vec = nullptr;
  702|      7|                    if (GetAttribVector(prim, attr, vec, undPos)) {
  ------------------
  |  Branch (702:25): [True: 7, False: 0]
  ------------------
  703|      7|                        size_t idx = (attr[undPos] == '_') ? atoi(attr + undPos + 1) : 0;
  ------------------
  |  Branch (703:38): [True: 2, False: 5]
  ------------------
  704|      7|                        if ((*vec).size() <= idx) (*vec).resize(idx + 1);
  ------------------
  |  Branch (704:29): [True: 7, False: 0]
  ------------------
  705|      7|                        (*vec)[idx] = pAsset_Root.accessors.Get(it->value.GetString());
  706|      7|                    }
  707|      7|                }
  708|      3|            }
  709|       |
  710|      3|            if (Value *indices = FindString(primitive, "indices")) {
  ------------------
  |  Branch (710:24): [True: 2, False: 1]
  ------------------
  711|      2|                prim.indices = pAsset_Root.accessors.Get(indices->GetString());
  712|      2|            }
  713|       |
  714|      3|            if (Value *material = FindString(primitive, "material")) {
  ------------------
  |  Branch (714:24): [True: 2, False: 1]
  ------------------
  715|      2|                prim.material = pAsset_Root.materials.Get(material->GetString());
  716|      2|            }
  717|      3|        }
  718|      3|    }
  719|       |
  720|       |    /****************** Mesh extensions ******************/
  721|      3|    Value *json_extensions = FindObject(pJSON_Object, "extensions");
  722|       |
  723|      3|    if (json_extensions == nullptr) goto mr_skip_extensions;
  ------------------
  |  Branch (723:9): [True: 2, False: 1]
  ------------------
  724|       |
  725|      1|#ifdef ASSIMP_IMPORTER_GLTF_USE_OPEN3DGC
  726|      1|    for (Value::MemberIterator it_memb = json_extensions->MemberBegin(); it_memb != json_extensions->MemberEnd(); it_memb++) {
  ------------------
  |  Branch (726:74): [True: 0, False: 1]
  ------------------
  727|      0|        if (it_memb->name.GetString() == std::string("Open3DGC-compression")) {
  ------------------
  |  Branch (727:13): [True: 0, False: 0]
  ------------------
  728|       |            // Search for compressed data.
  729|       |            // Compressed data contain description of part of "buffer" which is encoded. This part must be decoded and
  730|       |            // new data will replace old encoded part by request. In fact \"compressedData\" is kind of "accessor" structure.
  731|      0|            Value *comp_data = FindObject(it_memb->value, "compressedData");
  732|       |
  733|      0|            if (comp_data == nullptr) throw DeadlyImportError("GLTF: \"Open3DGC-compression\" must has \"compressedData\".");
  ------------------
  |  Branch (733:17): [True: 0, False: 0]
  ------------------
  734|       |
  735|      0|            ASSIMP_LOG_INFO("GLTF: Decompressing Open3DGC data.");
  736|       |
  737|       |/************** Read data from JSON-document **************/
  738|      0|#define MESH_READ_COMPRESSEDDATA_MEMBER(pFieldName, pOut)                                   \
  739|      0|    if (!ReadMember(*comp_data, pFieldName, pOut)) {                                        \
  740|      0|        throw DeadlyImportError("GLTF: \"compressedData\" must has \"", pFieldName, "\"."); \
  741|      0|    }
  742|       |
  743|      0|            const char *mode_str;
  744|      0|            const char *type_str;
  745|      0|            ComponentType component_type;
  746|      0|            SCompression_Open3DGC *ext_o3dgc = new SCompression_Open3DGC;
  747|       |
  748|      0|            MESH_READ_COMPRESSEDDATA_MEMBER("buffer", ext_o3dgc->Buffer);
  ------------------
  |  |  739|      0|    if (!ReadMember(*comp_data, pFieldName, pOut)) {                                        \
  |  |  ------------------
  |  |  |  Branch (739:9): [True: 0, False: 0]
  |  |  ------------------
  |  |  740|      0|        throw DeadlyImportError("GLTF: \"compressedData\" must has \"", pFieldName, "\"."); \
  |  |  741|      0|    }
  ------------------
  749|      0|            MESH_READ_COMPRESSEDDATA_MEMBER("byteOffset", ext_o3dgc->Offset);
  ------------------
  |  |  739|      0|    if (!ReadMember(*comp_data, pFieldName, pOut)) {                                        \
  |  |  ------------------
  |  |  |  Branch (739:9): [True: 0, False: 0]
  |  |  ------------------
  |  |  740|      0|        throw DeadlyImportError("GLTF: \"compressedData\" must has \"", pFieldName, "\"."); \
  |  |  741|      0|    }
  ------------------
  750|      0|            MESH_READ_COMPRESSEDDATA_MEMBER("componentType", component_type);
  ------------------
  |  |  739|      0|    if (!ReadMember(*comp_data, pFieldName, pOut)) {                                        \
  |  |  ------------------
  |  |  |  Branch (739:9): [True: 0, False: 0]
  |  |  ------------------
  |  |  740|      0|        throw DeadlyImportError("GLTF: \"compressedData\" must has \"", pFieldName, "\"."); \
  |  |  741|      0|    }
  ------------------
  751|      0|            MESH_READ_COMPRESSEDDATA_MEMBER("type", type_str);
  ------------------
  |  |  739|      0|    if (!ReadMember(*comp_data, pFieldName, pOut)) {                                        \
  |  |  ------------------
  |  |  |  Branch (739:9): [True: 0, False: 0]
  |  |  ------------------
  |  |  740|      0|        throw DeadlyImportError("GLTF: \"compressedData\" must has \"", pFieldName, "\"."); \
  |  |  741|      0|    }
  ------------------
  752|      0|            MESH_READ_COMPRESSEDDATA_MEMBER("count", ext_o3dgc->Count);
  ------------------
  |  |  739|      0|    if (!ReadMember(*comp_data, pFieldName, pOut)) {                                        \
  |  |  ------------------
  |  |  |  Branch (739:9): [True: 0, False: 0]
  |  |  ------------------
  |  |  740|      0|        throw DeadlyImportError("GLTF: \"compressedData\" must has \"", pFieldName, "\"."); \
  |  |  741|      0|    }
  ------------------
  753|      0|            MESH_READ_COMPRESSEDDATA_MEMBER("mode", mode_str);
  ------------------
  |  |  739|      0|    if (!ReadMember(*comp_data, pFieldName, pOut)) {                                        \
  |  |  ------------------
  |  |  |  Branch (739:9): [True: 0, False: 0]
  |  |  ------------------
  |  |  740|      0|        throw DeadlyImportError("GLTF: \"compressedData\" must has \"", pFieldName, "\"."); \
  |  |  741|      0|    }
  ------------------
  754|      0|            MESH_READ_COMPRESSEDDATA_MEMBER("indicesCount", ext_o3dgc->IndicesCount);
  ------------------
  |  |  739|      0|    if (!ReadMember(*comp_data, pFieldName, pOut)) {                                        \
  |  |  ------------------
  |  |  |  Branch (739:9): [True: 0, False: 0]
  |  |  ------------------
  |  |  740|      0|        throw DeadlyImportError("GLTF: \"compressedData\" must has \"", pFieldName, "\"."); \
  |  |  741|      0|    }
  ------------------
  755|      0|            MESH_READ_COMPRESSEDDATA_MEMBER("verticesCount", ext_o3dgc->VerticesCount);
  ------------------
  |  |  739|      0|    if (!ReadMember(*comp_data, pFieldName, pOut)) {                                        \
  |  |  ------------------
  |  |  |  Branch (739:9): [True: 0, False: 0]
  |  |  ------------------
  |  |  740|      0|        throw DeadlyImportError("GLTF: \"compressedData\" must has \"", pFieldName, "\"."); \
  |  |  741|      0|    }
  ------------------
  756|       |
  757|      0|#undef MESH_READ_COMPRESSEDDATA_MEMBER
  758|       |
  759|       |            // Check some values
  760|      0|            if (strcmp(type_str, "SCALAR")) throw DeadlyImportError("GLTF: only \"SCALAR\" type is supported for compressed data.");
  ------------------
  |  Branch (760:17): [True: 0, False: 0]
  ------------------
  761|      0|            if (component_type != ComponentType_UNSIGNED_BYTE) throw DeadlyImportError("GLTF: only \"UNSIGNED_BYTE\" component type is supported for compressed data.");
  ------------------
  |  Branch (761:17): [True: 0, False: 0]
  ------------------
  762|       |
  763|       |            // Set read/write data mode.
  764|      0|            if (strcmp(mode_str, "binary") == 0)
  ------------------
  |  Branch (764:17): [True: 0, False: 0]
  ------------------
  765|      0|                ext_o3dgc->Binary = true;
  766|      0|            else if (strcmp(mode_str, "ascii") == 0)
  ------------------
  |  Branch (766:22): [True: 0, False: 0]
  ------------------
  767|      0|                ext_o3dgc->Binary = false;
  768|      0|            else
  769|      0|                throw DeadlyImportError("GLTF: for compressed data supported modes is: \"ascii\", \"binary\". Not the: \"", mode_str, "\".");
  770|       |
  771|       |            /************************ Decoding ************************/
  772|      0|            Decode_O3DGC(*ext_o3dgc, pAsset_Root);
  773|      0|            Extension.push_back(ext_o3dgc); // store info in mesh extensions list.
  774|      0|        } // if(it_memb->name.GetString() == "Open3DGC-compression")
  775|      0|        else {
  776|      0|            throw DeadlyImportError("GLTF: Unknown mesh extension: \"", it_memb->name.GetString(), "\".");
  777|      0|        }
  778|      0|    } // for(Value::MemberIterator it_memb = json_extensions->MemberBegin(); it_memb != json_extensions->MemberEnd(); json_extensions++)
  779|      1|#endif
  780|       |
  781|      2|mr_skip_extensions:
  782|       |
  783|      2|    return; // After label some operators must be present.
  784|      1|}
glTFExporter.cpp:_ZN4glTF12_GLOBAL__N_115GetAttribVectorERNS_4Mesh9PrimitiveEPKcRPNSt3__16vectorIN10glTFCommon3RefINS_8AccessorEEENS6_9allocatorISB_EEEERi:
  661|      7|inline bool GetAttribVector(Mesh::Primitive &p, const char *attr, Mesh::AccessorList *&v, int &pos) {
  662|      7|    if ((pos = Compare(attr, "POSITION"))) {
  ------------------
  |  Branch (662:9): [True: 2, False: 5]
  ------------------
  663|      2|        v = &(p.attributes.position);
  664|      5|    } else if ((pos = Compare(attr, "NORMAL"))) {
  ------------------
  |  Branch (664:16): [True: 3, False: 2]
  ------------------
  665|      3|        v = &(p.attributes.normal);
  666|      3|    } else if ((pos = Compare(attr, "TEXCOORD"))) {
  ------------------
  |  Branch (666:16): [True: 2, False: 0]
  ------------------
  667|      2|        v = &(p.attributes.texcoord);
  668|      2|    } else if ((pos = Compare(attr, "COLOR"))) {
  ------------------
  |  Branch (668:16): [True: 0, False: 0]
  ------------------
  669|      0|        v = &(p.attributes.color);
  670|      0|    } else if ((pos = Compare(attr, "JOINT"))) {
  ------------------
  |  Branch (670:16): [True: 0, False: 0]
  ------------------
  671|      0|        v = &(p.attributes.joint);
  672|      0|    } else if ((pos = Compare(attr, "JOINTMATRIX"))) {
  ------------------
  |  Branch (672:16): [True: 0, False: 0]
  ------------------
  673|      0|        v = &(p.attributes.jointmatrix);
  674|      0|    } else if ((pos = Compare(attr, "WEIGHT"))) {
  ------------------
  |  Branch (674:16): [True: 0, False: 0]
  ------------------
  675|      0|        v = &(p.attributes.weight);
  676|      0|    } else
  677|      0|        return false;
  678|      7|    return true;
  679|      7|}
glTFExporter.cpp:_ZN4glTF12_GLOBAL__N_17CompareILi9EEEiPKcRAT__S2_:
  657|      9|inline int Compare(const char *attr, const char (&str)[N]) {
  658|      9|    return (strncmp(attr, str, N - 1) == 0) ? N - 1 : 0;
  ------------------
  |  Branch (658:12): [True: 4, False: 5]
  ------------------
  659|      9|}
glTFExporter.cpp:_ZN4glTF12_GLOBAL__N_17CompareILi7EEEiPKcRAT__S2_:
  657|      5|inline int Compare(const char *attr, const char (&str)[N]) {
  658|      5|    return (strncmp(attr, str, N - 1) == 0) ? N - 1 : 0;
  ------------------
  |  Branch (658:12): [True: 3, False: 2]
  ------------------
  659|      5|}
_ZN4glTF8LazyDictINS_8AccessorEE3GetEPKc:
  110|      9|Ref<T> LazyDict<T>::Get(const char *id) {
  111|      9|    id = T::TranslateId(mAsset, id);
  112|       |
  113|      9|    typename Dict::iterator it = mObjsById.find(id);
  114|      9|    if (it != mObjsById.end()) { // already created?
  ------------------
  |  Branch (114:9): [True: 0, False: 9]
  ------------------
  115|      0|        return Ref<T>(mObjs, it->second);
  116|      0|    }
  117|       |
  118|       |    // read it from the JSON object
  119|      9|    if (!mDict) {
  ------------------
  |  Branch (119:9): [True: 0, False: 9]
  ------------------
  120|      0|        throw DeadlyImportError("GLTF: Missing section \"", mDictId, "\"");
  121|      0|    }
  122|       |
  123|      9|    Value::MemberIterator obj = mDict->FindMember(id);
  124|      9|    if (obj == mDict->MemberEnd()) {
  ------------------
  |  Branch (124:9): [True: 0, False: 9]
  ------------------
  125|      0|        throw DeadlyImportError("GLTF: Missing object with id \"", id, "\" in \"", mDictId, "\"");
  126|      0|    }
  127|      9|    if (!obj->value.IsObject()) {
  ------------------
  |  Branch (127:9): [True: 0, False: 9]
  ------------------
  128|      0|        throw DeadlyImportError("GLTF: Object with id \"", id, "\" is not a JSON object");
  129|      0|    }
  130|       |
  131|       |    // create an instance of the given type
  132|      9|    T *inst = new T();
  133|      9|    inst->id = id;
  134|      9|    ReadMember(obj->value, "name", inst->name);
  135|      9|    inst->Read(obj->value, mAsset);
  136|      9|    return Add(inst);
  137|      9|}
_ZN4glTF8Accessor4ReadERN9rapidjson12GenericValueINS1_4UTF8IcEENS1_19MemoryPoolAllocatorINS1_12CrtAllocatorEEEEERNS_5AssetE:
  358|      9|inline void Accessor::Read(Value &obj, Asset &r) {
  359|      9|    const char *bufferViewId = MemberOrDefault<const char *>(obj, "bufferView", 0);
  360|      9|    if (bufferViewId) {
  ------------------
  |  Branch (360:9): [True: 9, False: 0]
  ------------------
  361|      9|        bufferView = r.bufferViews.Get(bufferViewId);
  362|      9|    }
  363|       |
  364|      9|    byteOffset = MemberOrDefault(obj, "byteOffset", 0u);
  365|      9|    byteStride = MemberOrDefault(obj, "byteStride", 0u);
  366|      9|    componentType = MemberOrDefault(obj, "componentType", ComponentType_BYTE);
  367|      9|    count = MemberOrDefault(obj, "count", 0u);
  368|       |
  369|      9|    const char *typestr;
  370|      9|    type = ReadMember(obj, "type", typestr) ? AttribType::FromString(typestr) : AttribType::SCALAR;
  ------------------
  |  Branch (370:12): [True: 8, False: 1]
  ------------------
  371|      9|}
_ZN4glTF8LazyDictINS_10BufferViewEE3GetEPKc:
  110|      9|Ref<T> LazyDict<T>::Get(const char *id) {
  111|      9|    id = T::TranslateId(mAsset, id);
  112|       |
  113|      9|    typename Dict::iterator it = mObjsById.find(id);
  114|      9|    if (it != mObjsById.end()) { // already created?
  ------------------
  |  Branch (114:9): [True: 4, False: 5]
  ------------------
  115|      4|        return Ref<T>(mObjs, it->second);
  116|      4|    }
  117|       |
  118|       |    // read it from the JSON object
  119|      5|    if (!mDict) {
  ------------------
  |  Branch (119:9): [True: 0, False: 5]
  ------------------
  120|      0|        throw DeadlyImportError("GLTF: Missing section \"", mDictId, "\"");
  121|      0|    }
  122|       |
  123|      5|    Value::MemberIterator obj = mDict->FindMember(id);
  124|      5|    if (obj == mDict->MemberEnd()) {
  ------------------
  |  Branch (124:9): [True: 0, False: 5]
  ------------------
  125|      0|        throw DeadlyImportError("GLTF: Missing object with id \"", id, "\" in \"", mDictId, "\"");
  126|      0|    }
  127|      5|    if (!obj->value.IsObject()) {
  ------------------
  |  Branch (127:9): [True: 0, False: 5]
  ------------------
  128|      0|        throw DeadlyImportError("GLTF: Object with id \"", id, "\" is not a JSON object");
  129|      0|    }
  130|       |
  131|       |    // create an instance of the given type
  132|      5|    T *inst = new T();
  133|      5|    inst->id = id;
  134|      5|    ReadMember(obj->value, "name", inst->name);
  135|      5|    inst->Read(obj->value, mAsset);
  136|      5|    return Add(inst);
  137|      5|}
_ZN4glTF10BufferView4ReadERN9rapidjson12GenericValueINS1_4UTF8IcEENS1_19MemoryPoolAllocatorINS1_12CrtAllocatorEEEEERNS_5AssetE:
  344|      5|inline void BufferView::Read(Value &obj, Asset &r) {
  345|      5|    const char *bufferId = MemberOrDefault<const char *>(obj, "buffer", 0);
  346|      5|    if (bufferId) {
  ------------------
  |  Branch (346:9): [True: 5, False: 0]
  ------------------
  347|      5|        buffer = r.buffers.Get(bufferId);
  348|      5|    }
  349|       |
  350|      5|    byteOffset = MemberOrDefault(obj, "byteOffset", 0u);
  351|      5|    byteLength = MemberOrDefault(obj, "byteLength", 0u);
  352|      5|}
_ZN4glTF8LazyDictINS_6BufferEE3GetEPKc:
  110|      5|Ref<T> LazyDict<T>::Get(const char *id) {
  111|      5|    id = T::TranslateId(mAsset, id);
  112|       |
  113|      5|    typename Dict::iterator it = mObjsById.find(id);
  114|      5|    if (it != mObjsById.end()) { // already created?
  ------------------
  |  Branch (114:9): [True: 2, False: 3]
  ------------------
  115|      2|        return Ref<T>(mObjs, it->second);
  116|      2|    }
  117|       |
  118|       |    // read it from the JSON object
  119|      3|    if (!mDict) {
  ------------------
  |  Branch (119:9): [True: 0, False: 3]
  ------------------
  120|      0|        throw DeadlyImportError("GLTF: Missing section \"", mDictId, "\"");
  121|      0|    }
  122|       |
  123|      3|    Value::MemberIterator obj = mDict->FindMember(id);
  124|      3|    if (obj == mDict->MemberEnd()) {
  ------------------
  |  Branch (124:9): [True: 0, False: 3]
  ------------------
  125|      0|        throw DeadlyImportError("GLTF: Missing object with id \"", id, "\" in \"", mDictId, "\"");
  126|      0|    }
  127|      3|    if (!obj->value.IsObject()) {
  ------------------
  |  Branch (127:9): [True: 0, False: 3]
  ------------------
  128|      0|        throw DeadlyImportError("GLTF: Object with id \"", id, "\" is not a JSON object");
  129|      0|    }
  130|       |
  131|       |    // create an instance of the given type
  132|      3|    T *inst = new T();
  133|      3|    inst->id = id;
  134|      3|    ReadMember(obj->value, "name", inst->name);
  135|      3|    inst->Read(obj->value, mAsset);
  136|      3|    return Add(inst);
  137|      3|}
_ZN4glTF6Buffer11TranslateIdERNS_5AssetEPKc:
  171|      5|inline const char *Buffer::TranslateId(Asset &r, const char *id) {
  172|       |    // Compatibility with old spec
  173|      5|    if (r.extensionsUsed.KHR_binary_glTF && strcmp(id, "KHR_binary_glTF") == 0) {
  ------------------
  |  Branch (173:9): [True: 0, False: 5]
  |  Branch (173:45): [True: 0, False: 0]
  ------------------
  174|      0|        return "binary_glTF";
  175|      0|    }
  176|       |
  177|      5|    return id;
  178|      5|}
_ZN4glTF6Buffer4ReadERN9rapidjson12GenericValueINS1_4UTF8IcEENS1_19MemoryPoolAllocatorINS1_12CrtAllocatorEEEEERNS_5AssetE:
  180|      3|inline void Buffer::Read(Value &obj, Asset &r) {
  181|      3|    size_t statedLength = MemberOrDefault<size_t>(obj, "byteLength", 0);
  182|      3|    byteLength = statedLength;
  183|       |
  184|      3|    Value *it = FindString(obj, "uri");
  185|      3|    if (!it) {
  ------------------
  |  Branch (185:9): [True: 0, False: 3]
  ------------------
  186|      0|        if (statedLength > 0) {
  ------------------
  |  Branch (186:13): [True: 0, False: 0]
  ------------------
  187|      0|            throw DeadlyImportError("GLTF: buffer with non-zero length missing the \"uri\" attribute");
  188|      0|        }
  189|      0|        return;
  190|      0|    }
  191|       |
  192|      3|    const char *uri = it->GetString();
  193|       |
  194|      3|    glTFCommon::Util::DataURI dataURI;
  195|      3|    if (ParseDataURI(uri, it->GetStringLength(), dataURI)) {
  ------------------
  |  Branch (195:9): [True: 2, False: 1]
  ------------------
  196|      2|        if (dataURI.base64) {
  ------------------
  |  Branch (196:13): [True: 2, False: 0]
  ------------------
  197|      2|            uint8_t *data = nullptr;
  198|      2|            this->byteLength = Base64::Decode(dataURI.data, dataURI.dataLength, data);
  199|      2|            this->mData.reset(data, std::default_delete<uint8_t[]>());
  200|       |
  201|      2|            if (statedLength > 0 && this->byteLength != statedLength) {
  ------------------
  |  Branch (201:17): [True: 2, False: 0]
  |  Branch (201:37): [True: 0, False: 2]
  ------------------
  202|      0|                throw DeadlyImportError("GLTF: buffer \"", id, "\", expected ", ai_to_string(statedLength),
  203|      0|                        " bytes, but found ", ai_to_string(dataURI.dataLength));
  204|      0|            }
  205|      2|        } else { // assume raw data
  206|      0|            if (statedLength != dataURI.dataLength) {
  ------------------
  |  Branch (206:17): [True: 0, False: 0]
  ------------------
  207|      0|                throw DeadlyImportError("GLTF: buffer \"", id, "\", expected ", ai_to_string(statedLength),
  208|      0|                        " bytes, but found ", ai_to_string(dataURI.dataLength));
  209|      0|            }
  210|       |
  211|      0|            this->mData.reset(new uint8_t[dataURI.dataLength], std::default_delete<uint8_t[]>());
  212|      0|            memcpy(this->mData.get(), dataURI.data, dataURI.dataLength);
  213|      0|        }
  214|      2|    } else { // Local file
  215|      1|        if (byteLength > 0) {
  ------------------
  |  Branch (215:13): [True: 1, False: 0]
  ------------------
  216|      1|            std::string dir = !r.mCurrentAssetDir.empty() ? (
  ------------------
  |  Branch (216:31): [True: 0, False: 1]
  ------------------
  217|      0|                                                                    r.mCurrentAssetDir.back() == '/' ?
  ------------------
  |  Branch (217:69): [True: 0, False: 0]
  ------------------
  218|      0|                                                                            r.mCurrentAssetDir :
  219|      0|                                                                            r.mCurrentAssetDir + '/') :
  220|      1|                                                            "";
  221|       |
  222|      1|            IOStream *file = r.OpenFile(dir + uri, "rb");
  223|      1|            if (file) {
  ------------------
  |  Branch (223:17): [True: 0, False: 1]
  ------------------
  224|      0|                bool ok = LoadFromStream(*file, byteLength);
  225|      0|                delete file;
  226|       |
  227|      0|                if (!ok)
  ------------------
  |  Branch (227:21): [True: 0, False: 0]
  ------------------
  228|      0|                    throw DeadlyImportError("GLTF: error while reading referenced file \"", uri, "\"");
  229|      1|            } else {
  230|      1|                throw DeadlyImportError("GLTF: could not open referenced file \"", uri, "\"");
  231|      1|            }
  232|      1|        }
  233|      1|    }
  234|      3|}
_ZN4glTF6Buffer14LoadFromStreamERN6Assimp8IOStreamEmm:
  236|      1|inline bool Buffer::LoadFromStream(IOStream &stream, size_t length, size_t baseOffset) {
  237|      1|    byteLength = length ? length : stream.FileSize();
  ------------------
  |  Branch (237:18): [True: 1, False: 0]
  ------------------
  238|       |
  239|      1|    if (baseOffset) {
  ------------------
  |  Branch (239:9): [True: 1, False: 0]
  ------------------
  240|      1|        stream.Seek(baseOffset, aiOrigin_SET);
  241|      1|    }
  242|       |
  243|      1|    mData.reset(new uint8_t[byteLength], std::default_delete<uint8_t[]>());
  244|       |
  245|      1|    if (stream.Read(mData.get(), byteLength, 1) != 1) {
  ------------------
  |  Branch (245:9): [True: 1, False: 0]
  ------------------
  246|      1|        return false;
  247|      1|    }
  248|      0|    return true;
  249|      1|}
_ZN4glTF8LazyDictINS_8MaterialEE3GetEPKc:
  110|      2|Ref<T> LazyDict<T>::Get(const char *id) {
  111|      2|    id = T::TranslateId(mAsset, id);
  112|       |
  113|      2|    typename Dict::iterator it = mObjsById.find(id);
  114|      2|    if (it != mObjsById.end()) { // already created?
  ------------------
  |  Branch (114:9): [True: 0, False: 2]
  ------------------
  115|      0|        return Ref<T>(mObjs, it->second);
  116|      0|    }
  117|       |
  118|       |    // read it from the JSON object
  119|      2|    if (!mDict) {
  ------------------
  |  Branch (119:9): [True: 0, False: 2]
  ------------------
  120|      0|        throw DeadlyImportError("GLTF: Missing section \"", mDictId, "\"");
  121|      0|    }
  122|       |
  123|      2|    Value::MemberIterator obj = mDict->FindMember(id);
  124|      2|    if (obj == mDict->MemberEnd()) {
  ------------------
  |  Branch (124:9): [True: 0, False: 2]
  ------------------
  125|      0|        throw DeadlyImportError("GLTF: Missing object with id \"", id, "\" in \"", mDictId, "\"");
  126|      0|    }
  127|      2|    if (!obj->value.IsObject()) {
  ------------------
  |  Branch (127:9): [True: 0, False: 2]
  ------------------
  128|      0|        throw DeadlyImportError("GLTF: Object with id \"", id, "\" is not a JSON object");
  129|      0|    }
  130|       |
  131|       |    // create an instance of the given type
  132|      2|    T *inst = new T();
  133|      2|    inst->id = id;
  134|      2|    ReadMember(obj->value, "name", inst->name);
  135|      2|    inst->Read(obj->value, mAsset);
  136|      2|    return Add(inst);
  137|      2|}
_ZN4glTF8Material11SetDefaultsEv:
  640|      4|inline void Material::SetDefaults() {
  641|      4|    SetVector(ambient.color, 0, 0, 0, 1);
  642|      4|    SetVector(diffuse.color, 0, 0, 0, 1);
  643|      4|    SetVector(specular.color, 0, 0, 0, 1);
  644|      4|    SetVector(emission.color, 0, 0, 0, 1);
  645|       |
  646|      4|    doubleSided = false;
  647|      4|    transparent = false;
  648|      4|    transparency = 1.0;
  649|      4|    shininess = 0.0;
  650|       |
  651|      4|    technique = Technique_undefined;
  652|      4|}
glTFExporter.cpp:_ZN4glTF12_GLOBAL__N_19SetVectorERA4_fffff:
  632|     16|void SetVector(vec4 &v, float x, float y, float z, float w) {
  633|     16|    v[0] = x;
  634|     16|    v[1] = y;
  635|     16|    v[2] = z;
  636|     16|    v[3] = w;
  637|     16|}
_ZN4glTF8Material4ReadERN9rapidjson12GenericValueINS1_4UTF8IcEENS1_19MemoryPoolAllocatorINS1_12CrtAllocatorEEEEERNS_5AssetE:
  589|      2|inline void Material::Read(Value &material, Asset &r) {
  590|      2|    SetDefaults();
  591|       |
  592|      2|    if (Value *values = FindObject(material, "values")) {
  ------------------
  |  Branch (592:16): [True: 2, False: 0]
  ------------------
  593|      2|        ReadMaterialProperty(r, *values, "ambient", this->ambient);
  594|      2|        ReadMaterialProperty(r, *values, "diffuse", this->diffuse);
  595|      2|        ReadMaterialProperty(r, *values, "specular", this->specular);
  596|       |
  597|      2|        ReadMember(*values, "transparency", transparency);
  598|      2|        ReadMember(*values, "shininess", shininess);
  599|      2|    }
  600|       |
  601|      2|    if (Value *extensions = FindObject(material, "extensions")) {
  ------------------
  |  Branch (601:16): [True: 0, False: 2]
  ------------------
  602|      0|        if (r.extensionsUsed.KHR_materials_common) {
  ------------------
  |  Branch (602:13): [True: 0, False: 0]
  ------------------
  603|      0|            if (Value *ext = FindObject(*extensions, "KHR_materials_common")) {
  ------------------
  |  Branch (603:24): [True: 0, False: 0]
  ------------------
  604|      0|                if (Value *tnq = FindString(*ext, "technique")) {
  ------------------
  |  Branch (604:28): [True: 0, False: 0]
  ------------------
  605|      0|                    const char *t = tnq->GetString();
  606|      0|                    if (strcmp(t, "BLINN") == 0)
  ------------------
  |  Branch (606:25): [True: 0, False: 0]
  ------------------
  607|      0|                        technique = Technique_BLINN;
  608|      0|                    else if (strcmp(t, "PHONG") == 0)
  ------------------
  |  Branch (608:30): [True: 0, False: 0]
  ------------------
  609|      0|                        technique = Technique_PHONG;
  610|      0|                    else if (strcmp(t, "LAMBERT") == 0)
  ------------------
  |  Branch (610:30): [True: 0, False: 0]
  ------------------
  611|      0|                        technique = Technique_LAMBERT;
  612|      0|                    else if (strcmp(t, "CONSTANT") == 0)
  ------------------
  |  Branch (612:30): [True: 0, False: 0]
  ------------------
  613|      0|                        technique = Technique_CONSTANT;
  614|      0|                }
  615|       |
  616|      0|                if (Value *values = FindObject(*ext, "values")) {
  ------------------
  |  Branch (616:28): [True: 0, False: 0]
  ------------------
  617|      0|                    ReadMaterialProperty(r, *values, "ambient", this->ambient);
  618|      0|                    ReadMaterialProperty(r, *values, "diffuse", this->diffuse);
  619|      0|                    ReadMaterialProperty(r, *values, "specular", this->specular);
  620|       |
  621|      0|                    ReadMember(*values, "doubleSided", doubleSided);
  622|      0|                    ReadMember(*values, "transparent", transparent);
  623|      0|                    ReadMember(*values, "transparency", transparency);
  624|      0|                    ReadMember(*values, "shininess", shininess);
  625|      0|                }
  626|      0|            }
  627|      0|        }
  628|      0|    }
  629|      2|}
glTFExporter.cpp:_ZN4glTF12_GLOBAL__N_120ReadMaterialPropertyERNS_5AssetERN9rapidjson12GenericValueINS3_4UTF8IcEENS3_19MemoryPoolAllocatorINS3_12CrtAllocatorEEEEEPKcRNS_11TexPropertyE:
  578|      6|inline void ReadMaterialProperty(Asset &r, Value &vals, const char *propName, TexProperty &out) {
  579|      6|    if (Value *prop = FindMember(vals, propName)) {
  ------------------
  |  Branch (579:16): [True: 4, False: 2]
  ------------------
  580|      4|        if (prop->IsString()) {
  ------------------
  |  Branch (580:13): [True: 2, False: 2]
  ------------------
  581|      2|            out.texture = r.textures.Get(prop->GetString());
  582|      2|        } else {
  583|      2|            ReadValue(*prop, out.color);
  584|      2|        }
  585|      4|    }
  586|      6|}
_ZN4glTF8LazyDictINS_7TextureEE3GetEPKc:
  110|      2|Ref<T> LazyDict<T>::Get(const char *id) {
  111|      2|    id = T::TranslateId(mAsset, id);
  112|       |
  113|      2|    typename Dict::iterator it = mObjsById.find(id);
  114|      2|    if (it != mObjsById.end()) { // already created?
  ------------------
  |  Branch (114:9): [True: 0, False: 2]
  ------------------
  115|      0|        return Ref<T>(mObjs, it->second);
  116|      0|    }
  117|       |
  118|       |    // read it from the JSON object
  119|      2|    if (!mDict) {
  ------------------
  |  Branch (119:9): [True: 0, False: 2]
  ------------------
  120|      0|        throw DeadlyImportError("GLTF: Missing section \"", mDictId, "\"");
  121|      0|    }
  122|       |
  123|      2|    Value::MemberIterator obj = mDict->FindMember(id);
  124|      2|    if (obj == mDict->MemberEnd()) {
  ------------------
  |  Branch (124:9): [True: 0, False: 2]
  ------------------
  125|      0|        throw DeadlyImportError("GLTF: Missing object with id \"", id, "\" in \"", mDictId, "\"");
  126|      0|    }
  127|      2|    if (!obj->value.IsObject()) {
  ------------------
  |  Branch (127:9): [True: 0, False: 2]
  ------------------
  128|      0|        throw DeadlyImportError("GLTF: Object with id \"", id, "\" is not a JSON object");
  129|      0|    }
  130|       |
  131|       |    // create an instance of the given type
  132|      2|    T *inst = new T();
  133|      2|    inst->id = id;
  134|      2|    ReadMember(obj->value, "name", inst->name);
  135|      2|    inst->Read(obj->value, mAsset);
  136|      2|    return Add(inst);
  137|      2|}
_ZN4glTF7Texture4ReadERN9rapidjson12GenericValueINS1_4UTF8IcEENS1_19MemoryPoolAllocatorINS1_12CrtAllocatorEEEEERNS_5AssetE:
  565|      2|inline void Texture::Read(Value &obj, Asset &r) {
  566|      2|    const char *sourcestr;
  567|      2|    if (ReadMember(obj, "source", sourcestr)) {
  ------------------
  |  Branch (567:9): [True: 2, False: 0]
  ------------------
  568|      2|        source = r.images.Get(sourcestr);
  569|      2|    }
  570|       |
  571|      2|    const char *samplerstr;
  572|      2|    if (ReadMember(obj, "sampler", samplerstr)) {
  ------------------
  |  Branch (572:9): [True: 2, False: 0]
  ------------------
  573|      2|        sampler = r.samplers.Get(samplerstr);
  574|      2|    }
  575|      2|}
_ZN4glTF8LazyDictINS_5ImageEE3GetEPKc:
  110|      2|Ref<T> LazyDict<T>::Get(const char *id) {
  111|      2|    id = T::TranslateId(mAsset, id);
  112|       |
  113|      2|    typename Dict::iterator it = mObjsById.find(id);
  114|      2|    if (it != mObjsById.end()) { // already created?
  ------------------
  |  Branch (114:9): [True: 0, False: 2]
  ------------------
  115|      0|        return Ref<T>(mObjs, it->second);
  116|      0|    }
  117|       |
  118|       |    // read it from the JSON object
  119|      2|    if (!mDict) {
  ------------------
  |  Branch (119:9): [True: 0, False: 2]
  ------------------
  120|      0|        throw DeadlyImportError("GLTF: Missing section \"", mDictId, "\"");
  121|      0|    }
  122|       |
  123|      2|    Value::MemberIterator obj = mDict->FindMember(id);
  124|      2|    if (obj == mDict->MemberEnd()) {
  ------------------
  |  Branch (124:9): [True: 0, False: 2]
  ------------------
  125|      0|        throw DeadlyImportError("GLTF: Missing object with id \"", id, "\" in \"", mDictId, "\"");
  126|      0|    }
  127|      2|    if (!obj->value.IsObject()) {
  ------------------
  |  Branch (127:9): [True: 0, False: 2]
  ------------------
  128|      0|        throw DeadlyImportError("GLTF: Object with id \"", id, "\" is not a JSON object");
  129|      0|    }
  130|       |
  131|       |    // create an instance of the given type
  132|      2|    T *inst = new T();
  133|      2|    inst->id = id;
  134|      2|    ReadMember(obj->value, "name", inst->name);
  135|      2|    inst->Read(obj->value, mAsset);
  136|      2|    return Add(inst);
  137|      2|}
_ZN4glTF5ImageC2Ev:
  480|      2|        width(0), height(0), mDataLength(0) {
  481|      2|}
_ZN4glTF5Image4ReadERN9rapidjson12GenericValueINS1_4UTF8IcEENS1_19MemoryPoolAllocatorINS1_12CrtAllocatorEEEEERNS_5AssetE:
  483|      2|inline void Image::Read(Value &obj, Asset &r) {
  484|       |    // Check for extensions first (to detect binary embedded data)
  485|      2|    if (Value *extensions = FindObject(obj, "extensions")) {
  ------------------
  |  Branch (485:16): [True: 0, False: 2]
  ------------------
  486|      0|        if (r.extensionsUsed.KHR_binary_glTF) {
  ------------------
  |  Branch (486:13): [True: 0, False: 0]
  ------------------
  487|      0|            if (Value *ext = FindObject(*extensions, "KHR_binary_glTF")) {
  ------------------
  |  Branch (487:24): [True: 0, False: 0]
  ------------------
  488|       |
  489|      0|                width = MemberOrDefault(*ext, "width", 0);
  490|      0|                height = MemberOrDefault(*ext, "height", 0);
  491|       |
  492|      0|                ReadMember(*ext, "mimeType", mimeType);
  493|       |
  494|      0|                const char *bufferViewId;
  495|      0|                if (ReadMember(*ext, "bufferView", bufferViewId)) {
  ------------------
  |  Branch (495:21): [True: 0, False: 0]
  ------------------
  496|      0|                    Ref<BufferView> bv = r.bufferViews.Get(bufferViewId);
  497|      0|                    if (bv) {
  ------------------
  |  Branch (497:25): [True: 0, False: 0]
  ------------------
  498|      0|                        mDataLength = bv->byteLength;
  499|      0|                        mData.reset(new uint8_t[mDataLength]);
  500|      0|                        memcpy(mData.get(), bv->buffer->GetPointer() + bv->byteOffset, mDataLength);
  501|      0|                    }
  502|      0|                }
  503|      0|            }
  504|      0|        }
  505|      0|    }
  506|       |
  507|      2|    if (!mDataLength) {
  ------------------
  |  Branch (507:9): [True: 2, False: 0]
  ------------------
  508|      2|        Value *curUri = FindString(obj, "uri");
  509|      2|        if (nullptr != curUri) {
  ------------------
  |  Branch (509:13): [True: 2, False: 0]
  ------------------
  510|      2|            const char *uristr = curUri->GetString();
  511|       |
  512|      2|            glTFCommon::Util::DataURI dataURI;
  513|      2|            if (ParseDataURI(uristr, curUri->GetStringLength(), dataURI)) {
  ------------------
  |  Branch (513:17): [True: 2, False: 0]
  ------------------
  514|      2|                mimeType = dataURI.mediaType;
  515|      2|                if (dataURI.base64) {
  ------------------
  |  Branch (515:21): [True: 2, False: 0]
  ------------------
  516|      2|                    uint8_t *ptr = nullptr;
  517|      2|                    mDataLength = Base64::Decode(dataURI.data, dataURI.dataLength, ptr);
  518|      2|                    mData.reset(ptr);
  519|      2|                }
  520|      2|            } else {
  521|      0|                this->uri = uristr;
  522|      0|            }
  523|      2|        }
  524|      2|    }
  525|      2|}
_ZN4glTF8LazyDictINS_5ImageEE3AddEPS1_:
  140|      2|Ref<T> LazyDict<T>::Add(T *obj) {
  141|      2|    unsigned int idx = unsigned(mObjs.size());
  142|      2|    mObjs.push_back(obj);
  143|      2|    mObjsById[obj->id] = idx;
  144|      2|    mAsset.mUsedIds[obj->id] = true;
  145|      2|    return Ref<T>(mObjs, idx);
  146|      2|}
_ZN4glTF8LazyDictINS_7SamplerEE3GetEPKc:
  110|      2|Ref<T> LazyDict<T>::Get(const char *id) {
  111|      2|    id = T::TranslateId(mAsset, id);
  112|       |
  113|      2|    typename Dict::iterator it = mObjsById.find(id);
  114|      2|    if (it != mObjsById.end()) { // already created?
  ------------------
  |  Branch (114:9): [True: 0, False: 2]
  ------------------
  115|      0|        return Ref<T>(mObjs, it->second);
  116|      0|    }
  117|       |
  118|       |    // read it from the JSON object
  119|      2|    if (!mDict) {
  ------------------
  |  Branch (119:9): [True: 0, False: 2]
  ------------------
  120|      0|        throw DeadlyImportError("GLTF: Missing section \"", mDictId, "\"");
  121|      0|    }
  122|       |
  123|      2|    Value::MemberIterator obj = mDict->FindMember(id);
  124|      2|    if (obj == mDict->MemberEnd()) {
  ------------------
  |  Branch (124:9): [True: 0, False: 2]
  ------------------
  125|      0|        throw DeadlyImportError("GLTF: Missing object with id \"", id, "\" in \"", mDictId, "\"");
  126|      0|    }
  127|      2|    if (!obj->value.IsObject()) {
  ------------------
  |  Branch (127:9): [True: 0, False: 2]
  ------------------
  128|      0|        throw DeadlyImportError("GLTF: Object with id \"", id, "\" is not a JSON object");
  129|      0|    }
  130|       |
  131|       |    // create an instance of the given type
  132|      2|    T *inst = new T();
  133|      2|    inst->id = id;
  134|      2|    ReadMember(obj->value, "name", inst->name);
  135|      2|    inst->Read(obj->value, mAsset);
  136|      2|    return Add(inst);
  137|      2|}
_ZN4glTF7Sampler4ReadERN9rapidjson12GenericValueINS1_4UTF8IcEENS1_19MemoryPoolAllocatorINS1_12CrtAllocatorEEEEERNS_5AssetE:
  549|      2|inline void Sampler::Read(Value &obj, Asset & /*r*/) {
  550|      2|    SetDefaults();
  551|       |
  552|      2|    ReadMember(obj, "magFilter", magFilter);
  553|      2|    ReadMember(obj, "minFilter", minFilter);
  554|      2|    ReadMember(obj, "wrapS", wrapS);
  555|      2|    ReadMember(obj, "wrapT", wrapT);
  556|      2|}
_ZN4glTF7Sampler11SetDefaultsEv:
  558|      2|inline void Sampler::SetDefaults() {
  559|      2|    magFilter = SamplerMagFilter_Linear;
  560|      2|    minFilter = SamplerMinFilter_Linear;
  561|      2|    wrapS = SamplerWrap_Repeat;
  562|      2|    wrapT = SamplerWrap_Repeat;
  563|      2|}
_ZN4glTF8LazyDictINS_7SamplerEE3AddEPS1_:
  140|      2|Ref<T> LazyDict<T>::Add(T *obj) {
  141|      2|    unsigned int idx = unsigned(mObjs.size());
  142|      2|    mObjs.push_back(obj);
  143|      2|    mObjsById[obj->id] = idx;
  144|      2|    mAsset.mUsedIds[obj->id] = true;
  145|      2|    return Ref<T>(mObjs, idx);
  146|      2|}
_ZN4glTF8LazyDictINS_7TextureEE3AddEPS1_:
  140|      2|Ref<T> LazyDict<T>::Add(T *obj) {
  141|      2|    unsigned int idx = unsigned(mObjs.size());
  142|      2|    mObjs.push_back(obj);
  143|      2|    mObjsById[obj->id] = idx;
  144|      2|    mAsset.mUsedIds[obj->id] = true;
  145|      2|    return Ref<T>(mObjs, idx);
  146|      2|}
_ZN4glTF8LazyDictINS_8MaterialEE3AddEPS1_:
  140|      2|Ref<T> LazyDict<T>::Add(T *obj) {
  141|      2|    unsigned int idx = unsigned(mObjs.size());
  142|      2|    mObjs.push_back(obj);
  143|      2|    mObjsById[obj->id] = idx;
  144|      2|    mAsset.mUsedIds[obj->id] = true;
  145|      2|    return Ref<T>(mObjs, idx);
  146|      2|}
_ZN4glTF8LazyDictINS_4MeshEE3AddEPS1_:
  140|      2|Ref<T> LazyDict<T>::Add(T *obj) {
  141|      2|    unsigned int idx = unsigned(mObjs.size());
  142|      2|    mObjs.push_back(obj);
  143|      2|    mObjsById[obj->id] = idx;
  144|      2|    mAsset.mUsedIds[obj->id] = true;
  145|      2|    return Ref<T>(mObjs, idx);
  146|      2|}
_ZN4glTF8LazyDictINS_4NodeEE3AddEPS1_:
  140|      9|Ref<T> LazyDict<T>::Add(T *obj) {
  141|      9|    unsigned int idx = unsigned(mObjs.size());
  142|      9|    mObjs.push_back(obj);
  143|      9|    mObjsById[obj->id] = idx;
  144|      9|    mAsset.mUsedIds[obj->id] = true;
  145|      9|    return Ref<T>(mObjs, idx);
  146|      9|}
_ZN4glTF8LazyDictINS_8AccessorEEC2ERNS_5AssetEPKcS6_:
   71|     50|        mDictId(dictId), mExtId(extId), mDict(nullptr), mAsset(asset) {
   72|     50|    asset.mDicts.push_back(this); // register to the list of dictionaries
   73|     50|}
_ZN4glTF8LazyDictINS_8AccessorEE16AttachToDocumentERN9rapidjson15GenericDocumentINS3_4UTF8IcEENS3_19MemoryPoolAllocatorINS3_12CrtAllocatorEEES8_EE:
   83|      3|inline void LazyDict<T>::AttachToDocument(Document &doc) {
   84|      3|    Value *container = nullptr;
   85|       |
   86|      3|    if (mExtId) {
  ------------------
  |  Branch (86:9): [True: 0, False: 3]
  ------------------
   87|      0|        if (Value *exts = FindObject(doc, "extensions")) {
  ------------------
  |  Branch (87:20): [True: 0, False: 0]
  ------------------
   88|      0|            container = FindObject(*exts, mExtId);
   89|      0|        }
   90|      3|    } else {
   91|      3|        container = &doc;
   92|      3|    }
   93|       |
   94|      3|    if (container) {
  ------------------
  |  Branch (94:9): [True: 3, False: 0]
  ------------------
   95|      3|        mDict = FindObject(*container, mDictId);
   96|      3|    }
   97|      3|}
_ZN4glTF8LazyDictINS_8AccessorEE18DetachFromDocumentEv:
  100|      2|inline void LazyDict<T>::DetachFromDocument() {
  101|      2|    mDict = nullptr;
  102|      2|}
_ZN4glTF8LazyDictINS_9AnimationEEC2ERNS_5AssetEPKcS6_:
   71|     50|        mDictId(dictId), mExtId(extId), mDict(nullptr), mAsset(asset) {
   72|     50|    asset.mDicts.push_back(this); // register to the list of dictionaries
   73|     50|}
_ZN4glTF8LazyDictINS_9AnimationEE16AttachToDocumentERN9rapidjson15GenericDocumentINS3_4UTF8IcEENS3_19MemoryPoolAllocatorINS3_12CrtAllocatorEEES8_EE:
   83|      3|inline void LazyDict<T>::AttachToDocument(Document &doc) {
   84|      3|    Value *container = nullptr;
   85|       |
   86|      3|    if (mExtId) {
  ------------------
  |  Branch (86:9): [True: 0, False: 3]
  ------------------
   87|      0|        if (Value *exts = FindObject(doc, "extensions")) {
  ------------------
  |  Branch (87:20): [True: 0, False: 0]
  ------------------
   88|      0|            container = FindObject(*exts, mExtId);
   89|      0|        }
   90|      3|    } else {
   91|      3|        container = &doc;
   92|      3|    }
   93|       |
   94|      3|    if (container) {
  ------------------
  |  Branch (94:9): [True: 3, False: 0]
  ------------------
   95|      3|        mDict = FindObject(*container, mDictId);
   96|      3|    }
   97|      3|}
_ZN4glTF8LazyDictINS_9AnimationEE18DetachFromDocumentEv:
  100|      2|inline void LazyDict<T>::DetachFromDocument() {
  101|      2|    mDict = nullptr;
  102|      2|}
_ZN4glTF8LazyDictINS_6BufferEEC2ERNS_5AssetEPKcS6_:
   71|     50|        mDictId(dictId), mExtId(extId), mDict(nullptr), mAsset(asset) {
   72|     50|    asset.mDicts.push_back(this); // register to the list of dictionaries
   73|     50|}
_ZN4glTF8LazyDictINS_6BufferEE16AttachToDocumentERN9rapidjson15GenericDocumentINS3_4UTF8IcEENS3_19MemoryPoolAllocatorINS3_12CrtAllocatorEEES8_EE:
   83|      3|inline void LazyDict<T>::AttachToDocument(Document &doc) {
   84|      3|    Value *container = nullptr;
   85|       |
   86|      3|    if (mExtId) {
  ------------------
  |  Branch (86:9): [True: 0, False: 3]
  ------------------
   87|      0|        if (Value *exts = FindObject(doc, "extensions")) {
  ------------------
  |  Branch (87:20): [True: 0, False: 0]
  ------------------
   88|      0|            container = FindObject(*exts, mExtId);
   89|      0|        }
   90|      3|    } else {
   91|      3|        container = &doc;
   92|      3|    }
   93|       |
   94|      3|    if (container) {
  ------------------
  |  Branch (94:9): [True: 3, False: 0]
  ------------------
   95|      3|        mDict = FindObject(*container, mDictId);
   96|      3|    }
   97|      3|}
_ZN4glTF8LazyDictINS_6BufferEE18DetachFromDocumentEv:
  100|      2|inline void LazyDict<T>::DetachFromDocument() {
  101|      2|    mDict = nullptr;
  102|      2|}
_ZN4glTF8LazyDictINS_10BufferViewEEC2ERNS_5AssetEPKcS6_:
   71|     50|        mDictId(dictId), mExtId(extId), mDict(nullptr), mAsset(asset) {
   72|     50|    asset.mDicts.push_back(this); // register to the list of dictionaries
   73|     50|}
_ZN4glTF8LazyDictINS_10BufferViewEE16AttachToDocumentERN9rapidjson15GenericDocumentINS3_4UTF8IcEENS3_19MemoryPoolAllocatorINS3_12CrtAllocatorEEES8_EE:
   83|      3|inline void LazyDict<T>::AttachToDocument(Document &doc) {
   84|      3|    Value *container = nullptr;
   85|       |
   86|      3|    if (mExtId) {
  ------------------
  |  Branch (86:9): [True: 0, False: 3]
  ------------------
   87|      0|        if (Value *exts = FindObject(doc, "extensions")) {
  ------------------
  |  Branch (87:20): [True: 0, False: 0]
  ------------------
   88|      0|            container = FindObject(*exts, mExtId);
   89|      0|        }
   90|      3|    } else {
   91|      3|        container = &doc;
   92|      3|    }
   93|       |
   94|      3|    if (container) {
  ------------------
  |  Branch (94:9): [True: 3, False: 0]
  ------------------
   95|      3|        mDict = FindObject(*container, mDictId);
   96|      3|    }
   97|      3|}
_ZN4glTF8LazyDictINS_10BufferViewEE18DetachFromDocumentEv:
  100|      2|inline void LazyDict<T>::DetachFromDocument() {
  101|      2|    mDict = nullptr;
  102|      2|}
_ZN4glTF8LazyDictINS_6CameraEEC2ERNS_5AssetEPKcS6_:
   71|     50|        mDictId(dictId), mExtId(extId), mDict(nullptr), mAsset(asset) {
   72|     50|    asset.mDicts.push_back(this); // register to the list of dictionaries
   73|     50|}
_ZN4glTF8LazyDictINS_6CameraEE16AttachToDocumentERN9rapidjson15GenericDocumentINS3_4UTF8IcEENS3_19MemoryPoolAllocatorINS3_12CrtAllocatorEEES8_EE:
   83|      3|inline void LazyDict<T>::AttachToDocument(Document &doc) {
   84|      3|    Value *container = nullptr;
   85|       |
   86|      3|    if (mExtId) {
  ------------------
  |  Branch (86:9): [True: 0, False: 3]
  ------------------
   87|      0|        if (Value *exts = FindObject(doc, "extensions")) {
  ------------------
  |  Branch (87:20): [True: 0, False: 0]
  ------------------
   88|      0|            container = FindObject(*exts, mExtId);
   89|      0|        }
   90|      3|    } else {
   91|      3|        container = &doc;
   92|      3|    }
   93|       |
   94|      3|    if (container) {
  ------------------
  |  Branch (94:9): [True: 3, False: 0]
  ------------------
   95|      3|        mDict = FindObject(*container, mDictId);
   96|      3|    }
   97|      3|}
_ZN4glTF8LazyDictINS_6CameraEE18DetachFromDocumentEv:
  100|      2|inline void LazyDict<T>::DetachFromDocument() {
  101|      2|    mDict = nullptr;
  102|      2|}
_ZN4glTF8LazyDictINS_5ImageEEC2ERNS_5AssetEPKcS6_:
   71|     50|        mDictId(dictId), mExtId(extId), mDict(nullptr), mAsset(asset) {
   72|     50|    asset.mDicts.push_back(this); // register to the list of dictionaries
   73|     50|}
_ZN4glTF8LazyDictINS_5ImageEE16AttachToDocumentERN9rapidjson15GenericDocumentINS3_4UTF8IcEENS3_19MemoryPoolAllocatorINS3_12CrtAllocatorEEES8_EE:
   83|      3|inline void LazyDict<T>::AttachToDocument(Document &doc) {
   84|      3|    Value *container = nullptr;
   85|       |
   86|      3|    if (mExtId) {
  ------------------
  |  Branch (86:9): [True: 0, False: 3]
  ------------------
   87|      0|        if (Value *exts = FindObject(doc, "extensions")) {
  ------------------
  |  Branch (87:20): [True: 0, False: 0]
  ------------------
   88|      0|            container = FindObject(*exts, mExtId);
   89|      0|        }
   90|      3|    } else {
   91|      3|        container = &doc;
   92|      3|    }
   93|       |
   94|      3|    if (container) {
  ------------------
  |  Branch (94:9): [True: 3, False: 0]
  ------------------
   95|      3|        mDict = FindObject(*container, mDictId);
   96|      3|    }
   97|      3|}
_ZN4glTF8LazyDictINS_5ImageEE18DetachFromDocumentEv:
  100|      2|inline void LazyDict<T>::DetachFromDocument() {
  101|      2|    mDict = nullptr;
  102|      2|}
_ZN4glTF8LazyDictINS_8MaterialEEC2ERNS_5AssetEPKcS6_:
   71|     50|        mDictId(dictId), mExtId(extId), mDict(nullptr), mAsset(asset) {
   72|     50|    asset.mDicts.push_back(this); // register to the list of dictionaries
   73|     50|}
_ZN4glTF8LazyDictINS_8MaterialEE16AttachToDocumentERN9rapidjson15GenericDocumentINS3_4UTF8IcEENS3_19MemoryPoolAllocatorINS3_12CrtAllocatorEEES8_EE:
   83|      3|inline void LazyDict<T>::AttachToDocument(Document &doc) {
   84|      3|    Value *container = nullptr;
   85|       |
   86|      3|    if (mExtId) {
  ------------------
  |  Branch (86:9): [True: 0, False: 3]
  ------------------
   87|      0|        if (Value *exts = FindObject(doc, "extensions")) {
  ------------------
  |  Branch (87:20): [True: 0, False: 0]
  ------------------
   88|      0|            container = FindObject(*exts, mExtId);
   89|      0|        }
   90|      3|    } else {
   91|      3|        container = &doc;
   92|      3|    }
   93|       |
   94|      3|    if (container) {
  ------------------
  |  Branch (94:9): [True: 3, False: 0]
  ------------------
   95|      3|        mDict = FindObject(*container, mDictId);
   96|      3|    }
   97|      3|}
_ZN4glTF8LazyDictINS_8MaterialEE18DetachFromDocumentEv:
  100|      2|inline void LazyDict<T>::DetachFromDocument() {
  101|      2|    mDict = nullptr;
  102|      2|}
_ZN4glTF8LazyDictINS_4MeshEEC2ERNS_5AssetEPKcS6_:
   71|     50|        mDictId(dictId), mExtId(extId), mDict(nullptr), mAsset(asset) {
   72|     50|    asset.mDicts.push_back(this); // register to the list of dictionaries
   73|     50|}
_ZN4glTF8LazyDictINS_4MeshEE16AttachToDocumentERN9rapidjson15GenericDocumentINS3_4UTF8IcEENS3_19MemoryPoolAllocatorINS3_12CrtAllocatorEEES8_EE:
   83|      3|inline void LazyDict<T>::AttachToDocument(Document &doc) {
   84|      3|    Value *container = nullptr;
   85|       |
   86|      3|    if (mExtId) {
  ------------------
  |  Branch (86:9): [True: 0, False: 3]
  ------------------
   87|      0|        if (Value *exts = FindObject(doc, "extensions")) {
  ------------------
  |  Branch (87:20): [True: 0, False: 0]
  ------------------
   88|      0|            container = FindObject(*exts, mExtId);
   89|      0|        }
   90|      3|    } else {
   91|      3|        container = &doc;
   92|      3|    }
   93|       |
   94|      3|    if (container) {
  ------------------
  |  Branch (94:9): [True: 3, False: 0]
  ------------------
   95|      3|        mDict = FindObject(*container, mDictId);
   96|      3|    }
   97|      3|}
_ZN4glTF8LazyDictINS_4MeshEE18DetachFromDocumentEv:
  100|      2|inline void LazyDict<T>::DetachFromDocument() {
  101|      2|    mDict = nullptr;
  102|      2|}
_ZN4glTF8LazyDictINS_4NodeEEC2ERNS_5AssetEPKcS6_:
   71|     50|        mDictId(dictId), mExtId(extId), mDict(nullptr), mAsset(asset) {
   72|     50|    asset.mDicts.push_back(this); // register to the list of dictionaries
   73|     50|}
_ZN4glTF8LazyDictINS_4NodeEE16AttachToDocumentERN9rapidjson15GenericDocumentINS3_4UTF8IcEENS3_19MemoryPoolAllocatorINS3_12CrtAllocatorEEES8_EE:
   83|      3|inline void LazyDict<T>::AttachToDocument(Document &doc) {
   84|      3|    Value *container = nullptr;
   85|       |
   86|      3|    if (mExtId) {
  ------------------
  |  Branch (86:9): [True: 0, False: 3]
  ------------------
   87|      0|        if (Value *exts = FindObject(doc, "extensions")) {
  ------------------
  |  Branch (87:20): [True: 0, False: 0]
  ------------------
   88|      0|            container = FindObject(*exts, mExtId);
   89|      0|        }
   90|      3|    } else {
   91|      3|        container = &doc;
   92|      3|    }
   93|       |
   94|      3|    if (container) {
  ------------------
  |  Branch (94:9): [True: 3, False: 0]
  ------------------
   95|      3|        mDict = FindObject(*container, mDictId);
   96|      3|    }
   97|      3|}
_ZN4glTF8LazyDictINS_4NodeEE18DetachFromDocumentEv:
  100|      2|inline void LazyDict<T>::DetachFromDocument() {
  101|      2|    mDict = nullptr;
  102|      2|}
_ZN4glTF8LazyDictINS_7SamplerEEC2ERNS_5AssetEPKcS6_:
   71|     50|        mDictId(dictId), mExtId(extId), mDict(nullptr), mAsset(asset) {
   72|     50|    asset.mDicts.push_back(this); // register to the list of dictionaries
   73|     50|}
_ZN4glTF8LazyDictINS_7SamplerEE16AttachToDocumentERN9rapidjson15GenericDocumentINS3_4UTF8IcEENS3_19MemoryPoolAllocatorINS3_12CrtAllocatorEEES8_EE:
   83|      3|inline void LazyDict<T>::AttachToDocument(Document &doc) {
   84|      3|    Value *container = nullptr;
   85|       |
   86|      3|    if (mExtId) {
  ------------------
  |  Branch (86:9): [True: 0, False: 3]
  ------------------
   87|      0|        if (Value *exts = FindObject(doc, "extensions")) {
  ------------------
  |  Branch (87:20): [True: 0, False: 0]
  ------------------
   88|      0|            container = FindObject(*exts, mExtId);
   89|      0|        }
   90|      3|    } else {
   91|      3|        container = &doc;
   92|      3|    }
   93|       |
   94|      3|    if (container) {
  ------------------
  |  Branch (94:9): [True: 3, False: 0]
  ------------------
   95|      3|        mDict = FindObject(*container, mDictId);
   96|      3|    }
   97|      3|}
_ZN4glTF8LazyDictINS_7SamplerEE18DetachFromDocumentEv:
  100|      2|inline void LazyDict<T>::DetachFromDocument() {
  101|      2|    mDict = nullptr;
  102|      2|}
_ZN4glTF8LazyDictINS_5SceneEEC2ERNS_5AssetEPKcS6_:
   71|     50|        mDictId(dictId), mExtId(extId), mDict(nullptr), mAsset(asset) {
   72|     50|    asset.mDicts.push_back(this); // register to the list of dictionaries
   73|     50|}
_ZN4glTF8LazyDictINS_5SceneEE16AttachToDocumentERN9rapidjson15GenericDocumentINS3_4UTF8IcEENS3_19MemoryPoolAllocatorINS3_12CrtAllocatorEEES8_EE:
   83|      3|inline void LazyDict<T>::AttachToDocument(Document &doc) {
   84|      3|    Value *container = nullptr;
   85|       |
   86|      3|    if (mExtId) {
  ------------------
  |  Branch (86:9): [True: 0, False: 3]
  ------------------
   87|      0|        if (Value *exts = FindObject(doc, "extensions")) {
  ------------------
  |  Branch (87:20): [True: 0, False: 0]
  ------------------
   88|      0|            container = FindObject(*exts, mExtId);
   89|      0|        }
   90|      3|    } else {
   91|      3|        container = &doc;
   92|      3|    }
   93|       |
   94|      3|    if (container) {
  ------------------
  |  Branch (94:9): [True: 3, False: 0]
  ------------------
   95|      3|        mDict = FindObject(*container, mDictId);
   96|      3|    }
   97|      3|}
_ZN4glTF8LazyDictINS_5SceneEE18DetachFromDocumentEv:
  100|      2|inline void LazyDict<T>::DetachFromDocument() {
  101|      2|    mDict = nullptr;
  102|      2|}
_ZN4glTF8LazyDictINS_4SkinEEC2ERNS_5AssetEPKcS6_:
   71|     50|        mDictId(dictId), mExtId(extId), mDict(nullptr), mAsset(asset) {
   72|     50|    asset.mDicts.push_back(this); // register to the list of dictionaries
   73|     50|}
_ZN4glTF8LazyDictINS_4SkinEE16AttachToDocumentERN9rapidjson15GenericDocumentINS3_4UTF8IcEENS3_19MemoryPoolAllocatorINS3_12CrtAllocatorEEES8_EE:
   83|      3|inline void LazyDict<T>::AttachToDocument(Document &doc) {
   84|      3|    Value *container = nullptr;
   85|       |
   86|      3|    if (mExtId) {
  ------------------
  |  Branch (86:9): [True: 0, False: 3]
  ------------------
   87|      0|        if (Value *exts = FindObject(doc, "extensions")) {
  ------------------
  |  Branch (87:20): [True: 0, False: 0]
  ------------------
   88|      0|            container = FindObject(*exts, mExtId);
   89|      0|        }
   90|      3|    } else {
   91|      3|        container = &doc;
   92|      3|    }
   93|       |
   94|      3|    if (container) {
  ------------------
  |  Branch (94:9): [True: 3, False: 0]
  ------------------
   95|      3|        mDict = FindObject(*container, mDictId);
   96|      3|    }
   97|      3|}
_ZN4glTF8LazyDictINS_4SkinEE18DetachFromDocumentEv:
  100|      2|inline void LazyDict<T>::DetachFromDocument() {
  101|      2|    mDict = nullptr;
  102|      2|}
_ZN4glTF8LazyDictINS_7TextureEEC2ERNS_5AssetEPKcS6_:
   71|     50|        mDictId(dictId), mExtId(extId), mDict(nullptr), mAsset(asset) {
   72|     50|    asset.mDicts.push_back(this); // register to the list of dictionaries
   73|     50|}
_ZN4glTF8LazyDictINS_7TextureEE16AttachToDocumentERN9rapidjson15GenericDocumentINS3_4UTF8IcEENS3_19MemoryPoolAllocatorINS3_12CrtAllocatorEEES8_EE:
   83|      3|inline void LazyDict<T>::AttachToDocument(Document &doc) {
   84|      3|    Value *container = nullptr;
   85|       |
   86|      3|    if (mExtId) {
  ------------------
  |  Branch (86:9): [True: 0, False: 3]
  ------------------
   87|      0|        if (Value *exts = FindObject(doc, "extensions")) {
  ------------------
  |  Branch (87:20): [True: 0, False: 0]
  ------------------
   88|      0|            container = FindObject(*exts, mExtId);
   89|      0|        }
   90|      3|    } else {
   91|      3|        container = &doc;
   92|      3|    }
   93|       |
   94|      3|    if (container) {
  ------------------
  |  Branch (94:9): [True: 3, False: 0]
  ------------------
   95|      3|        mDict = FindObject(*container, mDictId);
   96|      3|    }
   97|      3|}
_ZN4glTF8LazyDictINS_7TextureEE18DetachFromDocumentEv:
  100|      2|inline void LazyDict<T>::DetachFromDocument() {
  101|      2|    mDict = nullptr;
  102|      2|}
_ZN4glTF8LazyDictINS_5LightEEC2ERNS_5AssetEPKcS6_:
   71|     50|        mDictId(dictId), mExtId(extId), mDict(nullptr), mAsset(asset) {
   72|     50|    asset.mDicts.push_back(this); // register to the list of dictionaries
   73|     50|}
_ZN4glTF8LazyDictINS_5LightEE16AttachToDocumentERN9rapidjson15GenericDocumentINS3_4UTF8IcEENS3_19MemoryPoolAllocatorINS3_12CrtAllocatorEEES8_EE:
   83|      3|inline void LazyDict<T>::AttachToDocument(Document &doc) {
   84|      3|    Value *container = nullptr;
   85|       |
   86|      3|    if (mExtId) {
  ------------------
  |  Branch (86:9): [True: 3, False: 0]
  ------------------
   87|      3|        if (Value *exts = FindObject(doc, "extensions")) {
  ------------------
  |  Branch (87:20): [True: 0, False: 3]
  ------------------
   88|      0|            container = FindObject(*exts, mExtId);
   89|      0|        }
   90|      3|    } else {
   91|      0|        container = &doc;
   92|      0|    }
   93|       |
   94|      3|    if (container) {
  ------------------
  |  Branch (94:9): [True: 0, False: 3]
  ------------------
   95|      0|        mDict = FindObject(*container, mDictId);
   96|      0|    }
   97|      3|}
_ZN4glTF8LazyDictINS_5LightEE18DetachFromDocumentEv:
  100|      2|inline void LazyDict<T>::DetachFromDocument() {
  101|      2|    mDict = nullptr;
  102|      2|}
_ZN4glTF8LazyDictINS_5LightEED2Ev:
   76|     50|inline LazyDict<T>::~LazyDict() {
   77|     50|    for (size_t i = 0; i < mObjs.size(); ++i) {
  ------------------
  |  Branch (77:24): [True: 0, False: 50]
  ------------------
   78|      0|        delete mObjs[i];
   79|      0|    }
   80|     50|}
_ZN4glTF8LazyDictINS_7TextureEED2Ev:
   76|     50|inline LazyDict<T>::~LazyDict() {
   77|     52|    for (size_t i = 0; i < mObjs.size(); ++i) {
  ------------------
  |  Branch (77:24): [True: 2, False: 50]
  ------------------
   78|      2|        delete mObjs[i];
   79|      2|    }
   80|     50|}
_ZN4glTF8LazyDictINS_4SkinEED2Ev:
   76|     50|inline LazyDict<T>::~LazyDict() {
   77|     50|    for (size_t i = 0; i < mObjs.size(); ++i) {
  ------------------
  |  Branch (77:24): [True: 0, False: 50]
  ------------------
   78|      0|        delete mObjs[i];
   79|      0|    }
   80|     50|}
_ZN4glTF8LazyDictINS_5SceneEED2Ev:
   76|     50|inline LazyDict<T>::~LazyDict() {
   77|     52|    for (size_t i = 0; i < mObjs.size(); ++i) {
  ------------------
  |  Branch (77:24): [True: 2, False: 50]
  ------------------
   78|      2|        delete mObjs[i];
   79|      2|    }
   80|     50|}
_ZN4glTF8LazyDictINS_7SamplerEED2Ev:
   76|     50|inline LazyDict<T>::~LazyDict() {
   77|     52|    for (size_t i = 0; i < mObjs.size(); ++i) {
  ------------------
  |  Branch (77:24): [True: 2, False: 50]
  ------------------
   78|      2|        delete mObjs[i];
   79|      2|    }
   80|     50|}
_ZN4glTF8LazyDictINS_4NodeEED2Ev:
   76|     50|inline LazyDict<T>::~LazyDict() {
   77|     59|    for (size_t i = 0; i < mObjs.size(); ++i) {
  ------------------
  |  Branch (77:24): [True: 9, False: 50]
  ------------------
   78|      9|        delete mObjs[i];
   79|      9|    }
   80|     50|}
_ZN4glTF8LazyDictINS_4MeshEED2Ev:
   76|     50|inline LazyDict<T>::~LazyDict() {
   77|     52|    for (size_t i = 0; i < mObjs.size(); ++i) {
  ------------------
  |  Branch (77:24): [True: 2, False: 50]
  ------------------
   78|      2|        delete mObjs[i];
   79|      2|    }
   80|     50|}
_ZN4glTF8LazyDictINS_8MaterialEED2Ev:
   76|     50|inline LazyDict<T>::~LazyDict() {
   77|     52|    for (size_t i = 0; i < mObjs.size(); ++i) {
  ------------------
  |  Branch (77:24): [True: 2, False: 50]
  ------------------
   78|      2|        delete mObjs[i];
   79|      2|    }
   80|     50|}
_ZN4glTF8LazyDictINS_5ImageEED2Ev:
   76|     50|inline LazyDict<T>::~LazyDict() {
   77|     52|    for (size_t i = 0; i < mObjs.size(); ++i) {
  ------------------
  |  Branch (77:24): [True: 2, False: 50]
  ------------------
   78|      2|        delete mObjs[i];
   79|      2|    }
   80|     50|}
_ZN4glTF8LazyDictINS_6CameraEED2Ev:
   76|     50|inline LazyDict<T>::~LazyDict() {
   77|     50|    for (size_t i = 0; i < mObjs.size(); ++i) {
  ------------------
  |  Branch (77:24): [True: 0, False: 50]
  ------------------
   78|      0|        delete mObjs[i];
   79|      0|    }
   80|     50|}
_ZN4glTF8LazyDictINS_10BufferViewEED2Ev:
   76|     50|inline LazyDict<T>::~LazyDict() {
   77|     54|    for (size_t i = 0; i < mObjs.size(); ++i) {
  ------------------
  |  Branch (77:24): [True: 4, False: 50]
  ------------------
   78|      4|        delete mObjs[i];
   79|      4|    }
   80|     50|}
_ZN4glTF8LazyDictINS_6BufferEED2Ev:
   76|     50|inline LazyDict<T>::~LazyDict() {
   77|     53|    for (size_t i = 0; i < mObjs.size(); ++i) {
  ------------------
  |  Branch (77:24): [True: 3, False: 50]
  ------------------
   78|      3|        delete mObjs[i];
   79|      3|    }
   80|     50|}
_ZN4glTF8LazyDictINS_9AnimationEED2Ev:
   76|     50|inline LazyDict<T>::~LazyDict() {
   77|     50|    for (size_t i = 0; i < mObjs.size(); ++i) {
  ------------------
  |  Branch (77:24): [True: 0, False: 50]
  ------------------
   78|      0|        delete mObjs[i];
   79|      0|    }
   80|     50|}
_ZN4glTF8LazyDictINS_8AccessorEED2Ev:
   76|     50|inline LazyDict<T>::~LazyDict() {
   77|     58|    for (size_t i = 0; i < mObjs.size(); ++i) {
  ------------------
  |  Branch (77:24): [True: 8, False: 50]
  ------------------
   78|      8|        delete mObjs[i];
   79|      8|    }
   80|     50|}
_ZN4glTF8LazyDictINS_5SceneEE3AddEPS1_:
  140|      2|Ref<T> LazyDict<T>::Add(T *obj) {
  141|      2|    unsigned int idx = unsigned(mObjs.size());
  142|      2|    mObjs.push_back(obj);
  143|      2|    mObjsById[obj->id] = idx;
  144|      2|    mAsset.mUsedIds[obj->id] = true;
  145|      2|    return Ref<T>(mObjs, idx);
  146|      2|}
_ZN4glTF8Accessor14GetElementSizeEv:
  381|      4|inline unsigned int Accessor::GetElementSize() {
  382|      4|    return GetNumComponents() * GetBytesPerComponent();
  383|      4|}
_ZN4glTF8Accessor10GetPointerEv:
  385|      4|inline uint8_t *Accessor::GetPointer() {
  386|      4|    if (!bufferView || !bufferView->buffer) return nullptr;
  ------------------
  |  Branch (386:9): [True: 0, False: 4]
  |  Branch (386:24): [True: 0, False: 4]
  ------------------
  387|      4|    uint8_t *basePtr = bufferView->buffer->GetPointer();
  388|      4|    if (!basePtr) return nullptr;
  ------------------
  |  Branch (388:9): [True: 0, False: 4]
  ------------------
  389|       |
  390|      4|    size_t offset = byteOffset + bufferView->byteOffset;
  391|       |
  392|       |    // Check if region is encoded.
  393|      4|    if (bufferView->buffer->EncodedRegion_Current != nullptr) {
  ------------------
  |  Branch (393:9): [True: 0, False: 4]
  ------------------
  394|      0|        const size_t begin = bufferView->buffer->EncodedRegion_Current->Offset;
  395|      0|        const size_t end = begin + bufferView->buffer->EncodedRegion_Current->DecodedData_Length;
  396|       |
  397|      0|        if ((offset >= begin) && (offset < end))
  ------------------
  |  Branch (397:13): [True: 0, False: 0]
  |  Branch (397:34): [True: 0, False: 0]
  ------------------
  398|      0|            return &bufferView->buffer->EncodedRegion_Current->DecodedData[offset - begin];
  399|      0|    }
  400|       |
  401|      4|    return basePtr + offset;
  402|      4|}
_ZN4glTF5Image9StealDataEv:
  527|      1|inline uint8_t *Image::StealData() {
  528|      1|    mDataLength = 0;
  529|      1|    return mData.release();
  530|      1|}
_ZN4glTF5Scene4ReadERN9rapidjson12GenericValueINS1_4UTF8IcEENS1_19MemoryPoolAllocatorINS1_12CrtAllocatorEEEEERNS_5AssetE:
 1082|      3|inline void Scene::Read(Value &obj, Asset &r) {
 1083|      3|    if (Value *array = FindArray(obj, "nodes")) {
  ------------------
  |  Branch (1083:16): [True: 3, False: 0]
  ------------------
 1084|      7|        for (unsigned int i = 0; i < array->Size(); ++i) {
  ------------------
  |  Branch (1084:34): [True: 4, False: 3]
  ------------------
 1085|      4|            if (!(*array)[i].IsString()) continue;
  ------------------
  |  Branch (1085:17): [True: 0, False: 4]
  ------------------
 1086|      4|            Ref<Node> node = r.nodes.Get((*array)[i].GetString());
 1087|      4|            if (node)
  ------------------
  |  Branch (1087:17): [True: 3, False: 1]
  ------------------
 1088|      3|                this->nodes.push_back(node);
 1089|      4|        }
 1090|      3|    }
 1091|      3|}
_ZN4glTF13AssetMetadata4ReadERN9rapidjson15GenericDocumentINS1_4UTF8IcEENS1_19MemoryPoolAllocatorINS1_12CrtAllocatorEEES6_EE:
 1093|      8|inline void AssetMetadata::Read(Document &doc) {
 1094|       |    // read the version, etc.
 1095|      8|    if (Value *obj = FindObject(doc, "asset")) {
  ------------------
  |  Branch (1095:16): [True: 8, False: 0]
  ------------------
 1096|      8|        ReadMember(*obj, "copyright", copyright);
 1097|      8|        ReadMember(*obj, "generator", generator);
 1098|       |
 1099|      8|        premultipliedAlpha = MemberOrDefault(*obj, "premultipliedAlpha", false);
 1100|       |
 1101|      8|        if (Value *versionString = FindString(*obj, "version")) {
  ------------------
  |  Branch (1101:20): [True: 7, False: 1]
  ------------------
 1102|      7|            version = versionString->GetString();
 1103|      7|        } else if (Value *versionNumber = FindNumber(*obj, "version")) {
  ------------------
  |  Branch (1103:27): [True: 1, False: 0]
  ------------------
 1104|      1|            char buf[4];
 1105|       |
 1106|      1|            ai_snprintf(buf, 4, "%.1f", versionNumber->GetDouble());
 1107|       |
 1108|      1|            version = buf;
 1109|      1|        }
 1110|       |
 1111|      8|        Value *curProfile = FindObject(*obj, "profile");
 1112|      8|        if (nullptr != curProfile) {
  ------------------
  |  Branch (1112:13): [True: 3, False: 5]
  ------------------
 1113|      3|            ReadMember(*curProfile, "api", this->profile.api);
 1114|      3|            ReadMember(*curProfile, "version", this->profile.version);
 1115|      3|        }
 1116|      8|    }
 1117|      8|}
_ZN4glTF5Asset16ReadBinaryHeaderERN6Assimp8IOStreamE:
 1123|      1|inline void Asset::ReadBinaryHeader(IOStream &stream) {
 1124|      1|    GLB_Header header;
 1125|      1|    if (stream.Read(&header, sizeof(header), 1) != 1) {
  ------------------
  |  Branch (1125:9): [True: 0, False: 1]
  ------------------
 1126|      0|        throw DeadlyImportError("GLTF: Unable to read the file header");
 1127|      0|    }
 1128|       |
 1129|      1|    if (strncmp((char *)header.magic, AI_GLB_MAGIC_NUMBER, sizeof(header.magic)) != 0) {
  ------------------
  |  |  127|      1|#define AI_GLB_MAGIC_NUMBER "glTF"
  ------------------
  |  Branch (1129:9): [True: 0, False: 1]
  ------------------
 1130|      0|        throw DeadlyImportError("GLTF: Invalid binary glTF file");
 1131|      0|    }
 1132|       |
 1133|      1|    AI_SWAP4(header.version);
 1134|      1|    asset.version = ai_to_string(header.version);
 1135|      1|    if (header.version != 1) {
  ------------------
  |  Branch (1135:9): [True: 0, False: 1]
  ------------------
 1136|      0|        throw DeadlyImportError("GLTF: Unsupported binary glTF version");
 1137|      0|    }
 1138|       |
 1139|      1|    AI_SWAP4(header.sceneFormat);
 1140|      1|    if (header.sceneFormat != SceneFormat_JSON) {
  ------------------
  |  Branch (1140:9): [True: 0, False: 1]
  ------------------
 1141|      0|        throw DeadlyImportError("GLTF: Unsupported binary glTF scene format");
 1142|      0|    }
 1143|       |
 1144|      1|    AI_SWAP4(header.length);
 1145|      1|    AI_SWAP4(header.sceneLength);
 1146|       |
 1147|      1|    static_assert(std::numeric_limits<uint32_t>::max() <= std::numeric_limits<size_t>::max(), "size_t must be at least 32bits");
 1148|      1|    mSceneLength = static_cast<size_t>(header.sceneLength); // Can't be larger than 4GB (max. uint32_t)
 1149|       |
 1150|      1|    mBodyOffset = sizeof(header) + mSceneLength;
 1151|      1|    mBodyOffset = (mBodyOffset + 3) & ~3; // Round up to next multiple of 4
 1152|       |
 1153|      1|    mBodyLength = header.length - mBodyOffset;
 1154|      1|}
_ZN4glTF5Asset4LoadERKNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEb:
 1156|     50|inline void Asset::Load(const std::string &pFile, bool isBinary) {
 1157|     50|    mCurrentAssetDir.clear();
 1158|       |
 1159|       |    /*int pos = std::max(int(pFile.rfind('/')), int(pFile.rfind('\\')));
 1160|       |    if (pos != int(std::string::npos)) mCurrentAssetDir = pFile.substr(0, pos + 1);*/
 1161|     50|    if (0 != strncmp(pFile.c_str(), AI_MEMORYIO_MAGIC_FILENAME, AI_MEMORYIO_MAGIC_FILENAME_LENGTH)) {
  ------------------
  |  Branch (1161:9): [True: 0, False: 50]
  ------------------
 1162|      0|        mCurrentAssetDir = getCurrentAssetDir(pFile);
 1163|      0|    }
 1164|       |
 1165|     50|    shared_ptr<IOStream> stream(OpenFile(pFile.c_str(), "rb", true));
 1166|     50|    if (!stream) {
  ------------------
  |  Branch (1166:9): [True: 0, False: 50]
  ------------------
 1167|      0|        throw DeadlyImportError("GLTF: Could not open file for reading");
 1168|      0|    }
 1169|       |
 1170|       |    // is binary? then read the header
 1171|     50|    if (isBinary) {
  ------------------
  |  Branch (1171:9): [True: 1, False: 49]
  ------------------
 1172|      1|        SetAsBinary(); // also creates the body buffer
 1173|      1|        ReadBinaryHeader(*stream);
 1174|     49|    } else {
 1175|     49|        mSceneLength = stream->FileSize();
 1176|     49|        mBodyLength = 0;
 1177|     49|    }
 1178|       |
 1179|       |    // Smallest legal JSON file is "{}" Smallest loadable glTF file is larger than that but catch it later
 1180|     50|    if (mSceneLength < 2) {
  ------------------
  |  Branch (1180:9): [True: 0, False: 50]
  ------------------
 1181|      0|        throw DeadlyImportError("GLTF: No JSON file contents");
 1182|      0|    }
 1183|       |
 1184|       |    // Binary format only supports up to 4GB of JSON so limit it there to avoid extreme memory allocation
 1185|     50|    if (mSceneLength >= std::numeric_limits<uint32_t>::max()) {
  ------------------
  |  Branch (1185:9): [True: 0, False: 50]
  ------------------
 1186|      0|        throw DeadlyImportError("GLTF: JSON size greater than 4GB");
 1187|      0|    }
 1188|       |
 1189|       |    // read the scene data, ensure null termination
 1190|     50|    std::vector<char> sceneData(mSceneLength + 1);
 1191|     50|    sceneData[mSceneLength] = '\0';
 1192|       |
 1193|     50|    if (stream->Read(&sceneData[0], 1, mSceneLength) != mSceneLength) {
  ------------------
  |  Branch (1193:9): [True: 0, False: 50]
  ------------------
 1194|      0|        throw DeadlyImportError("GLTF: Could not read the file contents");
 1195|      0|    }
 1196|       |
 1197|       |    // parse the JSON document
 1198|       |
 1199|     50|    Document doc;
 1200|     50|    doc.ParseInsitu(&sceneData[0]);
 1201|       |
 1202|     50|    if (doc.HasParseError()) {
  ------------------
  |  Branch (1202:9): [True: 40, False: 10]
  ------------------
 1203|     40|        char buffer[32];
 1204|     40|        ai_snprintf(buffer, 32, "%d", static_cast<int>(doc.GetErrorOffset()));
 1205|     40|        throw DeadlyImportError("GLTF: JSON parse error, offset ", buffer, ": ", GetParseError_En(doc.GetParseError()));
 1206|     40|    }
 1207|       |
 1208|     10|    if (!doc.IsObject()) {
  ------------------
  |  Branch (1208:9): [True: 1, False: 9]
  ------------------
 1209|      1|        throw DeadlyImportError("GLTF: JSON document root must be a JSON object");
 1210|      1|    }
 1211|       |
 1212|       |    // Fill the buffer instance for the current file embedded contents
 1213|      9|    if (mBodyLength > 0) {
  ------------------
  |  Branch (1213:9): [True: 1, False: 8]
  ------------------
 1214|      1|        if (!mBodyBuffer->LoadFromStream(*stream, mBodyLength, mBodyOffset)) {
  ------------------
  |  Branch (1214:13): [True: 1, False: 0]
  ------------------
 1215|      1|            throw DeadlyImportError("GLTF: Unable to read gltf file");
 1216|      1|        }
 1217|      1|    }
 1218|       |
 1219|       |    // Load the metadata
 1220|      8|    asset.Read(doc);
 1221|      8|    if (!asset) {
  ------------------
  |  Branch (1221:9): [True: 5, False: 3]
  ------------------
 1222|      5|        return;
 1223|      5|    }
 1224|       |
 1225|      3|    ReadExtensionsUsed(doc);
 1226|       |
 1227|       |    // Prepare the dictionaries
 1228|     45|    for (size_t i = 0; i < mDicts.size(); ++i) {
  ------------------
  |  Branch (1228:24): [True: 42, False: 3]
  ------------------
 1229|     42|        mDicts[i]->AttachToDocument(doc);
 1230|     42|    }
 1231|       |
 1232|       |    // Read the "scene" property, which specifies which scene to load
 1233|       |    // and recursively load everything referenced by it
 1234|      3|    Value *curScene = FindString(doc, "scene");
 1235|      3|    if (nullptr != curScene) {
  ------------------
  |  Branch (1235:9): [True: 3, False: 0]
  ------------------
 1236|      3|        this->scene = scenes.Get(curScene->GetString());
 1237|      3|    }
 1238|       |
 1239|       |    // Clean up
 1240|     31|    for (size_t i = 0; i < mDicts.size(); ++i) {
  ------------------
  |  Branch (1240:24): [True: 28, False: 3]
  ------------------
 1241|     28|        mDicts[i]->DetachFromDocument();
 1242|     28|    }
 1243|      3|}
_ZN4glTF5Asset18ReadExtensionsUsedERN9rapidjson15GenericDocumentINS1_4UTF8IcEENS1_19MemoryPoolAllocatorINS1_12CrtAllocatorEEES6_EE:
 1253|      3|inline void Asset::ReadExtensionsUsed(Document &doc) {
 1254|      3|    Value *extsUsed = FindArray(doc, "extensionsUsed");
 1255|      3|    if (!extsUsed) return;
  ------------------
  |  Branch (1255:9): [True: 3, False: 0]
  ------------------
 1256|       |
 1257|      0|    std::gltf_unordered_map<std::string, bool> exts;
 1258|       |
 1259|      0|    for (unsigned int i = 0; i < extsUsed->Size(); ++i) {
  ------------------
  |  Branch (1259:30): [True: 0, False: 0]
  ------------------
 1260|      0|        if ((*extsUsed)[i].IsString()) {
  ------------------
  |  Branch (1260:13): [True: 0, False: 0]
  ------------------
 1261|      0|            exts[(*extsUsed)[i].GetString()] = true;
 1262|      0|        }
 1263|      0|    }
 1264|       |
 1265|      0|    CHECK_EXT(KHR_binary_glTF);
  ------------------
  |  |  237|      0|    if (exts.find(#EXT) != exts.end()) extensionsUsed.EXT = true;
  |  |  ------------------
  |  |  |  Branch (237:9): [True: 0, False: 0]
  |  |  ------------------
  ------------------
 1266|      0|    CHECK_EXT(KHR_materials_common);
  ------------------
  |  |  237|      0|    if (exts.find(#EXT) != exts.end()) extensionsUsed.EXT = true;
  |  |  ------------------
  |  |  |  Branch (237:9): [True: 0, False: 0]
  |  |  ------------------
  ------------------
 1267|       |
 1268|      0|#undef CHECK_EXT
 1269|      0|}
_ZN4glTF8Accessor7Indexer8GetValueIjEET_i:
  470|     36|T Accessor::Indexer::GetValue(int i) {
  471|     36|    ai_assert(data);
  472|     36|    ai_assert(i * stride < accessor.bufferView->byteLength);
  473|     36|    T value = T();
  474|     36|    memcpy(&value, data + i * stride, elemSize);
  475|       |    //value >>= 8 * (sizeof(T) - elemSize);
  476|     36|    return value;
  477|     36|}
_ZN4glTF8LazyDictINS_5SceneEE3GetEPKc:
  110|      3|Ref<T> LazyDict<T>::Get(const char *id) {
  111|      3|    id = T::TranslateId(mAsset, id);
  112|       |
  113|      3|    typename Dict::iterator it = mObjsById.find(id);
  114|      3|    if (it != mObjsById.end()) { // already created?
  ------------------
  |  Branch (114:9): [True: 0, False: 3]
  ------------------
  115|      0|        return Ref<T>(mObjs, it->second);
  116|      0|    }
  117|       |
  118|       |    // read it from the JSON object
  119|      3|    if (!mDict) {
  ------------------
  |  Branch (119:9): [True: 0, False: 3]
  ------------------
  120|      0|        throw DeadlyImportError("GLTF: Missing section \"", mDictId, "\"");
  121|      0|    }
  122|       |
  123|      3|    Value::MemberIterator obj = mDict->FindMember(id);
  124|      3|    if (obj == mDict->MemberEnd()) {
  ------------------
  |  Branch (124:9): [True: 0, False: 3]
  ------------------
  125|      0|        throw DeadlyImportError("GLTF: Missing object with id \"", id, "\" in \"", mDictId, "\"");
  126|      0|    }
  127|      3|    if (!obj->value.IsObject()) {
  ------------------
  |  Branch (127:9): [True: 0, False: 3]
  ------------------
  128|      0|        throw DeadlyImportError("GLTF: Object with id \"", id, "\" is not a JSON object");
  129|      0|    }
  130|       |
  131|       |    // create an instance of the given type
  132|      3|    T *inst = new T();
  133|      3|    inst->id = id;
  134|      3|    ReadMember(obj->value, "name", inst->name);
  135|      3|    inst->Read(obj->value, mAsset);
  136|      3|    return Add(inst);
  137|      3|}
_ZN4glTF8Accessor7IndexerC2ERS0_:
  465|      1|        accessor(acc), data(acc.GetPointer()), elemSize(acc.GetElementSize()), stride(acc.byteStride ? acc.byteStride : elemSize) {
  ------------------
  |  Branch (465:87): [True: 0, False: 1]
  ------------------
  466|      1|}
_ZN4glTF8Accessor11ExtractDataI10aiVector3tIfEEEbRPT_:
  425|      3|bool Accessor::ExtractData(T *&outData) {
  426|      3|    uint8_t *data = GetPointer();
  427|      3|    if (!data) return false;
  ------------------
  |  Branch (427:9): [True: 0, False: 3]
  ------------------
  428|       |
  429|      3|    const size_t elemSize = GetElementSize();
  430|      3|    const size_t totalSize = elemSize * count;
  431|       |
  432|      3|    const size_t stride = byteStride ? byteStride : elemSize;
  ------------------
  |  Branch (432:27): [True: 3, False: 0]
  ------------------
  433|       |
  434|      3|    const size_t targetElemSize = sizeof(T);
  435|      3|    ai_assert(elemSize <= targetElemSize);
  436|       |
  437|      3|    ai_assert(count * stride <= bufferView->byteLength);
  438|       |
  439|      3|    outData = new T[count];
  440|      3|    if (stride == elemSize && targetElemSize == elemSize) {
  ------------------
  |  Branch (440:9): [True: 3, False: 0]
  |  Branch (440:31): [True: 2, False: 1]
  ------------------
  441|      2|        memcpy(outData, data, totalSize);
  442|      2|    } else {
  443|     25|        for (size_t i = 0; i < count; ++i) {
  ------------------
  |  Branch (443:28): [True: 24, False: 1]
  ------------------
  444|     24|            memcpy(outData + i, data + i * stride, elemSize);
  445|     24|        }
  446|      1|    }
  447|       |
  448|      3|    return true;
  449|      3|}

_ZN6Assimp12glTFImporterC2Ev:
  148|    624|        mScene(nullptr) {
  149|       |    // empty
  150|    624|}
_ZNK6Assimp12glTFImporter7GetInfoEv:
  152|    635|const aiImporterDesc *glTFImporter::GetInfo() const {
  153|    635|    return &desc;
  154|    635|}
_ZNK6Assimp12glTFImporter7CanReadERKNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEPNS_8IOSystemEb:
  156|     49|bool glTFImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool /* checkSig */) const {
  157|     49|    Asset asset(pIOHandler);
  158|     49|    try {
  159|     49|        asset.Load(pFile,
  160|     49|                   CheckMagicToken(
  161|     49|                       pIOHandler, pFile, AI_GLB_MAGIC_NUMBER, 1, 0,
  ------------------
  |  |  127|     49|#define AI_GLB_MAGIC_NUMBER "glTF"
  ------------------
  162|     49|                       static_cast<unsigned int>(strlen(AI_GLB_MAGIC_NUMBER))));
  ------------------
  |  |  127|     49|#define AI_GLB_MAGIC_NUMBER "glTF"
  ------------------
  163|     49|        return asset.asset;
  164|     49|    } catch (...) {
  165|     43|        return false;
  166|     43|    }
  167|     49|}
_ZNK6Assimp12glTFImporter15ImportMaterialsERN4glTF5AssetE:
  169|      1|void glTFImporter::ImportMaterials(Asset &r) const {
  170|      1|    mScene->mNumMaterials = r.materials.Size();
  171|      1|    if (mScene->mNumMaterials == 0) {
  ------------------
  |  Branch (171:9): [True: 0, False: 1]
  ------------------
  172|      0|        createDefaultMaterial(mScene);
  173|      0|        return;
  174|      0|    }
  175|       |
  176|      1|    mScene->mMaterials = new aiMaterial *[mScene->mNumMaterials];
  177|      2|    for (unsigned int i = 0; i < mScene->mNumMaterials; ++i) {
  ------------------
  |  Branch (177:30): [True: 1, False: 1]
  ------------------
  178|      1|        aiMaterial *aimat = mScene->mMaterials[i] = new aiMaterial();
  179|       |
  180|      1|        Material &mat = r.materials[i];
  181|      1|        aiString str(mat.id);
  182|      1|        aimat->AddProperty(&str, AI_MATKEY_NAME);
  183|       |
  184|      1|        SetMaterialColorProperty(embeddedTexIdxs, r, mat.ambient, aimat, aiTextureType_AMBIENT, AI_MATKEY_COLOR_AMBIENT);
  185|      1|        SetMaterialColorProperty(embeddedTexIdxs, r, mat.diffuse, aimat, aiTextureType_DIFFUSE, AI_MATKEY_COLOR_DIFFUSE);
  186|      1|        SetMaterialColorProperty(embeddedTexIdxs, r, mat.specular, aimat, aiTextureType_SPECULAR, AI_MATKEY_COLOR_SPECULAR);
  187|      1|        SetMaterialColorProperty(embeddedTexIdxs, r, mat.emission, aimat, aiTextureType_EMISSIVE, AI_MATKEY_COLOR_EMISSIVE);
  188|       |
  189|      1|        aimat->AddProperty(&mat.doubleSided, 1, AI_MATKEY_TWOSIDED);
  190|       |
  191|      1|        if (mat.transparent && (mat.transparency != 1.0f)) {
  ------------------
  |  Branch (191:13): [True: 0, False: 1]
  |  Branch (191:32): [True: 0, False: 0]
  ------------------
  192|      0|            aimat->AddProperty(&mat.transparency, 1, AI_MATKEY_OPACITY);
  193|      0|        }
  194|       |
  195|      1|        if (mat.shininess > 0.f) {
  ------------------
  |  Branch (195:13): [True: 1, False: 0]
  ------------------
  196|       |            aimat->AddProperty(&mat.shininess, 1, AI_MATKEY_SHININESS);
  197|      1|        }
  198|      1|    }
  199|      1|}
_ZN6Assimp12glTFImporter12ImportMeshesERN4glTF5AssetE:
  201|      1|void glTFImporter::ImportMeshes(Asset &r) {
  202|      1|    std::vector<aiMesh *> meshes;
  203|       |
  204|      1|    unsigned int k = 0;
  205|      1|    meshOffsets.clear();
  206|       |
  207|      2|    for (unsigned int m = 0; m < r.meshes.Size(); ++m) {
  ------------------
  |  Branch (207:30): [True: 1, False: 1]
  ------------------
  208|      1|        Mesh &mesh = r.meshes[m];
  209|       |
  210|       |        // Check if mesh extensions is used
  211|      1|        if (mesh.Extension.size() > 0) {
  ------------------
  |  Branch (211:13): [True: 0, False: 1]
  ------------------
  212|      0|#ifdef ASSIMP_IMPORTER_GLTF_USE_OPEN3DGC
  213|      0|            for (Mesh::SExtension *cur_ext : mesh.Extension) {
  ------------------
  |  Branch (213:44): [True: 0, False: 0]
  ------------------
  214|      0|                if (cur_ext->Type == Mesh::SExtension::EType::Compression_Open3DGC) {
  ------------------
  |  Branch (214:21): [True: 0, False: 0]
  ------------------
  215|       |                    // Limitations for meshes when using Open3DGC-compression.
  216|       |                    // It's a current limitation of sp... Specification have not this part still - about mesh compression. Why only one primitive?
  217|       |                    // Because glTF is very flexibly. But in fact it ugly flexible. Every primitive can has own set of accessors and accessors can
  218|       |                    // point to a-a-a-a-any part of buffer (through bufferview of course) and even to another buffer. We know that "Open3DGC-compression"
  219|       |                    // is applicable only to part of buffer. As we can't guaranty continuity of the data for decoder, we will limit quantity of primitives.
  220|       |                    // Yes indices, coordinates etc. still can br stored in different buffers, but with current specification it's a exporter problem.
  221|       |                    // Also primitive can has only one of "POSITION", "NORMAL" and less then "AI_MAX_NUMBER_OF_TEXTURECOORDS" of "TEXCOORD". All accessor
  222|       |                    // of primitive must point to one continuous region of the buffer.
  223|      0|                    if (mesh.primitives.size() > 2) throw DeadlyImportError("GLTF: When using Open3DGC compression then only one primitive per mesh are allowed.");
  ------------------
  |  Branch (223:25): [True: 0, False: 0]
  ------------------
  224|       |
  225|      0|                    Mesh::SCompression_Open3DGC *o3dgc_ext = (Mesh::SCompression_Open3DGC *)cur_ext;
  226|      0|                    Ref<Buffer> buf = r.buffers.Get(o3dgc_ext->Buffer);
  227|       |
  228|      0|                    buf->EncodedRegion_SetCurrent(mesh.id);
  229|      0|                } else
  230|      0|                {
  231|      0|                    throw DeadlyImportError("GLTF: Can not import mesh: unknown mesh extension (code: \"", ai_to_string(cur_ext->Type),
  232|      0|                                            "\"), only Open3DGC is supported.");
  233|      0|                }
  234|      0|            }
  235|      0|#endif
  236|      0|        } // if(mesh.Extension.size() > 0)
  237|       |
  238|      1|        meshOffsets.push_back(k);
  239|      1|        k += static_cast<unsigned>(mesh.primitives.size());
  240|       |
  241|      2|        for (unsigned int p = 0; p < mesh.primitives.size(); ++p) {
  ------------------
  |  Branch (241:34): [True: 1, False: 1]
  ------------------
  242|      1|            auto &[mode, attributes, indices, material] = mesh.primitives[p];
  243|       |
  244|      1|            aiMesh *aim = new aiMesh();
  245|      1|            meshes.push_back(aim);
  246|       |
  247|      1|            aim->mName = mesh.id;
  248|      1|            if (mesh.primitives.size() > 1) {
  ------------------
  |  Branch (248:17): [True: 0, False: 1]
  ------------------
  249|      0|                ai_uint32 &len = aim->mName.length;
  250|      0|                aim->mName.data[len] = '-';
  251|      0|                len += 1 + ASSIMP_itoa10(aim->mName.data + len + 1, unsigned(AI_MAXLEN - len - 1), p);
  252|      0|            }
  253|       |
  254|      1|            switch (mode) {
  ------------------
  |  Branch (254:21): [True: 1, False: 0]
  ------------------
  255|      0|            case PrimitiveMode_POINTS:
  ------------------
  |  Branch (255:13): [True: 0, False: 1]
  ------------------
  256|      0|                aim->mPrimitiveTypes |= aiPrimitiveType_POINT;
  257|      0|                break;
  258|       |
  259|      0|            case PrimitiveMode_LINES:
  ------------------
  |  Branch (259:13): [True: 0, False: 1]
  ------------------
  260|      0|            case PrimitiveMode_LINE_LOOP:
  ------------------
  |  Branch (260:13): [True: 0, False: 1]
  ------------------
  261|      0|            case PrimitiveMode_LINE_STRIP:
  ------------------
  |  Branch (261:13): [True: 0, False: 1]
  ------------------
  262|      0|                aim->mPrimitiveTypes |= aiPrimitiveType_LINE;
  263|      0|                break;
  264|       |
  265|      1|            case PrimitiveMode_TRIANGLES:
  ------------------
  |  Branch (265:13): [True: 1, False: 0]
  ------------------
  266|      1|            case PrimitiveMode_TRIANGLE_STRIP:
  ------------------
  |  Branch (266:13): [True: 0, False: 1]
  ------------------
  267|      1|            case PrimitiveMode_TRIANGLE_FAN:
  ------------------
  |  Branch (267:13): [True: 0, False: 1]
  ------------------
  268|      1|                aim->mPrimitiveTypes |= aiPrimitiveType_TRIANGLE;
  269|      1|                break;
  270|      1|            }
  271|       |
  272|      1|            Mesh::Primitive::Attributes &attr = attributes;
  273|       |
  274|      1|            if (attr.position.size() > 0 && attr.position[0]) {
  ------------------
  |  Branch (274:17): [True: 1, False: 0]
  |  Branch (274:45): [True: 1, False: 0]
  ------------------
  275|      1|                aim->mNumVertices = attr.position[0]->count;
  276|      1|                attr.position[0]->ExtractData(aim->mVertices);
  277|      1|            }
  278|       |
  279|      1|            if (attr.normal.size() > 0 && attr.normal[0]) attr.normal[0]->ExtractData(aim->mNormals);
  ------------------
  |  Branch (279:17): [True: 1, False: 0]
  |  Branch (279:43): [True: 1, False: 0]
  ------------------
  280|       |
  281|      2|            for (size_t tc = 0; tc < attr.texcoord.size() && tc < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++tc) {
  ------------------
  |  Branch (281:33): [True: 1, False: 1]
  |  Branch (281:62): [True: 1, False: 0]
  ------------------
  282|      1|                attr.texcoord[tc]->ExtractData(aim->mTextureCoords[tc]);
  283|      1|                aim->mNumUVComponents[tc] = attr.texcoord[tc]->GetNumComponents();
  284|       |
  285|      1|                aiVector3D *values = aim->mTextureCoords[tc];
  286|     25|                for (unsigned int i = 0; i < aim->mNumVertices; ++i) {
  ------------------
  |  Branch (286:42): [True: 24, False: 1]
  ------------------
  287|     24|                    values[i].y = 1 - values[i].y; // Flip Y coords
  288|     24|                }
  289|      1|            }
  290|       |
  291|      1|            aiFace *faces = nullptr;
  292|      1|            unsigned int nFaces = 0;
  293|       |
  294|      1|            if (indices) {
  ------------------
  |  Branch (294:17): [True: 1, False: 0]
  ------------------
  295|      1|                unsigned int count = indices->count;
  296|       |
  297|      1|                Accessor::Indexer data = indices->GetIndexer();
  298|      1|                ai_assert(data.IsValid());
  299|       |
  300|      1|                switch (mode) {
  ------------------
  |  Branch (300:25): [True: 1, False: 0]
  ------------------
  301|      0|                case PrimitiveMode_POINTS: {
  ------------------
  |  Branch (301:17): [True: 0, False: 1]
  ------------------
  302|      0|                    nFaces = count;
  303|      0|                    faces = new aiFace[nFaces];
  304|      0|                    for (unsigned int i = 0; i < count; ++i) {
  ------------------
  |  Branch (304:46): [True: 0, False: 0]
  ------------------
  305|      0|                        SetFace(faces[i], data.GetUInt(i));
  306|      0|                    }
  307|      0|                    break;
  308|      0|                }
  309|       |
  310|      0|                case PrimitiveMode_LINES: {
  ------------------
  |  Branch (310:17): [True: 0, False: 1]
  ------------------
  311|      0|                    nFaces = count / 2;
  312|      0|                    if (nFaces * 2 != count) {
  ------------------
  |  Branch (312:25): [True: 0, False: 0]
  ------------------
  313|      0|                        ASSIMP_LOG_WARN("The number of vertices was not compatible with the LINES mode. Some vertices were dropped.");
  314|      0|                        count = nFaces * 2;
  315|      0|                    }
  316|      0|                    faces = new aiFace[nFaces];
  317|      0|                    for (unsigned int i = 0; i < count; i += 2) {
  ------------------
  |  Branch (317:46): [True: 0, False: 0]
  ------------------
  318|      0|                        SetFace(faces[i / 2], data.GetUInt(i), data.GetUInt(i + 1));
  319|      0|                    }
  320|      0|                    break;
  321|      0|                }
  322|       |
  323|      0|                case PrimitiveMode_LINE_LOOP:
  ------------------
  |  Branch (323:17): [True: 0, False: 1]
  ------------------
  324|      0|                case PrimitiveMode_LINE_STRIP: {
  ------------------
  |  Branch (324:17): [True: 0, False: 1]
  ------------------
  325|      0|                    nFaces = count - ((mode == PrimitiveMode_LINE_STRIP) ? 1 : 0);
  ------------------
  |  Branch (325:39): [True: 0, False: 0]
  ------------------
  326|      0|                    faces = new aiFace[nFaces];
  327|      0|                    SetFace(faces[0], data.GetUInt(0), data.GetUInt(1));
  328|      0|                    for (unsigned int i = 2; i < count; ++i) {
  ------------------
  |  Branch (328:46): [True: 0, False: 0]
  ------------------
  329|      0|                        SetFace(faces[i - 1], faces[i - 2].mIndices[1], data.GetUInt(i));
  330|      0|                    }
  331|      0|                    if (mode == PrimitiveMode_LINE_LOOP) { // close the loop
  ------------------
  |  Branch (331:25): [True: 0, False: 0]
  ------------------
  332|      0|                        SetFace(faces[count - 1], faces[count - 2].mIndices[1], faces[0].mIndices[0]);
  333|      0|                    }
  334|      0|                    break;
  335|      0|                }
  336|       |
  337|      1|                case PrimitiveMode_TRIANGLES: {
  ------------------
  |  Branch (337:17): [True: 1, False: 0]
  ------------------
  338|      1|                    nFaces = count / 3;
  339|      1|                    if (nFaces * 3 != count) {
  ------------------
  |  Branch (339:25): [True: 0, False: 1]
  ------------------
  340|      0|                        ASSIMP_LOG_WARN("The number of vertices was not compatible with the TRIANGLES mode. Some vertices were dropped.");
  341|      0|                        count = nFaces * 3;
  342|      0|                    }
  343|      1|                    faces = new aiFace[nFaces];
  344|     13|                    for (unsigned int i = 0; i < count; i += 3) {
  ------------------
  |  Branch (344:46): [True: 12, False: 1]
  ------------------
  345|     12|                        SetFace(faces[i / 3], data.GetUInt(i), data.GetUInt(i + 1), data.GetUInt(i + 2));
  346|     12|                    }
  347|      1|                    break;
  348|      0|                }
  349|      0|                case PrimitiveMode_TRIANGLE_STRIP: {
  ------------------
  |  Branch (349:17): [True: 0, False: 1]
  ------------------
  350|      0|                    nFaces = count - 2;
  351|      0|                    faces = new aiFace[nFaces];
  352|      0|                    SetFace(faces[0], data.GetUInt(0), data.GetUInt(1), data.GetUInt(2));
  353|      0|                    for (unsigned int i = 3; i < count; ++i) {
  ------------------
  |  Branch (353:46): [True: 0, False: 0]
  ------------------
  354|      0|                        SetFace(faces[i - 2], faces[i - 1].mIndices[1], faces[i - 1].mIndices[2], data.GetUInt(i));
  355|      0|                    }
  356|      0|                    break;
  357|      0|                }
  358|      0|                case PrimitiveMode_TRIANGLE_FAN:
  ------------------
  |  Branch (358:17): [True: 0, False: 1]
  ------------------
  359|      0|                    nFaces = count - 2;
  360|      0|                    faces = new aiFace[nFaces];
  361|      0|                    SetFace(faces[0], data.GetUInt(0), data.GetUInt(1), data.GetUInt(2));
  362|      0|                    for (unsigned int i = 3; i < count; ++i) {
  ------------------
  |  Branch (362:46): [True: 0, False: 0]
  ------------------
  363|      0|                        SetFace(faces[i - 2], faces[0].mIndices[0], faces[i - 1].mIndices[2], data.GetUInt(i));
  364|      0|                    }
  365|      0|                    break;
  366|      1|                }
  367|      1|            } else { // no indices provided so directly generate from counts
  368|       |
  369|       |                // use the already determined count as it includes checks
  370|      0|                unsigned int count = aim->mNumVertices;
  371|       |
  372|      0|                switch (mode) {
  ------------------
  |  Branch (372:25): [True: 0, False: 0]
  ------------------
  373|      0|                case PrimitiveMode_POINTS: {
  ------------------
  |  Branch (373:17): [True: 0, False: 0]
  ------------------
  374|      0|                    nFaces = count;
  375|      0|                    faces = new aiFace[nFaces];
  376|      0|                    for (unsigned int i = 0; i < count; ++i) {
  ------------------
  |  Branch (376:46): [True: 0, False: 0]
  ------------------
  377|      0|                        SetFace(faces[i], i);
  378|      0|                    }
  379|      0|                    break;
  380|      0|                }
  381|       |
  382|      0|                case PrimitiveMode_LINES: {
  ------------------
  |  Branch (382:17): [True: 0, False: 0]
  ------------------
  383|      0|                    nFaces = count / 2;
  384|      0|                    if (nFaces * 2 != count) {
  ------------------
  |  Branch (384:25): [True: 0, False: 0]
  ------------------
  385|      0|                        ASSIMP_LOG_WARN("The number of vertices was not compatible with the LINES mode. Some vertices were dropped.");
  386|      0|                        count = nFaces * 2;
  387|      0|                    }
  388|      0|                    faces = new aiFace[nFaces];
  389|      0|                    for (unsigned int i = 0; i < count; i += 2) {
  ------------------
  |  Branch (389:46): [True: 0, False: 0]
  ------------------
  390|      0|                        SetFace(faces[i / 2], i, i + 1);
  391|      0|                    }
  392|      0|                    break;
  393|      0|                }
  394|       |
  395|      0|                case PrimitiveMode_LINE_LOOP:
  ------------------
  |  Branch (395:17): [True: 0, False: 0]
  ------------------
  396|      0|                case PrimitiveMode_LINE_STRIP: {
  ------------------
  |  Branch (396:17): [True: 0, False: 0]
  ------------------
  397|      0|                    nFaces = count - ((mode == PrimitiveMode_LINE_STRIP) ? 1 : 0);
  ------------------
  |  Branch (397:39): [True: 0, False: 0]
  ------------------
  398|      0|                    faces = new aiFace[nFaces];
  399|      0|                    SetFace(faces[0], 0, 1);
  400|      0|                    for (unsigned int i = 2; i < count; ++i) {
  ------------------
  |  Branch (400:46): [True: 0, False: 0]
  ------------------
  401|      0|                        SetFace(faces[i - 1], faces[i - 2].mIndices[1], i);
  402|      0|                    }
  403|      0|                    if (mode == PrimitiveMode_LINE_LOOP) { // close the loop
  ------------------
  |  Branch (403:25): [True: 0, False: 0]
  ------------------
  404|      0|                        SetFace(faces[count - 1], faces[count - 2].mIndices[1], faces[0].mIndices[0]);
  405|      0|                    }
  406|      0|                    break;
  407|      0|                }
  408|       |
  409|      0|                case PrimitiveMode_TRIANGLES: {
  ------------------
  |  Branch (409:17): [True: 0, False: 0]
  ------------------
  410|      0|                    nFaces = count / 3;
  411|      0|                    if (nFaces * 3 != count) {
  ------------------
  |  Branch (411:25): [True: 0, False: 0]
  ------------------
  412|      0|                        ASSIMP_LOG_WARN("The number of vertices was not compatible with the TRIANGLES mode. Some vertices were dropped.");
  413|      0|                        count = nFaces * 3;
  414|      0|                    }
  415|      0|                    faces = new aiFace[nFaces];
  416|      0|                    for (unsigned int i = 0; i < count; i += 3) {
  ------------------
  |  Branch (416:46): [True: 0, False: 0]
  ------------------
  417|      0|                        SetFace(faces[i / 3], i, i + 1, i + 2);
  418|      0|                    }
  419|      0|                    break;
  420|      0|                }
  421|      0|                case PrimitiveMode_TRIANGLE_STRIP: {
  ------------------
  |  Branch (421:17): [True: 0, False: 0]
  ------------------
  422|      0|                    nFaces = count - 2;
  423|      0|                    faces = new aiFace[nFaces];
  424|      0|                    SetFace(faces[0], 0, 1, 2);
  425|      0|                    for (unsigned int i = 3; i < count; ++i) {
  ------------------
  |  Branch (425:46): [True: 0, False: 0]
  ------------------
  426|      0|                        SetFace(faces[i - 2], faces[i - 1].mIndices[1], faces[i - 1].mIndices[2], i);
  427|      0|                    }
  428|      0|                    break;
  429|      0|                }
  430|      0|                case PrimitiveMode_TRIANGLE_FAN:
  ------------------
  |  Branch (430:17): [True: 0, False: 0]
  ------------------
  431|      0|                    nFaces = count - 2;
  432|      0|                    faces = new aiFace[nFaces];
  433|      0|                    SetFace(faces[0], 0, 1, 2);
  434|      0|                    for (unsigned int i = 3; i < count; ++i) {
  ------------------
  |  Branch (434:46): [True: 0, False: 0]
  ------------------
  435|      0|                        SetFace(faces[i - 2], faces[0].mIndices[0], faces[i - 1].mIndices[2], i);
  436|      0|                    }
  437|      0|                    break;
  438|      0|                }
  439|      0|            }
  440|       |
  441|      1|            if (faces) {
  ------------------
  |  Branch (441:17): [True: 1, False: 0]
  ------------------
  442|      1|                aim->mFaces = faces;
  443|      1|                aim->mNumFaces = nFaces;
  444|      1|                const bool validRes = CheckValidFacesIndices(faces, nFaces, aim->mNumVertices);
  445|      1|                if (!validRes) {
  ------------------
  |  Branch (445:21): [True: 0, False: 1]
  ------------------
  446|      0|                    ai_assert(validRes);
  447|      0|                    ASSIMP_LOG_WARN("Invalid number of faces detected.");
  448|      0|                }
  449|      1|            }
  450|       |
  451|      1|            if (material) {
  ------------------
  |  Branch (451:17): [True: 1, False: 0]
  ------------------
  452|      1|                aim->mMaterialIndex = material.GetIndex();
  453|      1|            }
  454|      1|        }
  455|      1|    }
  456|       |
  457|      1|    meshOffsets.push_back(k);
  458|       |
  459|      1|    CopyVector(meshes, mScene->mMeshes, mScene->mNumMeshes);
  460|      1|}
_ZNK6Assimp12glTFImporter13ImportCamerasERN4glTF5AssetE:
  462|      1|void glTFImporter::ImportCameras(Asset &r) const {
  463|      1|    if (!r.cameras.Size()) {
  ------------------
  |  Branch (463:9): [True: 1, False: 0]
  ------------------
  464|      1|        return;
  465|      1|    }
  466|       |
  467|      0|    mScene->mNumCameras = r.cameras.Size();
  468|      0|    mScene->mCameras = new aiCamera *[r.cameras.Size()];
  469|      0|    for (size_t i = 0; i < r.cameras.Size(); ++i) {
  ------------------
  |  Branch (469:24): [True: 0, False: 0]
  ------------------
  470|      0|        const Camera &cam = r.cameras[i];
  471|      0|        mScene->mCameras[i] = new aiCamera();
  472|      0|        const auto aiCameraPtr = mScene->mCameras[i];
  473|      0|        if (cam.type == Camera::Perspective) {
  ------------------
  |  Branch (473:13): [True: 0, False: 0]
  ------------------
  474|      0|            aiCameraPtr->mAspect = cam.perspective.aspectRatio;
  475|      0|            aiCameraPtr->mHorizontalFOV = cam.perspective.yfov * ((aiCameraPtr->mAspect == 0.f) ? 1.f : aiCameraPtr->mAspect);
  ------------------
  |  Branch (475:67): [True: 0, False: 0]
  ------------------
  476|      0|            aiCameraPtr->mClipPlaneFar = cam.perspective.zfar;
  477|      0|            aiCameraPtr->mClipPlaneNear = cam.perspective.znear;
  478|      0|        } else {
  479|      0|            aiCameraPtr->mClipPlaneFar = cam.ortographic.zfar;
  480|      0|            aiCameraPtr->mClipPlaneNear = cam.ortographic.znear;
  481|      0|            aiCameraPtr->mHorizontalFOV = 0.0;
  482|      0|            aiCameraPtr->mAspect = 1.0f;
  483|      0|            if (0.f != cam.ortographic.ymag) {
  ------------------
  |  Branch (483:17): [True: 0, False: 0]
  ------------------
  484|      0|                aiCameraPtr->mAspect = cam.ortographic.xmag / cam.ortographic.ymag;
  485|      0|            }
  486|      0|        }
  487|      0|    }
  488|      0|}
_ZNK6Assimp12glTFImporter12ImportLightsERN4glTF5AssetE:
  490|      1|void glTFImporter::ImportLights(Asset &r) const {
  491|      1|    if (!r.lights.Size()) {
  ------------------
  |  Branch (491:9): [True: 1, False: 0]
  ------------------
  492|      1|        return;
  493|      1|    }
  494|       |
  495|      0|    mScene->mNumLights = r.lights.Size();
  496|      0|    mScene->mLights = new aiLight *[r.lights.Size()];
  497|       |
  498|      0|    for (size_t i = 0; i < r.lights.Size(); ++i) {
  ------------------
  |  Branch (498:24): [True: 0, False: 0]
  ------------------
  499|      0|        Light &l = r.lights[i];
  500|       |
  501|      0|        aiLight *ail = mScene->mLights[i] = new aiLight();
  502|       |
  503|      0|        switch (l.type) {
  504|      0|        case Light::Type_directional:
  ------------------
  |  Branch (504:9): [True: 0, False: 0]
  ------------------
  505|      0|            ail->mType = aiLightSource_DIRECTIONAL;
  506|      0|            break;
  507|       |
  508|      0|        case Light::Type_spot:
  ------------------
  |  Branch (508:9): [True: 0, False: 0]
  ------------------
  509|      0|            ail->mType = aiLightSource_SPOT;
  510|      0|            break;
  511|       |
  512|      0|        case Light::Type_ambient:
  ------------------
  |  Branch (512:9): [True: 0, False: 0]
  ------------------
  513|      0|            ail->mType = aiLightSource_AMBIENT;
  514|      0|            break;
  515|       |
  516|      0|        default: // Light::Type_point
  ------------------
  |  Branch (516:9): [True: 0, False: 0]
  ------------------
  517|      0|            ail->mType = aiLightSource_POINT;
  518|      0|            break;
  519|      0|        }
  520|       |
  521|      0|        CopyValue(l.color, ail->mColorAmbient);
  522|      0|        CopyValue(l.color, ail->mColorDiffuse);
  523|      0|        CopyValue(l.color, ail->mColorSpecular);
  524|       |
  525|      0|        ail->mAngleOuterCone = l.falloffAngle;
  526|      0|        ail->mAngleInnerCone = l.falloffAngle * (1.0f - 1.0f / (1.0f + l.falloffExponent)); 
  527|       |
  528|      0|        ail->mAttenuationConstant = l.constantAttenuation;
  529|      0|        ail->mAttenuationLinear = l.linearAttenuation;
  530|      0|        ail->mAttenuationQuadratic = l.quadraticAttenuation;
  531|      0|    }
  532|      0|}
_Z10ImportNodeP7aiSceneRN4glTF5AssetERNSt3__16vectorIjNS4_9allocatorIjEEEERN10glTFCommon3RefINS1_4NodeEEE:
  534|      4|aiNode *ImportNode(aiScene *pScene, Asset &r, std::vector<unsigned int> &meshOffsets, Ref<Node> &ptr) {
  535|      4|    Node &node = *ptr;
  536|       |
  537|      4|    aiNode *ainode = new aiNode(node.id);
  538|       |
  539|      4|    if (!node.children.empty()) {
  ------------------
  |  Branch (539:9): [True: 2, False: 2]
  ------------------
  540|      2|        ainode->mNumChildren = static_cast<unsigned>(node.children.size());
  541|      2|        ainode->mChildren = new aiNode *[ainode->mNumChildren];
  542|       |
  543|      5|        for (unsigned int i = 0; i < ainode->mNumChildren; ++i) {
  ------------------
  |  Branch (543:34): [True: 3, False: 2]
  ------------------
  544|      3|            aiNode *child = ImportNode(pScene, r, meshOffsets, node.children[i]);
  545|      3|            child->mParent = ainode;
  546|      3|            ainode->mChildren[i] = child;
  547|      3|        }
  548|      2|    }
  549|       |
  550|      4|    aiMatrix4x4 &matrix = ainode->mTransformation;
  551|      4|    if (node.matrix.isPresent) {
  ------------------
  |  Branch (551:9): [True: 4, False: 0]
  ------------------
  552|      4|        CopyValue(node.matrix.value, matrix);
  553|      4|    } else {
  554|      0|        if (node.translation.isPresent) {
  ------------------
  |  Branch (554:13): [True: 0, False: 0]
  ------------------
  555|      0|            aiVector3D trans;
  556|      0|            CopyValue(node.translation.value, trans);
  557|      0|            aiMatrix4x4 t;
  558|      0|            aiMatrix4x4::Translation(trans, t);
  559|      0|            matrix = t * matrix;
  560|      0|        }
  561|       |
  562|      0|        if (node.scale.isPresent) {
  ------------------
  |  Branch (562:13): [True: 0, False: 0]
  ------------------
  563|      0|            aiVector3D scal(1.f);
  564|      0|            CopyValue(node.scale.value, scal);
  565|      0|            aiMatrix4x4 s;
  566|      0|            aiMatrix4x4::Scaling(scal, s);
  567|      0|            matrix = s * matrix;
  568|      0|        }
  569|       |
  570|      0|        if (node.rotation.isPresent) {
  ------------------
  |  Branch (570:13): [True: 0, False: 0]
  ------------------
  571|      0|            aiQuaternion rot;
  572|      0|            CopyValue(node.rotation.value, rot);
  573|      0|            matrix = aiMatrix4x4(rot.GetMatrix()) * matrix;
  574|      0|        }
  575|      0|    }
  576|       |
  577|      4|    if (!node.meshes.empty()) {
  ------------------
  |  Branch (577:9): [True: 1, False: 3]
  ------------------
  578|      1|        int count = 0;
  579|      2|        for (size_t i = 0; i < node.meshes.size(); ++i) {
  ------------------
  |  Branch (579:28): [True: 1, False: 1]
  ------------------
  580|      1|            const int idx = node.meshes[i].GetIndex();
  581|      1|            count += meshOffsets[idx + 1] - meshOffsets[idx];
  582|      1|        }
  583|       |
  584|      1|        ainode->mNumMeshes = count;
  585|      1|        ainode->mMeshes = new unsigned int[count];
  586|       |
  587|      1|        int k = 0;
  588|      2|        for (size_t i = 0; i < node.meshes.size(); ++i) {
  ------------------
  |  Branch (588:28): [True: 1, False: 1]
  ------------------
  589|      1|            const int idx = node.meshes[i].GetIndex();
  590|      2|            for (unsigned int j = meshOffsets[idx]; j < meshOffsets[idx + 1]; ++j, ++k) {
  ------------------
  |  Branch (590:53): [True: 1, False: 1]
  ------------------
  591|      1|                ainode->mMeshes[k] = j;
  592|      1|            }
  593|      1|        }
  594|      1|    }
  595|       |
  596|      4|    if (node.camera) {
  ------------------
  |  Branch (596:9): [True: 0, False: 4]
  ------------------
  597|      0|        pScene->mCameras[node.camera.GetIndex()]->mName = ainode->mName;
  598|      0|    }
  599|       |
  600|      4|    if (node.light) {
  ------------------
  |  Branch (600:9): [True: 0, False: 4]
  ------------------
  601|      0|        pScene->mLights[node.light.GetIndex()]->mName = ainode->mName;
  602|      0|    }
  603|       |
  604|      4|    return ainode;
  605|      4|}
_ZN6Assimp12glTFImporter11ImportNodesERN4glTF5AssetE:
  607|      1|void glTFImporter::ImportNodes(Asset &r) {
  608|      1|    if (!r.scene) {
  ------------------
  |  Branch (608:9): [True: 0, False: 1]
  ------------------
  609|      0|        return;
  610|      0|    }
  611|       |
  612|      1|    std::vector<Ref<Node>> rootNodes = r.scene->nodes;
  613|       |
  614|       |    // The root nodes
  615|      1|    if (auto numRootNodes = static_cast<unsigned>(rootNodes.size()); numRootNodes == 1) { // a single root node: use it
  ------------------
  |  Branch (615:70): [True: 1, False: 0]
  ------------------
  616|      1|        mScene->mRootNode = ImportNode(mScene, r, meshOffsets, rootNodes[0]);
  617|      1|    } else if (numRootNodes > 1) { // more than one root node: create a fake root
  ------------------
  |  Branch (617:16): [True: 0, False: 0]
  ------------------
  618|      0|        aiNode *root = new aiNode("ROOT");
  619|      0|        root->mChildren = new aiNode *[numRootNodes];
  620|      0|        for (unsigned int i = 0; i < numRootNodes; ++i) {
  ------------------
  |  Branch (620:34): [True: 0, False: 0]
  ------------------
  621|      0|            aiNode *node = ImportNode(mScene, r, meshOffsets, rootNodes[i]);
  622|      0|            node->mParent = root;
  623|      0|            root->mChildren[root->mNumChildren++] = node;
  624|      0|        }
  625|      0|        mScene->mRootNode = root;
  626|      0|    }
  627|      1|}
_ZN6Assimp12glTFImporter22ImportEmbeddedTexturesERN4glTF5AssetE:
  629|      1|void glTFImporter::ImportEmbeddedTextures(Asset &r) {
  630|      1|    embeddedTexIdxs.resize(r.images.Size(), -1);
  631|       |
  632|      1|    int numEmbeddedTexs = 0;
  633|      2|    for (size_t i = 0; i < r.images.Size(); ++i) {
  ------------------
  |  Branch (633:24): [True: 1, False: 1]
  ------------------
  634|      1|        if (r.images[i].HasData())
  ------------------
  |  Branch (634:13): [True: 1, False: 0]
  ------------------
  635|      1|            numEmbeddedTexs += 1;
  636|      1|    }
  637|       |
  638|      1|    if (numEmbeddedTexs == 0) {
  ------------------
  |  Branch (638:9): [True: 0, False: 1]
  ------------------
  639|      0|        return;
  640|      0|    }
  641|       |
  642|      1|    mScene->mTextures = new aiTexture *[numEmbeddedTexs];
  643|       |
  644|       |    // Add the embedded textures
  645|      2|    for (size_t i = 0; i < r.images.Size(); ++i) {
  ------------------
  |  Branch (645:24): [True: 1, False: 1]
  ------------------
  646|      1|        Image &img = r.images[i];
  647|      1|        if (!img.HasData()) continue;
  ------------------
  |  Branch (647:13): [True: 0, False: 1]
  ------------------
  648|       |
  649|      1|        int idx = mScene->mNumTextures++;
  650|      1|        embeddedTexIdxs[i] = idx;
  651|       |
  652|      1|        aiTexture *tex = mScene->mTextures[idx] = new aiTexture();
  653|       |
  654|      1|        const size_t length = img.GetDataLength();
  655|      1|        void *data = img.StealData();
  656|       |
  657|      1|        tex->mFilename = img.name;
  658|      1|        tex->mWidth = static_cast<unsigned int>(length);
  659|      1|        tex->mHeight = 0;
  660|      1|        tex->pcData = static_cast<aiTexel *>(data);
  661|       |
  662|      1|        if (!img.mimeType.empty()) {
  ------------------
  |  Branch (662:13): [True: 1, False: 0]
  ------------------
  663|      1|            if (const char *ext = strchr(img.mimeType.c_str(), '/') + 1) {
  ------------------
  |  Branch (663:29): [True: 1, False: 0]
  ------------------
  664|      1|                if (strncmp(ext, "jpeg", 4) == 0) {
  ------------------
  |  Branch (664:21): [True: 0, False: 1]
  ------------------
  665|      0|                    ext = "jpg";
  666|      0|                }
  667|       |
  668|      1|                tex->achFormatHint[3] = '\0';
  669|      1|                size_t len = strlen(ext);
  670|      1|                if (len > 3) len = 3;
  ------------------
  |  Branch (670:21): [True: 0, False: 1]
  ------------------
  671|      1|                memcpy(tex->achFormatHint, ext, len);
  672|      1|            }
  673|      1|        }
  674|      1|    }
  675|      1|}
_ZNK6Assimp12glTFImporter20ImportCommonMetadataERKN4glTF5AssetE:
  677|      1|void glTFImporter::ImportCommonMetadata(const Asset &a) const {
  678|      1|    ai_assert(mScene->mMetaData == nullptr);
  679|       |
  680|      1|    const bool hasVersion = !a.asset.version.empty();
  681|      1|    const bool hasGenerator = !a.asset.generator.empty();
  682|      1|    const bool hasCopyright = !a.asset.copyright.empty();
  683|      1|    if (hasVersion || hasGenerator || hasCopyright) {
  ------------------
  |  Branch (683:9): [True: 1, False: 0]
  |  Branch (683:23): [True: 0, False: 0]
  |  Branch (683:39): [True: 0, False: 0]
  ------------------
  684|      1|        mScene->mMetaData = new aiMetadata;
  685|      1|        if (hasVersion) {
  ------------------
  |  Branch (685:13): [True: 1, False: 0]
  ------------------
  686|      1|            mScene->mMetaData->Add(AI_METADATA_SOURCE_FORMAT_VERSION, aiString(a.asset.version));
  687|      1|        }
  688|      1|        if (hasGenerator) {
  ------------------
  |  Branch (688:13): [True: 1, False: 0]
  ------------------
  689|      1|            mScene->mMetaData->Add(AI_METADATA_SOURCE_GENERATOR, aiString(a.asset.generator));
  690|      1|        }
  691|      1|        if (hasCopyright) {
  ------------------
  |  Branch (691:13): [True: 0, False: 1]
  ------------------
  692|       |            mScene->mMetaData->Add(AI_METADATA_SOURCE_COPYRIGHT, aiString(a.asset.copyright));
  693|      0|        }
  694|      1|    }
  695|      1|}
_ZN6Assimp12glTFImporter14InternReadFileERKNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEP7aiScenePNS_8IOSystemE:
  697|      1|void glTFImporter::InternReadFile(const std::string &pFile, aiScene *pScene, IOSystem *pIOHandler) {
  698|       |    // clean all member arrays
  699|      1|    meshOffsets.clear();
  700|      1|    embeddedTexIdxs.clear();
  701|       |
  702|      1|    this->mScene = pScene;
  703|       |
  704|       |    // read the asset file
  705|      1|    Asset asset(pIOHandler);
  706|      1|    asset.Load(pFile,
  707|      1|               CheckMagicToken(
  708|      1|                   pIOHandler, pFile, AI_GLB_MAGIC_NUMBER, 1, 0,
  ------------------
  |  |  127|      1|#define AI_GLB_MAGIC_NUMBER "glTF"
  ------------------
  709|      1|                   static_cast<unsigned int>(strlen(AI_GLB_MAGIC_NUMBER))));
  ------------------
  |  |  127|      1|#define AI_GLB_MAGIC_NUMBER "glTF"
  ------------------
  710|       |
  711|       |    //
  712|       |    // Copy the data out
  713|       |    //
  714|       |
  715|      1|    ImportEmbeddedTextures(asset);
  716|      1|    ImportMaterials(asset);
  717|       |
  718|      1|    ImportMeshes(asset);
  719|       |
  720|      1|    ImportCameras(asset);
  721|      1|    ImportLights(asset);
  722|       |
  723|      1|    ImportNodes(asset);
  724|      1|    ImportCommonMetadata(asset);
  725|       |
  726|      1|    if (pScene->mNumMeshes == 0) {
  ------------------
  |  Branch (726:9): [True: 0, False: 1]
  ------------------
  727|       |        pScene->mFlags |= AI_SCENE_FLAGS_INCOMPLETE;
  728|      0|    }
  729|      1|}
glTFImporter.cpp:_ZN12_GLOBAL__N_124SetMaterialColorPropertyERKNSt3__16vectorIiNS0_9allocatorIiEEEERN4glTF5AssetENS7_11TexPropertyEP10aiMaterial13aiTextureTypePKcjj:
   82|      4|            aiTextureType texType, const char *pKey, unsigned int type, unsigned int idx) {
   83|      4|        if (prop.texture) {
  ------------------
  |  Branch (83:13): [True: 1, False: 3]
  ------------------
   84|      1|            if (prop.texture->source) {
  ------------------
  |  Branch (84:17): [True: 1, False: 0]
  ------------------
   85|      1|                aiString uri(prop.texture->source->uri);
   86|       |
   87|      1|                if (const int texIdx = embeddedTexIdxs[prop.texture->source.GetIndex()]; texIdx != -1) { // embedded
  ------------------
  |  Branch (87:90): [True: 1, False: 0]
  ------------------
   88|       |                    // setup texture reference string (copied from ColladaLoader::FindFilenameForEffectTexture)
   89|      1|                    uri.data[0] = '*';
   90|      1|                    uri.length = 1 + ASSIMP_itoa10(uri.data + 1, AI_MAXLEN - 1, texIdx);
   91|      1|                }
   92|       |
   93|      1|                mat->AddProperty(&uri, _AI_MATKEY_TEXTURE_BASE, texType, 0);
   94|      1|            }
   95|      1|            return;
   96|      1|        }
   97|       |
   98|      3|        aiColor4D col;
   99|      3|        CopyValue(prop.color, col);
  100|      3|        mat->AddProperty(&col, 1, pKey, type, idx);
  101|      3|    }
glTFImporter.cpp:_ZN12_GLOBAL__N_17SetFaceER6aiFaceiii:
  116|     12|    void SetFace(aiFace &face, int a, int b, int c) {
  117|     12|        face.mNumIndices = 3;
  118|     12|        face.mIndices = new unsigned int[3];
  119|     12|        face.mIndices[0] = a;
  120|     12|        face.mIndices[1] = b;
  121|     12|        face.mIndices[2] = c;
  122|     12|    }
glTFImporter.cpp:_ZN12_GLOBAL__N_122CheckValidFacesIndicesEPK6aiFacejj:
  124|      1|    bool CheckValidFacesIndices(const aiFace *faces, unsigned nFaces, unsigned nVerts) {
  125|     13|        for (unsigned i = 0; i < nFaces; ++i) {
  ------------------
  |  Branch (125:30): [True: 12, False: 1]
  ------------------
  126|     48|            for (unsigned j = 0; j < faces[i].mNumIndices; ++j) {
  ------------------
  |  Branch (126:34): [True: 36, False: 12]
  ------------------
  127|     36|                unsigned idx = faces[i].mIndices[j];
  128|     36|                if (idx >= nVerts)
  ------------------
  |  Branch (128:21): [True: 0, False: 36]
  ------------------
  129|      0|                    return false;
  130|     36|            }
  131|     12|        }
  132|      1|        return true;
  133|      1|    }

_ZN6Assimp12glTFImporterD2Ev:
   64|    624|    ~glTFImporter() override = default;

_ZN5glTF26ObjectD2Ev:
  394|     77|    virtual ~Object() = default;
_ZN5glTF215CustomExtensionD2Ev:
  367|     81|    ~CustomExtension() = default;
_ZN5glTF25AssetC2EPN6Assimp8IOSystemEPN9rapidjson36IGenericRemoteSchemaDocumentProviderINS4_21GenericSchemaDocumentINS4_12GenericValueINS4_4UTF8IcEENS4_19MemoryPoolAllocatorINS4_12CrtAllocatorEEEEESB_EEEE:
 1179|     53|            mDicts(),
 1180|     53|            extensionsUsed(),
 1181|     53|            extensionsRequired(),
 1182|     53|            asset(),
 1183|     53|            extras(nullptr),
 1184|     53|            accessors(*this, "accessors"),
 1185|     53|            animations(*this, "animations"),
 1186|     53|            buffers(*this, "buffers"),
 1187|     53|            bufferViews(*this, "bufferViews"),
 1188|     53|            cameras(*this, "cameras"),
 1189|     53|            lights(*this, "lights", "KHR_lights_punctual"),
 1190|     53|            images(*this, "images"),
 1191|     53|            materials(*this, "materials"),
 1192|     53|            meshes(*this, "meshes"),
 1193|     53|            nodes(*this, "nodes"),
 1194|     53|            samplers(*this, "samplers"),
 1195|     53|            scenes(*this, "scenes"),
 1196|     53|            skins(*this, "skins"),
 1197|     53|            textures(*this, "textures") ,
 1198|     53|            mIOSystem(io),
 1199|     53|            mSchemaDocumentProvider(schemaDocumentProvider) {
 1200|       |        // empty
 1201|     53|    }
_ZN5glTF25Asset10ExtensionsC2Ev:
 1142|     53|        Extensions() = default;
_ZN5glTF25Asset18RequiredExtensionsC2Ev:
 1152|     53|        RequiredExtensions() = default;
_ZN5glTF213AssetMetadataC2Ev:
 1104|     53|    AssetMetadata() = default;
_ZN5glTF212LazyDictBaseD2Ev:
 1026|    742|    virtual ~LazyDictBase() = default;
_ZN5glTF215CustomExtensionC2Ev:
  366|     81|    CustomExtension() = default;
_ZN5glTF26Buffer13MarkAsSpecialEv:
  522|      1|    void MarkAsSpecial() { mIsSpecial = true; }
_ZN5glTF221PbrSpecularGlossinessC2Ev:
  754|      6|    PbrSpecularGlossiness() { SetDefaults(); }
_ZN5glTF216MaterialSpecularC2Ev:
  764|      6|    MaterialSpecular() { SetDefaults(); }
_ZN5glTF213MaterialSheenC2Ev:
  774|      6|    MaterialSheen() { SetDefaults(); }
_ZN5glTF214MaterialVolumeC2Ev:
  797|      6|    MaterialVolume() { SetDefaults(); }
_ZN5glTF211MaterialIORC2Ev:
  804|      6|    MaterialIOR() { SetDefaults(); }
_ZN5glTF224MaterialEmissiveStrengthC2Ev:
  811|      6|    MaterialEmissiveStrength() { SetDefaults(); }
_ZN5glTF218MaterialAnisotropyC2Ev:
  820|      6|    MaterialAnisotropy() { SetDefaults(); }
_ZN5glTF210AttribType16GetNumComponentsENS0_5ValueE:
  321|     36|    inline static unsigned int GetNumComponents(Value type) {
  322|     36|        return data<0>::infos[static_cast<size_t>(type)].numComponents;
  323|     36|    }
_ZN5glTF28AccessorC2Ev:
  609|     20|    Accessor() = default;
_ZN5glTF217ComponentTypeSizeENS_13ComponentTypeE:
  197|     36|inline unsigned int ComponentTypeSize(ComponentType t) {
  198|     36|    switch (t) {
  199|      0|    case ComponentType_SHORT:
  ------------------
  |  Branch (199:5): [True: 0, False: 36]
  ------------------
  200|      0|    case ComponentType_UNSIGNED_SHORT:
  ------------------
  |  Branch (200:5): [True: 0, False: 36]
  ------------------
  201|      0|        return 2;
  202|       |
  203|      0|    case ComponentType_UNSIGNED_INT:
  ------------------
  |  Branch (203:5): [True: 0, False: 36]
  ------------------
  204|     24|    case ComponentType_FLOAT:
  ------------------
  |  Branch (204:5): [True: 24, False: 12]
  ------------------
  205|     24|        return 4;
  206|       |
  207|      0|    case ComponentType_BYTE:
  ------------------
  |  Branch (207:5): [True: 0, False: 36]
  ------------------
  208|     12|    case ComponentType_UNSIGNED_BYTE:
  ------------------
  |  Branch (208:5): [True: 12, False: 24]
  ------------------
  209|     12|        return 1;
  210|      0|    default:
  ------------------
  |  Branch (210:5): [True: 0, False: 36]
  ------------------
  211|      0|        throw DeadlyImportError("GLTF: Unsupported Component Type ", ai_to_string(t));
  212|     36|    }
  213|     36|}
_ZN5glTF24Mesh9PrimitiveC2Ev:
  901|      9|        Primitive(): ngonEncoded(false) {}
_ZN5glTF27SamplerC2Ev:
  950|      1|    Sampler() { SetDefaults(); }
_ZN5glTF27TextureC2Ev:
  989|      2|    Texture() = default;
_ZN5glTF28MaterialC2Ev:
  868|      6|    Material() { SetDefaults(); }
_ZN5glTF24MeshC2Ev:
  909|      8|    Mesh() = default;
_ZN5glTF24NodeC2Ev:
  935|      9|    Node() = default;
_ZN5glTF25SceneC2Ev:
  959|      4|    Scene() = default;
_ZN5glTF210AttribType10FromStringEPKc:
  308|     18|    inline static Value FromString(const char *str) {
  309|     40|        for (size_t i = 0; i < NUM_VALUES; ++i) {
  ------------------
  |  Branch (309:28): [True: 40, False: 0]
  ------------------
  310|     40|            if (strcmp(data<0>::infos[i].name, str) == 0) {
  ------------------
  |  Branch (310:17): [True: 18, False: 22]
  ------------------
  311|     18|                return static_cast<Value>(i);
  312|     18|            }
  313|     40|        }
  314|      0|        return SCALAR;
  315|     18|    }

_ZN5glTF26BufferD2Ev:
  565|      5|inline Buffer::~Buffer() {
  566|      5|    for (SEncodedRegion *reg : EncodedRegion_List) delete reg;
  ------------------
  |  Branch (566:30): [True: 0, False: 5]
  ------------------
  567|      5|}
_ZN5glTF28LazyDictINS_8AccessorEEC2ERNS_5AssetEPKcS6_:
  390|     53|        mDictId(dictId),
  391|     53|        mExtId(extId),
  392|     53|        mDict(nullptr),
  393|     53|        mAsset(asset) {
  394|     53|    asset.mDicts.push_back(this); // register to the list of dictionaries
  395|     53|}
_ZN5glTF28LazyDictINS_8AccessorEE16AttachToDocumentERN9rapidjson15GenericDocumentINS3_4UTF8IcEENS3_19MemoryPoolAllocatorINS3_12CrtAllocatorEEES8_EE:
  405|      4|inline void LazyDict<T>::AttachToDocument(Document &doc) {
  406|      4|    Value *container = nullptr;
  407|      4|    const char *context = nullptr;
  408|       |
  409|      4|    if (mExtId) {
  ------------------
  |  Branch (409:9): [True: 0, False: 4]
  ------------------
  410|      0|        if (Value *exts = FindObject(doc, "extensions")) {
  ------------------
  |  Branch (410:20): [True: 0, False: 0]
  ------------------
  411|      0|            container = FindObjectInContext(*exts, mExtId, "extensions");
  412|      0|            context = mExtId;
  413|      0|        }
  414|      4|    } else {
  415|      4|        container = &doc;
  416|      4|        context = "the document";
  417|      4|    }
  418|       |
  419|      4|    if (container) {
  ------------------
  |  Branch (419:9): [True: 4, False: 0]
  ------------------
  420|      4|        mDict = FindArrayInContext(*container, mDictId, context);
  421|      4|    }
  422|      4|}
_ZN5glTF28LazyDictINS_9AnimationEEC2ERNS_5AssetEPKcS6_:
  390|     53|        mDictId(dictId),
  391|     53|        mExtId(extId),
  392|     53|        mDict(nullptr),
  393|     53|        mAsset(asset) {
  394|     53|    asset.mDicts.push_back(this); // register to the list of dictionaries
  395|     53|}
_ZN5glTF28LazyDictINS_9AnimationEE16AttachToDocumentERN9rapidjson15GenericDocumentINS3_4UTF8IcEENS3_19MemoryPoolAllocatorINS3_12CrtAllocatorEEES8_EE:
  405|      4|inline void LazyDict<T>::AttachToDocument(Document &doc) {
  406|      4|    Value *container = nullptr;
  407|      4|    const char *context = nullptr;
  408|       |
  409|      4|    if (mExtId) {
  ------------------
  |  Branch (409:9): [True: 0, False: 4]
  ------------------
  410|      0|        if (Value *exts = FindObject(doc, "extensions")) {
  ------------------
  |  Branch (410:20): [True: 0, False: 0]
  ------------------
  411|      0|            container = FindObjectInContext(*exts, mExtId, "extensions");
  412|      0|            context = mExtId;
  413|      0|        }
  414|      4|    } else {
  415|      4|        container = &doc;
  416|      4|        context = "the document";
  417|      4|    }
  418|       |
  419|      4|    if (container) {
  ------------------
  |  Branch (419:9): [True: 4, False: 0]
  ------------------
  420|      4|        mDict = FindArrayInContext(*container, mDictId, context);
  421|      4|    }
  422|      4|}
_ZN5glTF28LazyDictINS_6BufferEEC2ERNS_5AssetEPKcS6_:
  390|     53|        mDictId(dictId),
  391|     53|        mExtId(extId),
  392|     53|        mDict(nullptr),
  393|     53|        mAsset(asset) {
  394|     53|    asset.mDicts.push_back(this); // register to the list of dictionaries
  395|     53|}
_ZN5glTF28LazyDictINS_6BufferEE16AttachToDocumentERN9rapidjson15GenericDocumentINS3_4UTF8IcEENS3_19MemoryPoolAllocatorINS3_12CrtAllocatorEEES8_EE:
  405|      4|inline void LazyDict<T>::AttachToDocument(Document &doc) {
  406|      4|    Value *container = nullptr;
  407|      4|    const char *context = nullptr;
  408|       |
  409|      4|    if (mExtId) {
  ------------------
  |  Branch (409:9): [True: 0, False: 4]
  ------------------
  410|      0|        if (Value *exts = FindObject(doc, "extensions")) {
  ------------------
  |  Branch (410:20): [True: 0, False: 0]
  ------------------
  411|      0|            container = FindObjectInContext(*exts, mExtId, "extensions");
  412|      0|            context = mExtId;
  413|      0|        }
  414|      4|    } else {
  415|      4|        container = &doc;
  416|      4|        context = "the document";
  417|      4|    }
  418|       |
  419|      4|    if (container) {
  ------------------
  |  Branch (419:9): [True: 4, False: 0]
  ------------------
  420|      4|        mDict = FindArrayInContext(*container, mDictId, context);
  421|      4|    }
  422|      4|}
_ZN5glTF28LazyDictINS_10BufferViewEEC2ERNS_5AssetEPKcS6_:
  390|     53|        mDictId(dictId),
  391|     53|        mExtId(extId),
  392|     53|        mDict(nullptr),
  393|     53|        mAsset(asset) {
  394|     53|    asset.mDicts.push_back(this); // register to the list of dictionaries
  395|     53|}
_ZN5glTF28LazyDictINS_10BufferViewEE16AttachToDocumentERN9rapidjson15GenericDocumentINS3_4UTF8IcEENS3_19MemoryPoolAllocatorINS3_12CrtAllocatorEEES8_EE:
  405|      4|inline void LazyDict<T>::AttachToDocument(Document &doc) {
  406|      4|    Value *container = nullptr;
  407|      4|    const char *context = nullptr;
  408|       |
  409|      4|    if (mExtId) {
  ------------------
  |  Branch (409:9): [True: 0, False: 4]
  ------------------
  410|      0|        if (Value *exts = FindObject(doc, "extensions")) {
  ------------------
  |  Branch (410:20): [True: 0, False: 0]
  ------------------
  411|      0|            container = FindObjectInContext(*exts, mExtId, "extensions");
  412|      0|            context = mExtId;
  413|      0|        }
  414|      4|    } else {
  415|      4|        container = &doc;
  416|      4|        context = "the document";
  417|      4|    }
  418|       |
  419|      4|    if (container) {
  ------------------
  |  Branch (419:9): [True: 4, False: 0]
  ------------------
  420|      4|        mDict = FindArrayInContext(*container, mDictId, context);
  421|      4|    }
  422|      4|}
_ZN5glTF28LazyDictINS_6CameraEEC2ERNS_5AssetEPKcS6_:
  390|     53|        mDictId(dictId),
  391|     53|        mExtId(extId),
  392|     53|        mDict(nullptr),
  393|     53|        mAsset(asset) {
  394|     53|    asset.mDicts.push_back(this); // register to the list of dictionaries
  395|     53|}
_ZN5glTF28LazyDictINS_6CameraEE16AttachToDocumentERN9rapidjson15GenericDocumentINS3_4UTF8IcEENS3_19MemoryPoolAllocatorINS3_12CrtAllocatorEEES8_EE:
  405|      4|inline void LazyDict<T>::AttachToDocument(Document &doc) {
  406|      4|    Value *container = nullptr;
  407|      4|    const char *context = nullptr;
  408|       |
  409|      4|    if (mExtId) {
  ------------------
  |  Branch (409:9): [True: 0, False: 4]
  ------------------
  410|      0|        if (Value *exts = FindObject(doc, "extensions")) {
  ------------------
  |  Branch (410:20): [True: 0, False: 0]
  ------------------
  411|      0|            container = FindObjectInContext(*exts, mExtId, "extensions");
  412|      0|            context = mExtId;
  413|      0|        }
  414|      4|    } else {
  415|      4|        container = &doc;
  416|      4|        context = "the document";
  417|      4|    }
  418|       |
  419|      4|    if (container) {
  ------------------
  |  Branch (419:9): [True: 4, False: 0]
  ------------------
  420|      4|        mDict = FindArrayInContext(*container, mDictId, context);
  421|      4|    }
  422|      4|}
_ZN5glTF28LazyDictINS_5LightEEC2ERNS_5AssetEPKcS6_:
  390|     53|        mDictId(dictId),
  391|     53|        mExtId(extId),
  392|     53|        mDict(nullptr),
  393|     53|        mAsset(asset) {
  394|     53|    asset.mDicts.push_back(this); // register to the list of dictionaries
  395|     53|}
_ZN5glTF28LazyDictINS_5LightEE16AttachToDocumentERN9rapidjson15GenericDocumentINS3_4UTF8IcEENS3_19MemoryPoolAllocatorINS3_12CrtAllocatorEEES8_EE:
  405|      4|inline void LazyDict<T>::AttachToDocument(Document &doc) {
  406|      4|    Value *container = nullptr;
  407|      4|    const char *context = nullptr;
  408|       |
  409|      4|    if (mExtId) {
  ------------------
  |  Branch (409:9): [True: 4, False: 0]
  ------------------
  410|      4|        if (Value *exts = FindObject(doc, "extensions")) {
  ------------------
  |  Branch (410:20): [True: 0, False: 4]
  ------------------
  411|      0|            container = FindObjectInContext(*exts, mExtId, "extensions");
  412|      0|            context = mExtId;
  413|      0|        }
  414|      4|    } else {
  415|      0|        container = &doc;
  416|      0|        context = "the document";
  417|      0|    }
  418|       |
  419|      4|    if (container) {
  ------------------
  |  Branch (419:9): [True: 0, False: 4]
  ------------------
  420|      0|        mDict = FindArrayInContext(*container, mDictId, context);
  421|      0|    }
  422|      4|}
_ZN5glTF28LazyDictINS_5ImageEEC2ERNS_5AssetEPKcS6_:
  390|     53|        mDictId(dictId),
  391|     53|        mExtId(extId),
  392|     53|        mDict(nullptr),
  393|     53|        mAsset(asset) {
  394|     53|    asset.mDicts.push_back(this); // register to the list of dictionaries
  395|     53|}
_ZN5glTF28LazyDictINS_5ImageEE16AttachToDocumentERN9rapidjson15GenericDocumentINS3_4UTF8IcEENS3_19MemoryPoolAllocatorINS3_12CrtAllocatorEEES8_EE:
  405|      4|inline void LazyDict<T>::AttachToDocument(Document &doc) {
  406|      4|    Value *container = nullptr;
  407|      4|    const char *context = nullptr;
  408|       |
  409|      4|    if (mExtId) {
  ------------------
  |  Branch (409:9): [True: 0, False: 4]
  ------------------
  410|      0|        if (Value *exts = FindObject(doc, "extensions")) {
  ------------------
  |  Branch (410:20): [True: 0, False: 0]
  ------------------
  411|      0|            container = FindObjectInContext(*exts, mExtId, "extensions");
  412|      0|            context = mExtId;
  413|      0|        }
  414|      4|    } else {
  415|      4|        container = &doc;
  416|      4|        context = "the document";
  417|      4|    }
  418|       |
  419|      4|    if (container) {
  ------------------
  |  Branch (419:9): [True: 4, False: 0]
  ------------------
  420|      4|        mDict = FindArrayInContext(*container, mDictId, context);
  421|      4|    }
  422|      4|}
_ZN5glTF28LazyDictINS_8MaterialEEC2ERNS_5AssetEPKcS6_:
  390|     53|        mDictId(dictId),
  391|     53|        mExtId(extId),
  392|     53|        mDict(nullptr),
  393|     53|        mAsset(asset) {
  394|     53|    asset.mDicts.push_back(this); // register to the list of dictionaries
  395|     53|}
_ZN5glTF28LazyDictINS_8MaterialEE16AttachToDocumentERN9rapidjson15GenericDocumentINS3_4UTF8IcEENS3_19MemoryPoolAllocatorINS3_12CrtAllocatorEEES8_EE:
  405|      4|inline void LazyDict<T>::AttachToDocument(Document &doc) {
  406|      4|    Value *container = nullptr;
  407|      4|    const char *context = nullptr;
  408|       |
  409|      4|    if (mExtId) {
  ------------------
  |  Branch (409:9): [True: 0, False: 4]
  ------------------
  410|      0|        if (Value *exts = FindObject(doc, "extensions")) {
  ------------------
  |  Branch (410:20): [True: 0, False: 0]
  ------------------
  411|      0|            container = FindObjectInContext(*exts, mExtId, "extensions");
  412|      0|            context = mExtId;
  413|      0|        }
  414|      4|    } else {
  415|      4|        container = &doc;
  416|      4|        context = "the document";
  417|      4|    }
  418|       |
  419|      4|    if (container) {
  ------------------
  |  Branch (419:9): [True: 4, False: 0]
  ------------------
  420|      4|        mDict = FindArrayInContext(*container, mDictId, context);
  421|      4|    }
  422|      4|}
_ZN5glTF28LazyDictINS_4MeshEEC2ERNS_5AssetEPKcS6_:
  390|     53|        mDictId(dictId),
  391|     53|        mExtId(extId),
  392|     53|        mDict(nullptr),
  393|     53|        mAsset(asset) {
  394|     53|    asset.mDicts.push_back(this); // register to the list of dictionaries
  395|     53|}
_ZN5glTF28LazyDictINS_4MeshEE16AttachToDocumentERN9rapidjson15GenericDocumentINS3_4UTF8IcEENS3_19MemoryPoolAllocatorINS3_12CrtAllocatorEEES8_EE:
  405|      4|inline void LazyDict<T>::AttachToDocument(Document &doc) {
  406|      4|    Value *container = nullptr;
  407|      4|    const char *context = nullptr;
  408|       |
  409|      4|    if (mExtId) {
  ------------------
  |  Branch (409:9): [True: 0, False: 4]
  ------------------
  410|      0|        if (Value *exts = FindObject(doc, "extensions")) {
  ------------------
  |  Branch (410:20): [True: 0, False: 0]
  ------------------
  411|      0|            container = FindObjectInContext(*exts, mExtId, "extensions");
  412|      0|            context = mExtId;
  413|      0|        }
  414|      4|    } else {
  415|      4|        container = &doc;
  416|      4|        context = "the document";
  417|      4|    }
  418|       |
  419|      4|    if (container) {
  ------------------
  |  Branch (419:9): [True: 4, False: 0]
  ------------------
  420|      4|        mDict = FindArrayInContext(*container, mDictId, context);
  421|      4|    }
  422|      4|}
_ZN5glTF28LazyDictINS_4NodeEEC2ERNS_5AssetEPKcS6_:
  390|     53|        mDictId(dictId),
  391|     53|        mExtId(extId),
  392|     53|        mDict(nullptr),
  393|     53|        mAsset(asset) {
  394|     53|    asset.mDicts.push_back(this); // register to the list of dictionaries
  395|     53|}
_ZN5glTF28LazyDictINS_4NodeEE16AttachToDocumentERN9rapidjson15GenericDocumentINS3_4UTF8IcEENS3_19MemoryPoolAllocatorINS3_12CrtAllocatorEEES8_EE:
  405|      4|inline void LazyDict<T>::AttachToDocument(Document &doc) {
  406|      4|    Value *container = nullptr;
  407|      4|    const char *context = nullptr;
  408|       |
  409|      4|    if (mExtId) {
  ------------------
  |  Branch (409:9): [True: 0, False: 4]
  ------------------
  410|      0|        if (Value *exts = FindObject(doc, "extensions")) {
  ------------------
  |  Branch (410:20): [True: 0, False: 0]
  ------------------
  411|      0|            container = FindObjectInContext(*exts, mExtId, "extensions");
  412|      0|            context = mExtId;
  413|      0|        }
  414|      4|    } else {
  415|      4|        container = &doc;
  416|      4|        context = "the document";
  417|      4|    }
  418|       |
  419|      4|    if (container) {
  ------------------
  |  Branch (419:9): [True: 4, False: 0]
  ------------------
  420|      4|        mDict = FindArrayInContext(*container, mDictId, context);
  421|      4|    }
  422|      4|}
_ZN5glTF28LazyDictINS_7SamplerEEC2ERNS_5AssetEPKcS6_:
  390|     53|        mDictId(dictId),
  391|     53|        mExtId(extId),
  392|     53|        mDict(nullptr),
  393|     53|        mAsset(asset) {
  394|     53|    asset.mDicts.push_back(this); // register to the list of dictionaries
  395|     53|}
_ZN5glTF28LazyDictINS_7SamplerEE16AttachToDocumentERN9rapidjson15GenericDocumentINS3_4UTF8IcEENS3_19MemoryPoolAllocatorINS3_12CrtAllocatorEEES8_EE:
  405|      4|inline void LazyDict<T>::AttachToDocument(Document &doc) {
  406|      4|    Value *container = nullptr;
  407|      4|    const char *context = nullptr;
  408|       |
  409|      4|    if (mExtId) {
  ------------------
  |  Branch (409:9): [True: 0, False: 4]
  ------------------
  410|      0|        if (Value *exts = FindObject(doc, "extensions")) {
  ------------------
  |  Branch (410:20): [True: 0, False: 0]
  ------------------
  411|      0|            container = FindObjectInContext(*exts, mExtId, "extensions");
  412|      0|            context = mExtId;
  413|      0|        }
  414|      4|    } else {
  415|      4|        container = &doc;
  416|      4|        context = "the document";
  417|      4|    }
  418|       |
  419|      4|    if (container) {
  ------------------
  |  Branch (419:9): [True: 4, False: 0]
  ------------------
  420|      4|        mDict = FindArrayInContext(*container, mDictId, context);
  421|      4|    }
  422|      4|}
_ZN5glTF28LazyDictINS_5SceneEEC2ERNS_5AssetEPKcS6_:
  390|     53|        mDictId(dictId),
  391|     53|        mExtId(extId),
  392|     53|        mDict(nullptr),
  393|     53|        mAsset(asset) {
  394|     53|    asset.mDicts.push_back(this); // register to the list of dictionaries
  395|     53|}
_ZN5glTF28LazyDictINS_5SceneEE16AttachToDocumentERN9rapidjson15GenericDocumentINS3_4UTF8IcEENS3_19MemoryPoolAllocatorINS3_12CrtAllocatorEEES8_EE:
  405|      4|inline void LazyDict<T>::AttachToDocument(Document &doc) {
  406|      4|    Value *container = nullptr;
  407|      4|    const char *context = nullptr;
  408|       |
  409|      4|    if (mExtId) {
  ------------------
  |  Branch (409:9): [True: 0, False: 4]
  ------------------
  410|      0|        if (Value *exts = FindObject(doc, "extensions")) {
  ------------------
  |  Branch (410:20): [True: 0, False: 0]
  ------------------
  411|      0|            container = FindObjectInContext(*exts, mExtId, "extensions");
  412|      0|            context = mExtId;
  413|      0|        }
  414|      4|    } else {
  415|      4|        container = &doc;
  416|      4|        context = "the document";
  417|      4|    }
  418|       |
  419|      4|    if (container) {
  ------------------
  |  Branch (419:9): [True: 4, False: 0]
  ------------------
  420|      4|        mDict = FindArrayInContext(*container, mDictId, context);
  421|      4|    }
  422|      4|}
_ZN5glTF28LazyDictINS_4SkinEEC2ERNS_5AssetEPKcS6_:
  390|     53|        mDictId(dictId),
  391|     53|        mExtId(extId),
  392|     53|        mDict(nullptr),
  393|     53|        mAsset(asset) {
  394|     53|    asset.mDicts.push_back(this); // register to the list of dictionaries
  395|     53|}
_ZN5glTF28LazyDictINS_4SkinEE16AttachToDocumentERN9rapidjson15GenericDocumentINS3_4UTF8IcEENS3_19MemoryPoolAllocatorINS3_12CrtAllocatorEEES8_EE:
  405|      4|inline void LazyDict<T>::AttachToDocument(Document &doc) {
  406|      4|    Value *container = nullptr;
  407|      4|    const char *context = nullptr;
  408|       |
  409|      4|    if (mExtId) {
  ------------------
  |  Branch (409:9): [True: 0, False: 4]
  ------------------
  410|      0|        if (Value *exts = FindObject(doc, "extensions")) {
  ------------------
  |  Branch (410:20): [True: 0, False: 0]
  ------------------
  411|      0|            container = FindObjectInContext(*exts, mExtId, "extensions");
  412|      0|            context = mExtId;
  413|      0|        }
  414|      4|    } else {
  415|      4|        container = &doc;
  416|      4|        context = "the document";
  417|      4|    }
  418|       |
  419|      4|    if (container) {
  ------------------
  |  Branch (419:9): [True: 4, False: 0]
  ------------------
  420|      4|        mDict = FindArrayInContext(*container, mDictId, context);
  421|      4|    }
  422|      4|}
_ZN5glTF28LazyDictINS_7TextureEEC2ERNS_5AssetEPKcS6_:
  390|     53|        mDictId(dictId),
  391|     53|        mExtId(extId),
  392|     53|        mDict(nullptr),
  393|     53|        mAsset(asset) {
  394|     53|    asset.mDicts.push_back(this); // register to the list of dictionaries
  395|     53|}
_ZN5glTF28LazyDictINS_7TextureEE16AttachToDocumentERN9rapidjson15GenericDocumentINS3_4UTF8IcEENS3_19MemoryPoolAllocatorINS3_12CrtAllocatorEEES8_EE:
  405|      4|inline void LazyDict<T>::AttachToDocument(Document &doc) {
  406|      4|    Value *container = nullptr;
  407|      4|    const char *context = nullptr;
  408|       |
  409|      4|    if (mExtId) {
  ------------------
  |  Branch (409:9): [True: 0, False: 4]
  ------------------
  410|      0|        if (Value *exts = FindObject(doc, "extensions")) {
  ------------------
  |  Branch (410:20): [True: 0, False: 0]
  ------------------
  411|      0|            container = FindObjectInContext(*exts, mExtId, "extensions");
  412|      0|            context = mExtId;
  413|      0|        }
  414|      4|    } else {
  415|      4|        container = &doc;
  416|      4|        context = "the document";
  417|      4|    }
  418|       |
  419|      4|    if (container) {
  ------------------
  |  Branch (419:9): [True: 4, False: 0]
  ------------------
  420|      4|        mDict = FindArrayInContext(*container, mDictId, context);
  421|      4|    }
  422|      4|}
_ZN5glTF28LazyDictINS_7TextureEED2Ev:
  398|     53|inline LazyDict<T>::~LazyDict() {
  399|     54|    for (size_t i = 0; i < mObjs.size(); ++i) {
  ------------------
  |  Branch (399:24): [True: 1, False: 53]
  ------------------
  400|      1|        delete mObjs[i];
  401|      1|    }
  402|     53|}
_ZN5glTF28LazyDictINS_4SkinEED2Ev:
  398|     53|inline LazyDict<T>::~LazyDict() {
  399|     53|    for (size_t i = 0; i < mObjs.size(); ++i) {
  ------------------
  |  Branch (399:24): [True: 0, False: 53]
  ------------------
  400|      0|        delete mObjs[i];
  401|      0|    }
  402|     53|}
_ZN5glTF28LazyDictINS_5SceneEED2Ev:
  398|     53|inline LazyDict<T>::~LazyDict() {
  399|     53|    for (size_t i = 0; i < mObjs.size(); ++i) {
  ------------------
  |  Branch (399:24): [True: 0, False: 53]
  ------------------
  400|      0|        delete mObjs[i];
  401|      0|    }
  402|     53|}
_ZN5glTF28LazyDictINS_7SamplerEED2Ev:
  398|     53|inline LazyDict<T>::~LazyDict() {
  399|     54|    for (size_t i = 0; i < mObjs.size(); ++i) {
  ------------------
  |  Branch (399:24): [True: 1, False: 53]
  ------------------
  400|      1|        delete mObjs[i];
  401|      1|    }
  402|     53|}
_ZN5glTF28LazyDictINS_4NodeEED2Ev:
  398|     53|inline LazyDict<T>::~LazyDict() {
  399|     57|    for (size_t i = 0; i < mObjs.size(); ++i) {
  ------------------
  |  Branch (399:24): [True: 4, False: 53]
  ------------------
  400|      4|        delete mObjs[i];
  401|      4|    }
  402|     53|}
_ZN5glTF28LazyDictINS_4MeshEED2Ev:
  398|     53|inline LazyDict<T>::~LazyDict() {
  399|     57|    for (size_t i = 0; i < mObjs.size(); ++i) {
  ------------------
  |  Branch (399:24): [True: 4, False: 53]
  ------------------
  400|      4|        delete mObjs[i];
  401|      4|    }
  402|     53|}
_ZN5glTF28LazyDictINS_8MaterialEED2Ev:
  398|     53|inline LazyDict<T>::~LazyDict() {
  399|     58|    for (size_t i = 0; i < mObjs.size(); ++i) {
  ------------------
  |  Branch (399:24): [True: 5, False: 53]
  ------------------
  400|      5|        delete mObjs[i];
  401|      5|    }
  402|     53|}
_ZN5glTF28LazyDictINS_5ImageEED2Ev:
  398|     53|inline LazyDict<T>::~LazyDict() {
  399|     54|    for (size_t i = 0; i < mObjs.size(); ++i) {
  ------------------
  |  Branch (399:24): [True: 1, False: 53]
  ------------------
  400|      1|        delete mObjs[i];
  401|      1|    }
  402|     53|}
_ZN5glTF28LazyDictINS_5LightEED2Ev:
  398|     53|inline LazyDict<T>::~LazyDict() {
  399|     53|    for (size_t i = 0; i < mObjs.size(); ++i) {
  ------------------
  |  Branch (399:24): [True: 0, False: 53]
  ------------------
  400|      0|        delete mObjs[i];
  401|      0|    }
  402|     53|}
_ZN5glTF28LazyDictINS_6CameraEED2Ev:
  398|     53|inline LazyDict<T>::~LazyDict() {
  399|     53|    for (size_t i = 0; i < mObjs.size(); ++i) {
  ------------------
  |  Branch (399:24): [True: 0, False: 53]
  ------------------
  400|      0|        delete mObjs[i];
  401|      0|    }
  402|     53|}
_ZN5glTF28LazyDictINS_10BufferViewEED2Ev:
  398|     53|inline LazyDict<T>::~LazyDict() {
  399|     71|    for (size_t i = 0; i < mObjs.size(); ++i) {
  ------------------
  |  Branch (399:24): [True: 18, False: 53]
  ------------------
  400|     18|        delete mObjs[i];
  401|     18|    }
  402|     53|}
_ZN5glTF28LazyDictINS_6BufferEED2Ev:
  398|     53|inline LazyDict<T>::~LazyDict() {
  399|     56|    for (size_t i = 0; i < mObjs.size(); ++i) {
  ------------------
  |  Branch (399:24): [True: 3, False: 53]
  ------------------
  400|      3|        delete mObjs[i];
  401|      3|    }
  402|     53|}
_ZN5glTF28LazyDictINS_9AnimationEED2Ev:
  398|     53|inline LazyDict<T>::~LazyDict() {
  399|     53|    for (size_t i = 0; i < mObjs.size(); ++i) {
  ------------------
  |  Branch (399:24): [True: 0, False: 53]
  ------------------
  400|      0|        delete mObjs[i];
  401|      0|    }
  402|     53|}
_ZN5glTF28LazyDictINS_8AccessorEED2Ev:
  398|     53|inline LazyDict<T>::~LazyDict() {
  399|     71|    for (size_t i = 0; i < mObjs.size(); ++i) {
  ------------------
  |  Branch (399:24): [True: 18, False: 53]
  ------------------
  400|     18|        delete mObjs[i];
  401|     18|    }
  402|     53|}
_ZN5glTF25Asset11SetAsBinaryEv:
 2142|      1|inline void Asset::SetAsBinary() {
 2143|      1|    if (!mBodyBuffer) {
  ------------------
  |  Branch (2143:9): [True: 1, False: 0]
  ------------------
 2144|      1|        mBodyBuffer = buffers.Create("binary_glTF");
 2145|      1|        mBodyBuffer->MarkAsSpecial();
 2146|      1|    }
 2147|      1|}
_ZN5glTF28LazyDictINS_6BufferEE6CreateEPKc:
  545|      1|Ref<T> LazyDict<T>::Create(const char *id) {
  546|      1|    T *inst = new T();
  547|      1|    unsigned int idx = unsigned(mObjs.size());
  548|      1|    inst->id = id;
  549|      1|    inst->index = idx;
  550|      1|    inst->oIndex = idx;
  551|      1|    return Add(inst);
  552|      1|}
_ZN5glTF26BufferC2Ev:
  558|      5|        byteLength(0),
  559|      5|        type(Type_arraybuffer),
  560|      5|        EncodedRegion_Current(nullptr),
  561|      5|        mIsSpecial(false) {
  562|       |    // empty
  563|      5|}
_ZN5glTF28LazyDictINS_6BufferEE3AddEPS1_:
  536|      3|Ref<T> LazyDict<T>::Add(T *obj) {
  537|      3|    unsigned int idx = unsigned(mObjs.size());
  538|      3|    mObjs.push_back(obj);
  539|      3|    mObjsByOIndex[obj->oIndex] = idx;
  540|      3|    mObjsById[obj->id] = idx;
  541|      3|    return Ref<T>(mObjs, idx);
  542|      3|}
_ZN5glTF25Asset8OpenFileERKNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEPKcb:
 2205|     55|inline IOStream *Asset::OpenFile(const std::string &path, const char *mode, bool /*absolute*/) {
 2206|     55|#ifdef ASSIMP_API
 2207|     55|    return mIOSystem->Open(path, mode);
 2208|       |#else
 2209|       |    if (path.size() < 2) return nullptr;
 2210|       |    if (!absolute && path[1] != ':' && path[0] != '/') { // relative?
 2211|       |        path = mCurrentAssetDir + path;
 2212|       |    }
 2213|       |    FILE *f = fopen(path.c_str(), mode);
 2214|       |    return f ? new IOStream(f) : nullptr;
 2215|       |#endif
 2216|     55|}
_ZN5glTF28LazyDictINS_10BufferViewEE3AddEPS1_:
  536|     18|Ref<T> LazyDict<T>::Add(T *obj) {
  537|     18|    unsigned int idx = unsigned(mObjs.size());
  538|     18|    mObjs.push_back(obj);
  539|     18|    mObjsByOIndex[obj->oIndex] = idx;
  540|     18|    mObjsById[obj->id] = idx;
  541|     18|    return Ref<T>(mObjs, idx);
  542|     18|}
_ZN5glTF221PbrSpecularGlossiness11SetDefaultsEv:
 1456|      6|inline void PbrSpecularGlossiness::SetDefaults() {
 1457|       |    //pbrSpecularGlossiness properties
 1458|      6|    SetVector(diffuseFactor, defaultDiffuseFactor);
 1459|      6|    SetVector(specularFactor, defaultSpecularFactor);
 1460|      6|    glossinessFactor = 1.0f;
 1461|      6|}
glTF2Exporter.cpp:_ZN5glTF212_GLOBAL__N_19SetVectorERA4_fRA4_Kf:
  176|     12|void SetVector(vec4 &v, const float (&in)[4]) {
  177|     12|    v[0] = in[0];
  178|     12|    v[1] = in[1];
  179|     12|    v[2] = in[2];
  180|     12|    v[3] = in[3];
  181|     12|}
glTF2Exporter.cpp:_ZN5glTF212_GLOBAL__N_19SetVectorERA3_fRA3_Kf:
  183|     30|void SetVector(vec3 &v, const float (&in)[3]) {
  184|     30|    v[0] = in[0];
  185|     30|    v[1] = in[1];
  186|     30|    v[2] = in[2];
  187|     30|}
_ZN5glTF216MaterialSpecular11SetDefaultsEv:
 1463|      6|inline void MaterialSpecular::SetDefaults() {
 1464|       |    //KHR_materials_specular properties
 1465|      6|    SetVector(specularColorFactor, defaultSpecularColorFactor);
 1466|      6|    specularFactor = 1.f;
 1467|      6|}
_ZN5glTF213MaterialSheen11SetDefaultsEv:
 1469|      6|inline void MaterialSheen::SetDefaults() {
 1470|       |    //KHR_materials_sheen properties
 1471|      6|    SetVector(sheenColorFactor, defaultSheenFactor);
 1472|      6|    sheenRoughnessFactor = 0.f;
 1473|      6|}
_ZN5glTF214MaterialVolume11SetDefaultsEv:
 1475|      6|inline void MaterialVolume::SetDefaults() {
 1476|       |    //KHR_materials_volume properties
 1477|      6|    thicknessFactor = 0.f;
 1478|      6|    attenuationDistance = std::numeric_limits<float>::infinity();
 1479|      6|    SetVector(attenuationColor, defaultAttenuationColor);
 1480|      6|}
_ZN5glTF211MaterialIOR11SetDefaultsEv:
 1482|      6|inline void MaterialIOR::SetDefaults() {
 1483|       |    //KHR_materials_ior properties
 1484|      6|    ior = 1.5f;
 1485|      6|}
_ZN5glTF224MaterialEmissiveStrength11SetDefaultsEv:
 1487|      6|inline void MaterialEmissiveStrength::SetDefaults() {
 1488|       |    //KHR_materials_emissive_strength properties
 1489|      6|    emissiveStrength = 0.f;
 1490|      6|}
_ZN5glTF218MaterialAnisotropy11SetDefaultsEv:
 1492|      6|inline void MaterialAnisotropy::SetDefaults() {
 1493|       |    //KHR_materials_anisotropy properties
 1494|      6|    anisotropyStrength = 0.f;
 1495|      6|    anisotropyRotation = 0.f;
 1496|      6|}
_ZN5glTF28LazyDictINS_8AccessorEE3AddEPS1_:
  536|     18|Ref<T> LazyDict<T>::Add(T *obj) {
  537|     18|    unsigned int idx = unsigned(mObjs.size());
  538|     18|    mObjs.push_back(obj);
  539|     18|    mObjsByOIndex[obj->oIndex] = idx;
  540|     18|    mObjsById[obj->id] = idx;
  541|     18|    return Ref<T>(mObjs, idx);
  542|     18|}
_ZN5glTF28Accessor16GetNumComponentsEv:
  959|     36|inline unsigned int Accessor::GetNumComponents() {
  960|     36|    return AttribType::GetNumComponents(type);
  961|     36|}
_ZN5glTF28Accessor20GetBytesPerComponentEv:
  963|     36|inline unsigned int Accessor::GetBytesPerComponent() {
  964|     36|    return int(ComponentTypeSize(componentType));
  965|     36|}
_ZN5glTF27Sampler11SetDefaultsEv:
 1209|      2|inline void Sampler::SetDefaults() {
 1210|       |    //only wrapping modes have defaults
 1211|      2|    wrapS = SamplerWrap::Repeat;
 1212|      2|    wrapT = SamplerWrap::Repeat;
 1213|      2|    magFilter = SamplerMagFilter::UNSET;
 1214|      2|    minFilter = SamplerMinFilter::UNSET;
 1215|      2|}
_ZN5glTF28LazyDictINS_7SamplerEE3AddEPS1_:
  536|      1|Ref<T> LazyDict<T>::Add(T *obj) {
  537|      1|    unsigned int idx = unsigned(mObjs.size());
  538|      1|    mObjs.push_back(obj);
  539|      1|    mObjsByOIndex[obj->oIndex] = idx;
  540|      1|    mObjsById[obj->id] = idx;
  541|      1|    return Ref<T>(mObjs, idx);
  542|      1|}
_ZN5glTF28LazyDictINS_7TextureEE3AddEPS1_:
  536|      1|Ref<T> LazyDict<T>::Add(T *obj) {
  537|      1|    unsigned int idx = unsigned(mObjs.size());
  538|      1|    mObjs.push_back(obj);
  539|      1|    mObjsByOIndex[obj->oIndex] = idx;
  540|      1|    mObjsById[obj->id] = idx;
  541|      1|    return Ref<T>(mObjs, idx);
  542|      1|}
_ZN5glTF25ImageC2Ev:
 1131|      2|        width(0),
 1132|      2|        height(0),
 1133|      2|        mDataLength(0) {
 1134|      2|}
_ZN5glTF28LazyDictINS_5ImageEE3AddEPS1_:
  536|      1|Ref<T> LazyDict<T>::Add(T *obj) {
  537|      1|    unsigned int idx = unsigned(mObjs.size());
  538|      1|    mObjs.push_back(obj);
  539|      1|    mObjsByOIndex[obj->oIndex] = idx;
  540|      1|    mObjsById[obj->id] = idx;
  541|      1|    return Ref<T>(mObjs, idx);
  542|      1|}
_ZN5glTF28Material11SetDefaultsEv:
 1443|     12|inline void Material::SetDefaults() {
 1444|       |    //pbr materials
 1445|     12|    SetVector(pbrMetallicRoughness.baseColorFactor, defaultBaseColor);
 1446|     12|    pbrMetallicRoughness.metallicFactor = 1.0f;
 1447|     12|    pbrMetallicRoughness.roughnessFactor = 1.0f;
 1448|       |
 1449|     12|    SetVector(emissiveFactor, defaultEmissiveFactor);
 1450|     12|    alphaMode = "OPAQUE";
 1451|     12|    alphaCutoff = 0.5f;
 1452|     12|    doubleSided = false;
 1453|     12|    unlit = false;
 1454|     12|}
_ZN5glTF28LazyDictINS_8MaterialEE3AddEPS1_:
  536|      5|Ref<T> LazyDict<T>::Add(T *obj) {
  537|      5|    unsigned int idx = unsigned(mObjs.size());
  538|      5|    mObjs.push_back(obj);
  539|      5|    mObjsByOIndex[obj->oIndex] = idx;
  540|      5|    mObjsById[obj->id] = idx;
  541|      5|    return Ref<T>(mObjs, idx);
  542|      5|}
_ZN5glTF28LazyDictINS_4MeshEE3AddEPS1_:
  536|      4|Ref<T> LazyDict<T>::Add(T *obj) {
  537|      4|    unsigned int idx = unsigned(mObjs.size());
  538|      4|    mObjs.push_back(obj);
  539|      4|    mObjsByOIndex[obj->oIndex] = idx;
  540|      4|    mObjsById[obj->id] = idx;
  541|      4|    return Ref<T>(mObjs, idx);
  542|      4|}
_ZN5glTF28LazyDictINS_4NodeEE3AddEPS1_:
  536|      4|Ref<T> LazyDict<T>::Add(T *obj) {
  537|      4|    unsigned int idx = unsigned(mObjs.size());
  538|      4|    mObjs.push_back(obj);
  539|      4|    mObjsByOIndex[obj->oIndex] = idx;
  540|      4|    mObjsById[obj->id] = idx;
  541|      4|    return Ref<T>(mObjs, idx);
  542|      4|}
_ZN5glTF26Object10FindStringERN9rapidjson12GenericValueINS1_4UTF8IcEENS1_19MemoryPoolAllocatorINS1_12CrtAllocatorEEEEEPKc:
  235|     10|inline Value *Object::FindString(Value &val, const char *memberId) {
  236|     10|    return FindStringInContext(val, memberId, id.c_str(), name.c_str());
  237|     10|}
_ZN5glTF26Object8FindUIntERN9rapidjson12GenericValueINS1_4UTF8IcEENS1_19MemoryPoolAllocatorINS1_12CrtAllocatorEEEEEPKc:
  243|     98|inline Value *Object::FindUInt(Value &val, const char *memberId) {
  244|     98|    return FindUIntInContext(val, memberId, id.c_str(), name.c_str());
  245|     98|}
_ZN5glTF26Object9FindArrayERN9rapidjson12GenericValueINS1_4UTF8IcEENS1_19MemoryPoolAllocatorINS1_12CrtAllocatorEEEEEPKc:
  247|     37|inline Value *Object::FindArray(Value &val, const char *memberId) {
  248|     37|    return FindArrayInContext(val, memberId, id.c_str(), name.c_str());
  249|     37|}
_ZN5glTF26Object10FindObjectERN9rapidjson12GenericValueINS1_4UTF8IcEENS1_19MemoryPoolAllocatorINS1_12CrtAllocatorEEEEEPKc:
  251|    155|inline Value *Object::FindObject(Value &val, const char *memberId) {
  252|    155|    return FindObjectInContext(val, memberId, id.c_str(), name.c_str());
  253|    155|}
_ZN5glTF26Object14ReadExtensionsERN9rapidjson12GenericValueINS1_4UTF8IcEENS1_19MemoryPoolAllocatorINS1_12CrtAllocatorEEEEE:
  259|     54|inline void Object::ReadExtensions(Value &val) {
  260|     54|    if (Value *curExtensions = FindObject(val, "extensions")) {
  ------------------
  |  Branch (260:16): [True: 0, False: 54]
  ------------------
  261|      0|        this->customExtensions = glTF2::ReadExtensions("extensions", *curExtensions);
  262|      0|    }
  263|     54|}
_ZN5glTF26Object10ReadExtrasERN9rapidjson12GenericValueINS1_4UTF8IcEENS1_19MemoryPoolAllocatorINS1_12CrtAllocatorEEEEE:
  265|     54|inline void Object::ReadExtras(Value &val) {
  266|     54|    if (Value *curExtras = FindObject(val, "extras")) {
  ------------------
  |  Branch (266:16): [True: 0, False: 54]
  ------------------
  267|      0|        this->extras = glTF2::ReadExtras(*curExtras);
  268|      0|    }
  269|     54|}
_ZN5glTF26Buffer4ReadERN9rapidjson12GenericValueINS1_4UTF8IcEENS1_19MemoryPoolAllocatorINS1_12CrtAllocatorEEEEERNS_5AssetE:
  573|      4|inline void Buffer::Read(Value &obj, Asset &r) {
  574|      4|    size_t statedLength = MemberOrDefault<size_t>(obj, "byteLength", 0);
  575|      4|    byteLength = statedLength;
  576|       |
  577|      4|    Value *it = FindString(obj, "uri");
  578|      4|    if (!it) {
  ------------------
  |  Branch (578:9): [True: 0, False: 4]
  ------------------
  579|      0|        if (statedLength > 0) {
  ------------------
  |  Branch (579:13): [True: 0, False: 0]
  ------------------
  580|      0|            throw DeadlyImportError("GLTF: buffer with non-zero length missing the \"uri\" attribute");
  581|      0|        }
  582|      0|        return;
  583|      0|    }
  584|       |
  585|      4|    const char *uri = it->GetString();
  586|       |
  587|      4|    glTFCommon::Util::DataURI dataURI;
  588|      4|    if (ParseDataURI(uri, it->GetStringLength(), dataURI)) {
  ------------------
  |  Branch (588:9): [True: 2, False: 2]
  ------------------
  589|      2|        if (dataURI.base64) {
  ------------------
  |  Branch (589:13): [True: 2, False: 0]
  ------------------
  590|      2|            uint8_t *data = nullptr;
  591|      2|            this->byteLength = Base64::Decode(dataURI.data, dataURI.dataLength, data);
  592|      2|            this->mData.reset(data, std::default_delete<uint8_t[]>());
  593|       |
  594|      2|            if (statedLength > 0 && this->byteLength != statedLength) {
  ------------------
  |  Branch (594:17): [True: 2, False: 0]
  |  Branch (594:37): [True: 0, False: 2]
  ------------------
  595|      0|                throw DeadlyImportError("GLTF: buffer \"", id, "\", expected ", ai_to_string(statedLength),
  596|      0|                        " bytes, but found ", ai_to_string(dataURI.dataLength));
  597|      0|            }
  598|      2|        } else { // assume raw data
  599|      0|            if (statedLength != dataURI.dataLength) {
  ------------------
  |  Branch (599:17): [True: 0, False: 0]
  ------------------
  600|      0|                throw DeadlyImportError("GLTF: buffer \"", id, "\", expected ", ai_to_string(statedLength),
  601|      0|                        " bytes, but found ", ai_to_string(dataURI.dataLength));
  602|      0|            }
  603|       |
  604|      0|            this->mData.reset(new uint8_t[dataURI.dataLength], std::default_delete<uint8_t[]>());
  605|      0|            memcpy(this->mData.get(), dataURI.data, dataURI.dataLength);
  606|      0|        }
  607|      2|    } else { // Local file
  608|      2|        if (byteLength > 0) {
  ------------------
  |  Branch (608:13): [True: 2, False: 0]
  ------------------
  609|      2|            std::string dir = !r.mCurrentAssetDir.empty() ? (r.mCurrentAssetDir.back() == '/' ? r.mCurrentAssetDir : r.mCurrentAssetDir + '/') : "";
  ------------------
  |  Branch (609:31): [True: 0, False: 2]
  |  Branch (609:62): [True: 0, False: 0]
  ------------------
  610|       |
  611|      2|            IOStream *file = r.OpenFile(dir + uri, "rb");
  612|      2|            if (file) {
  ------------------
  |  Branch (612:17): [True: 0, False: 2]
  ------------------
  613|      0|                bool ok = LoadFromStream(*file, byteLength);
  614|      0|                delete file;
  615|       |
  616|      0|                if (!ok)
  ------------------
  |  Branch (616:21): [True: 0, False: 0]
  ------------------
  617|      0|                    throw DeadlyImportError("GLTF: error while reading referenced file \"", uri, "\"");
  618|      2|            } else {
  619|      2|                throw DeadlyImportError("GLTF: could not open referenced file \"", uri, "\"");
  620|      2|            }
  621|      2|        }
  622|      2|    }
  623|      4|}
_ZN5glTF210BufferView4ReadERN9rapidjson12GenericValueINS1_4UTF8IcEENS1_19MemoryPoolAllocatorINS1_12CrtAllocatorEEEEERNS_5AssetE:
  765|     20|inline void BufferView::Read(Value &obj, Asset &r) {
  766|     20|    if (Value *bufferVal = FindUInt(obj, "buffer")) {
  ------------------
  |  Branch (766:16): [True: 20, False: 0]
  ------------------
  767|     20|        buffer = r.buffers.Retrieve(bufferVal->GetUint());
  768|     20|    }
  769|       |
  770|     20|    if (!buffer) {
  ------------------
  |  Branch (770:9): [True: 0, False: 20]
  ------------------
  771|      0|        throw DeadlyImportError("GLTF: Buffer view without valid buffer.");
  772|      0|    }
  773|       |
  774|     20|    byteOffset = MemberOrDefault(obj, "byteOffset", size_t(0));
  775|     20|    byteLength = MemberOrDefault(obj, "byteLength", size_t(0));
  776|     20|    byteStride = MemberOrDefault(obj, "byteStride", 0u);
  777|       |
  778|       |    // Check length
  779|     20|    if ((byteOffset + byteLength) > buffer->byteLength) {
  ------------------
  |  Branch (779:9): [True: 0, False: 20]
  ------------------
  780|      0|        throw DeadlyImportError("GLTF: Buffer view with offset/length (", byteOffset, "/", byteLength, ") is out of range.");
  781|      0|    }
  782|     20|}
_ZN5glTF28Accessor4ReadERN9rapidjson12GenericValueINS1_4UTF8IcEENS1_19MemoryPoolAllocatorINS1_12CrtAllocatorEEEEERNS_5AssetE:
  871|     20|inline void Accessor::Read(Value &obj, Asset &r) {
  872|     20|    if (Value *bufferViewVal = FindUInt(obj, "bufferView")) {
  ------------------
  |  Branch (872:16): [True: 20, False: 0]
  ------------------
  873|     20|        bufferView = r.bufferViews.Retrieve(bufferViewVal->GetUint());
  874|     20|    }
  875|       |
  876|     20|    byteOffset = MemberOrDefault(obj, "byteOffset", size_t(0));
  877|     20|    componentType = MemberOrDefault(obj, "componentType", ComponentType_BYTE);
  878|     20|    {
  879|     20|        const Value *countValue = FindUInt(obj, "count");
  880|     20|        if (!countValue) {
  ------------------
  |  Branch (880:13): [True: 0, False: 20]
  ------------------
  881|      0|            throw DeadlyImportError("A count value is required, when reading ", id.c_str(), name.empty() ? "" : " (" + name + ")");
  ------------------
  |  Branch (881:93): [True: 0, False: 0]
  ------------------
  882|      0|        }
  883|     20|        count = countValue->GetUint();
  884|     20|    }
  885|       |
  886|      0|    const char *typestr;
  887|     20|    type = ReadMember(obj, "type", typestr) ? AttribType::FromString(typestr) : AttribType::SCALAR;
  ------------------
  |  Branch (887:12): [True: 18, False: 2]
  ------------------
  888|       |
  889|     20|    if (bufferView) {
  ------------------
  |  Branch (889:9): [True: 18, False: 2]
  ------------------
  890|       |        // Check length
  891|     18|        unsigned long long byteLength = count > 0
  ------------------
  |  Branch (891:41): [True: 18, False: 0]
  ------------------
  892|     18|            ? (unsigned long long)GetStride() * (unsigned long long)(count - 1) + (unsigned long long)GetElementSize()
  893|     18|            : 0;
  894|       |
  895|       |        // handle integer overflow
  896|     18|        if (byteLength < count) {
  ------------------
  |  Branch (896:13): [True: 0, False: 18]
  ------------------
  897|      0|            throw DeadlyImportError("GLTF: Accessor with offset/count (", byteOffset, "/", count, ") is out of range.");
  898|      0|        }
  899|       |
  900|     18|        if ((byteOffset + byteLength) > bufferView->byteLength || (bufferView->byteOffset + byteOffset + byteLength) > bufferView->buffer->byteLength) {
  ------------------
  |  Branch (900:13): [True: 0, False: 18]
  |  Branch (900:67): [True: 0, False: 18]
  ------------------
  901|      0|            throw DeadlyImportError("GLTF: Accessor with offset/length (", byteOffset, "/", byteLength, ") is out of range.");
  902|      0|        }
  903|     18|    }
  904|       |
  905|     20|    if (Value *sparseValue = FindObject(obj, "sparse")) {
  ------------------
  |  Branch (905:16): [True: 0, False: 20]
  ------------------
  906|      0|        sparse.reset(new Sparse);
  907|       |        // count
  908|      0|        ReadMember(*sparseValue, "count", sparse->count);
  909|       |
  910|       |        // indices
  911|      0|        if (Value *indicesValue = FindObject(*sparseValue, "indices")) {
  ------------------
  |  Branch (911:20): [True: 0, False: 0]
  ------------------
  912|       |            //indices bufferView
  913|      0|            Value *indiceViewID = FindUInt(*indicesValue, "bufferView");
  914|      0|            if (!indiceViewID) {
  ------------------
  |  Branch (914:17): [True: 0, False: 0]
  ------------------
  915|      0|                throw DeadlyImportError("A bufferView value is required, when reading ", id.c_str(), name.empty() ? "" : " (" + name + ")");
  ------------------
  |  Branch (915:102): [True: 0, False: 0]
  ------------------
  916|      0|            }
  917|      0|            sparse->indices = r.bufferViews.Retrieve(indiceViewID->GetUint());
  918|       |            //indices byteOffset
  919|      0|            sparse->indicesByteOffset = MemberOrDefault(*indicesValue, "byteOffset", size_t(0));
  920|       |            //indices componentType
  921|      0|            sparse->indicesType = MemberOrDefault(*indicesValue, "componentType", ComponentType_BYTE);
  922|       |            //sparse->indices->Read(*indicesValue, r);
  923|      0|        } else {
  924|       |            // indicesType
  925|      0|            sparse->indicesType = MemberOrDefault(*sparseValue, "componentType", ComponentType_UNSIGNED_SHORT);
  926|      0|        }
  927|       |
  928|       |        // value
  929|      0|        if (Value *valuesValue = FindObject(*sparseValue, "values")) {
  ------------------
  |  Branch (929:20): [True: 0, False: 0]
  ------------------
  930|       |            //value bufferView
  931|      0|            Value *valueViewID = FindUInt(*valuesValue, "bufferView");
  932|      0|            if (!valueViewID) {
  ------------------
  |  Branch (932:17): [True: 0, False: 0]
  ------------------
  933|      0|                throw DeadlyImportError("A bufferView value is required, when reading ", id.c_str(), name.empty() ? "" : " (" + name + ")");
  ------------------
  |  Branch (933:102): [True: 0, False: 0]
  ------------------
  934|      0|            }
  935|      0|            sparse->values = r.bufferViews.Retrieve(valueViewID->GetUint());
  936|       |            //value byteOffset
  937|      0|            sparse->valuesByteOffset = MemberOrDefault(*valuesValue, "byteOffset", size_t(0));
  938|       |            //sparse->values->Read(*valuesValue, r);
  939|      0|        }
  940|       |
  941|       |
  942|      0|        const unsigned int elementSize = GetElementSize();
  943|      0|        const size_t dataSize = count * elementSize;
  944|      0|        if (bufferView) {
  ------------------
  |  Branch (944:13): [True: 0, False: 0]
  ------------------
  945|      0|            size_t bufferViewTailSize;
  946|      0|            const uint8_t* bufferViewPointer = bufferView->GetPointerAndTailSize(byteOffset, bufferViewTailSize);
  947|      0|            if (dataSize > bufferViewTailSize) {
  ------------------
  |  Branch (947:17): [True: 0, False: 0]
  ------------------
  948|      0|                throw DeadlyImportError("Invalid buffer when reading ", id.c_str(), name.empty() ? "" : " (" + name + ")");
  ------------------
  |  Branch (948:85): [True: 0, False: 0]
  ------------------
  949|      0|            }
  950|      0|            sparse->PopulateData(dataSize, bufferViewPointer);
  951|      0|        }
  952|      0|        else {
  953|      0|            sparse->PopulateData(dataSize, nullptr);
  954|      0|        }
  955|      0|        sparse->PatchData(elementSize);
  956|      0|    }
  957|     20|}
_ZN5glTF28Accessor14GetElementSizeEv:
  967|     36|inline unsigned int Accessor::GetElementSize() {
  968|     36|    return GetNumComponents() * GetBytesPerComponent();
  969|     36|}
_ZN5glTF28Accessor9GetStrideEv:
  996|     18|inline size_t Accessor::GetStride() {
  997|       |    // Decoded buffer is always packed
  998|     18|    if (decodedBuffer)
  ------------------
  |  Branch (998:9): [True: 0, False: 18]
  ------------------
  999|      0|        return GetElementSize();
 1000|       |
 1001|       |    // Sparse and normal bufferView
 1002|     18|    return (bufferView && bufferView->byteStride ? bufferView->byteStride : GetElementSize());
  ------------------
  |  Branch (1002:13): [True: 18, False: 0]
  |  Branch (1002:27): [True: 0, False: 18]
  ------------------
 1003|     18|}
_ZN5glTF25Image4ReadERN9rapidjson12GenericValueINS1_4UTF8IcEENS1_19MemoryPoolAllocatorINS1_12CrtAllocatorEEEEERNS_5AssetE:
 1136|      2|inline void Image::Read(Value &obj, Asset &r) {
 1137|       |    //basisu: no need to handle .ktx2, .basis, load as is
 1138|      2|    if (!mDataLength) {
  ------------------
  |  Branch (1138:9): [True: 2, False: 0]
  ------------------
 1139|      2|        Value *curUri = FindString(obj, "uri");
 1140|      2|        if (nullptr != curUri) {
  ------------------
  |  Branch (1140:13): [True: 2, False: 0]
  ------------------
 1141|      2|            const char *uristr = curUri->GetString();
 1142|       |
 1143|      2|            glTFCommon::Util::DataURI dataURI;
 1144|      2|            if (ParseDataURI(uristr, curUri->GetStringLength(), dataURI)) {
  ------------------
  |  Branch (1144:17): [True: 2, False: 0]
  ------------------
 1145|      2|                mimeType = dataURI.mediaType;
 1146|      2|                if (dataURI.base64) {
  ------------------
  |  Branch (1146:21): [True: 2, False: 0]
  ------------------
 1147|      2|                    uint8_t *ptr = nullptr;
 1148|      2|                    mDataLength = Base64::Decode(dataURI.data, dataURI.dataLength, ptr);
 1149|      2|                    mData.reset(ptr);
 1150|      2|                }
 1151|      2|            } else {
 1152|      0|                this->uri = uristr;
 1153|      0|            }
 1154|      2|        } else if (Value *bufferViewVal = FindUInt(obj, "bufferView")) {
  ------------------
  |  Branch (1154:27): [True: 0, False: 0]
  ------------------
 1155|      0|            this->bufferView = r.bufferViews.Retrieve(bufferViewVal->GetUint());
 1156|      0|            if (Value *mtype = FindString(obj, "mimeType")) {
  ------------------
  |  Branch (1156:24): [True: 0, False: 0]
  ------------------
 1157|      0|                this->mimeType = mtype->GetString();
 1158|      0|            }
 1159|      0|            if (!this->bufferView || this->mimeType.empty()) {
  ------------------
  |  Branch (1159:17): [True: 0, False: 0]
  |  Branch (1159:38): [True: 0, False: 0]
  ------------------
 1160|      0|                throw DeadlyImportError("GLTF2: ", getContextForErrorMessages(id, name), " does not have a URI, so it must have a valid bufferView and mimetype");
 1161|      0|            }
 1162|       |
 1163|      0|            Ref<Buffer> buffer = this->bufferView->buffer;
 1164|       |
 1165|      0|            this->mDataLength = this->bufferView->byteLength;
 1166|       |            // maybe this memcpy could be avoided if aiTexture does not delete[] pcData at destruction.
 1167|       |
 1168|      0|            this->mData.reset(new uint8_t[this->mDataLength]);
 1169|      0|            memcpy(this->mData.get(), buffer->GetPointer() + this->bufferView->byteOffset, this->mDataLength);
 1170|      0|        } else {
 1171|      0|            throw DeadlyImportError("GLTF2: ", getContextForErrorMessages(id, name), " should have either a URI of a bufferView and mimetype");
 1172|      0|        }
 1173|      2|    }
 1174|      2|}
_ZN5glTF27Sampler4ReadERN9rapidjson12GenericValueINS1_4UTF8IcEENS1_19MemoryPoolAllocatorINS1_12CrtAllocatorEEEEERNS_5AssetE:
 1199|      1|inline void Sampler::Read(Value &obj, Asset & /*r*/) {
 1200|      1|    SetDefaults();
 1201|       |
 1202|      1|    ReadMember(obj, "name", name);
 1203|      1|    ReadMember(obj, "magFilter", magFilter);
 1204|      1|    ReadMember(obj, "minFilter", minFilter);
 1205|      1|    ReadMember(obj, "wrapS", wrapS);
 1206|      1|    ReadMember(obj, "wrapT", wrapT);
 1207|      1|}
_ZN5glTF27Texture4ReadERN9rapidjson12GenericValueINS1_4UTF8IcEENS1_19MemoryPoolAllocatorINS1_12CrtAllocatorEEEEERNS_5AssetE:
 1217|      2|inline void Texture::Read(Value &obj, Asset &r) {
 1218|      2|    if (Value *sourceVal = FindUInt(obj, "source")) {
  ------------------
  |  Branch (1218:16): [True: 2, False: 0]
  ------------------
 1219|      2|        source = r.images.Retrieve(sourceVal->GetUint());
 1220|      2|    }
 1221|       |
 1222|      2|    if (Value *samplerVal = FindUInt(obj, "sampler")) {
  ------------------
  |  Branch (1222:16): [True: 1, False: 1]
  ------------------
 1223|      1|        sampler = r.samplers.Retrieve(samplerVal->GetUint());
 1224|      1|    }
 1225|       |
 1226|      2|    if (Value *extensions = FindObject(obj, "extensions")) {
  ------------------
  |  Branch (1226:16): [True: 0, False: 2]
  ------------------
 1227|      0|        if (r.extensionsUsed.KHR_texture_basisu) {
  ------------------
  |  Branch (1227:13): [True: 0, False: 0]
  ------------------
 1228|      0|            if (Value *curBasisU = FindObject(*extensions, "KHR_texture_basisu")) {
  ------------------
  |  Branch (1228:24): [True: 0, False: 0]
  ------------------
 1229|       |
 1230|      0|                if (Value *sourceVal = FindUInt(*curBasisU, "source")) {
  ------------------
  |  Branch (1230:28): [True: 0, False: 0]
  ------------------
 1231|      0|                    source = r.images.Retrieve(sourceVal->GetUint());
 1232|      0|                }
 1233|      0|            }
 1234|      0|        } else if(r.extensionsUsed.EXT_texture_webp) {
  ------------------
  |  Branch (1234:19): [True: 0, False: 0]
  ------------------
 1235|      0|            if (Value *curBasisU = FindObject(*extensions, "EXT_texture_webp")) {
  ------------------
  |  Branch (1235:24): [True: 0, False: 0]
  ------------------
 1236|       |
 1237|      0|                if (Value *sourceVal = FindUInt(*curBasisU, "source")) {
  ------------------
  |  Branch (1237:28): [True: 0, False: 0]
  ------------------
 1238|      0|                    source = r.images.Retrieve(sourceVal->GetUint());
 1239|      0|                }
 1240|      0|            }
 1241|      0|        }
 1242|      0|    }
 1243|      2|}
_ZN5glTF28Material20SetTexturePropertiesERNS_5AssetEPN9rapidjson12GenericValueINS3_4UTF8IcEENS3_19MemoryPoolAllocatorINS3_12CrtAllocatorEEEEERNS_11TextureInfoE:
 1245|      4|void Material::SetTextureProperties(Asset &r, Value *prop, TextureInfo &out) {
 1246|      4|    if (r.extensionsUsed.KHR_texture_transform) {
  ------------------
  |  Branch (1246:9): [True: 0, False: 4]
  ------------------
 1247|      0|        if (Value *pKHR_texture_transform = FindExtension(*prop, "KHR_texture_transform")) {
  ------------------
  |  Branch (1247:20): [True: 0, False: 0]
  ------------------
 1248|      0|            out.textureTransformSupported = true;
 1249|      0|            if (Value *array = FindArray(*pKHR_texture_transform, "offset")) {
  ------------------
  |  Branch (1249:24): [True: 0, False: 0]
  ------------------
 1250|      0|                out.TextureTransformExt_t.offset[0] = (*array)[0].GetFloat();
 1251|      0|                out.TextureTransformExt_t.offset[1] = (*array)[1].GetFloat();
 1252|      0|            } else {
 1253|      0|                out.TextureTransformExt_t.offset[0] = 0;
 1254|      0|                out.TextureTransformExt_t.offset[1] = 0;
 1255|      0|            }
 1256|       |
 1257|      0|            if (!ReadMember(*pKHR_texture_transform, "rotation", out.TextureTransformExt_t.rotation)) {
  ------------------
  |  Branch (1257:17): [True: 0, False: 0]
  ------------------
 1258|      0|                out.TextureTransformExt_t.rotation = 0;
 1259|      0|            }
 1260|       |
 1261|      0|            if (Value *array = FindArray(*pKHR_texture_transform, "scale")) {
  ------------------
  |  Branch (1261:24): [True: 0, False: 0]
  ------------------
 1262|      0|                out.TextureTransformExt_t.scale[0] = (*array)[0].GetFloat();
 1263|      0|                out.TextureTransformExt_t.scale[1] = (*array)[1].GetFloat();
 1264|      0|            } else {
 1265|      0|                out.TextureTransformExt_t.scale[0] = 1;
 1266|      0|                out.TextureTransformExt_t.scale[1] = 1;
 1267|      0|            }
 1268|      0|        }
 1269|      0|    }
 1270|       |
 1271|      4|    if (Value *indexProp = FindUInt(*prop, "index")) {
  ------------------
  |  Branch (1271:16): [True: 4, False: 0]
  ------------------
 1272|      4|        out.texture = r.textures.Retrieve(indexProp->GetUint());
 1273|      4|    }
 1274|       |
 1275|      4|    if (Value *texcoord = FindUInt(*prop, "texCoord")) {
  ------------------
  |  Branch (1275:16): [True: 0, False: 4]
  ------------------
 1276|      0|        out.texCoord = texcoord->GetUint();
 1277|      0|    }
 1278|      4|}
_ZN5glTF28Material19ReadTexturePropertyERNS_5AssetERN9rapidjson12GenericValueINS3_4UTF8IcEENS3_19MemoryPoolAllocatorINS3_12CrtAllocatorEEEEEPKcRNS_11TextureInfoE:
 1280|     16|inline void Material::ReadTextureProperty(Asset &r, Value &vals, const char *propName, TextureInfo &out) {
 1281|     16|    if (Value *prop = FindMember(vals, propName)) {
  ------------------
  |  Branch (1281:16): [True: 4, False: 12]
  ------------------
 1282|      4|        SetTextureProperties(r, prop, out);
 1283|      4|    }
 1284|     16|}
_ZN5glTF28Material19ReadTexturePropertyERNS_5AssetERN9rapidjson12GenericValueINS3_4UTF8IcEENS3_19MemoryPoolAllocatorINS3_12CrtAllocatorEEEEEPKcRNS_17NormalTextureInfoE:
 1286|      5|inline void Material::ReadTextureProperty(Asset &r, Value &vals, const char *propName, NormalTextureInfo &out) {
 1287|      5|    if (Value *prop = FindMember(vals, propName)) {
  ------------------
  |  Branch (1287:16): [True: 0, False: 5]
  ------------------
 1288|      0|        SetTextureProperties(r, prop, out);
 1289|       |
 1290|      0|        if (Value *scale = FindNumber(*prop, "scale")) {
  ------------------
  |  Branch (1290:20): [True: 0, False: 0]
  ------------------
 1291|      0|            out.scale = static_cast<float>(scale->GetDouble());
 1292|      0|        }
 1293|      0|    }
 1294|      5|}
_ZN5glTF28Material19ReadTexturePropertyERNS_5AssetERN9rapidjson12GenericValueINS3_4UTF8IcEENS3_19MemoryPoolAllocatorINS3_12CrtAllocatorEEEEEPKcRNS_20OcclusionTextureInfoE:
 1296|      5|inline void Material::ReadTextureProperty(Asset &r, Value &vals, const char *propName, OcclusionTextureInfo &out) {
 1297|      5|    if (Value *prop = FindMember(vals, propName)) {
  ------------------
  |  Branch (1297:16): [True: 0, False: 5]
  ------------------
 1298|      0|        SetTextureProperties(r, prop, out);
 1299|       |
 1300|      0|        if (Value *strength = FindNumber(*prop, "strength")) {
  ------------------
  |  Branch (1300:20): [True: 0, False: 0]
  ------------------
 1301|      0|            out.strength = static_cast<float>(strength->GetDouble());
 1302|      0|        }
 1303|      0|    }
 1304|      5|}
_ZN5glTF28Material4ReadERN9rapidjson12GenericValueINS1_4UTF8IcEENS1_19MemoryPoolAllocatorINS1_12CrtAllocatorEEEEERNS_5AssetE:
 1306|      6|inline void Material::Read(Value &material, Asset &r) {
 1307|      6|    SetDefaults();
 1308|       |
 1309|      6|    if (Value *curPbrMetallicRoughness = FindObject(material, "pbrMetallicRoughness")) {
  ------------------
  |  Branch (1309:16): [True: 6, False: 0]
  ------------------
 1310|      6|        ReadMember(*curPbrMetallicRoughness, "baseColorFactor", this->pbrMetallicRoughness.baseColorFactor);
 1311|      6|        ReadTextureProperty(r, *curPbrMetallicRoughness, "baseColorTexture", this->pbrMetallicRoughness.baseColorTexture);
 1312|      6|        ReadTextureProperty(r, *curPbrMetallicRoughness, "metallicRoughnessTexture", this->pbrMetallicRoughness.metallicRoughnessTexture);
 1313|      6|        ReadMember(*curPbrMetallicRoughness, "metallicFactor", this->pbrMetallicRoughness.metallicFactor);
 1314|      6|        ReadMember(*curPbrMetallicRoughness, "roughnessFactor", this->pbrMetallicRoughness.roughnessFactor);
 1315|      6|    }
 1316|       |
 1317|      6|    ReadTextureProperty(r, material, "normalTexture", this->normalTexture);
 1318|      6|    ReadTextureProperty(r, material, "occlusionTexture", this->occlusionTexture);
 1319|      6|    ReadTextureProperty(r, material, "emissiveTexture", this->emissiveTexture);
 1320|      6|    ReadMember(material, "emissiveFactor", this->emissiveFactor);
 1321|       |
 1322|      6|    ReadMember(material, "doubleSided", this->doubleSided);
 1323|      6|    ReadMember(material, "alphaMode", this->alphaMode);
 1324|      6|    ReadMember(material, "alphaCutoff", this->alphaCutoff);
 1325|       |
 1326|      6|    if (Value *extensions = FindObject(material, "extensions")) {
  ------------------
  |  Branch (1326:16): [True: 0, False: 6]
  ------------------
 1327|      0|        if (r.extensionsUsed.KHR_materials_pbrSpecularGlossiness) {
  ------------------
  |  Branch (1327:13): [True: 0, False: 0]
  ------------------
 1328|      0|            if (Value *curPbrSpecularGlossiness = FindObject(*extensions, "KHR_materials_pbrSpecularGlossiness")) {
  ------------------
  |  Branch (1328:24): [True: 0, False: 0]
  ------------------
 1329|      0|                PbrSpecularGlossiness pbrSG;
 1330|       |
 1331|      0|                ReadMember(*curPbrSpecularGlossiness, "diffuseFactor", pbrSG.diffuseFactor);
 1332|      0|                ReadTextureProperty(r, *curPbrSpecularGlossiness, "diffuseTexture", pbrSG.diffuseTexture);
 1333|      0|                ReadTextureProperty(r, *curPbrSpecularGlossiness, "specularGlossinessTexture", pbrSG.specularGlossinessTexture);
 1334|      0|                ReadMember(*curPbrSpecularGlossiness, "specularFactor", pbrSG.specularFactor);
 1335|      0|                ReadMember(*curPbrSpecularGlossiness, "glossinessFactor", pbrSG.glossinessFactor);
 1336|       |
 1337|      0|                this->pbrSpecularGlossiness = Nullable<PbrSpecularGlossiness>(pbrSG);
 1338|      0|            }
 1339|      0|        }
 1340|       |
 1341|      0|        if (r.extensionsUsed.KHR_materials_specular) {
  ------------------
  |  Branch (1341:13): [True: 0, False: 0]
  ------------------
 1342|      0|            if (Value *curMatSpecular = FindObject(*extensions, "KHR_materials_specular")) {
  ------------------
  |  Branch (1342:24): [True: 0, False: 0]
  ------------------
 1343|      0|                MaterialSpecular specular;
 1344|       |
 1345|      0|                ReadMember(*curMatSpecular, "specularFactor", specular.specularFactor);
 1346|      0|                ReadTextureProperty(r, *curMatSpecular, "specularTexture", specular.specularTexture);
 1347|      0|                ReadMember(*curMatSpecular, "specularColorFactor", specular.specularColorFactor);
 1348|      0|                ReadTextureProperty(r, *curMatSpecular, "specularColorTexture", specular.specularColorTexture);
 1349|       |
 1350|      0|                this->materialSpecular = Nullable<MaterialSpecular>(specular);
 1351|      0|            }
 1352|      0|        }
 1353|       |
 1354|       |        // Extension KHR_texture_transform is handled in ReadTextureProperty
 1355|       |
 1356|      0|        if (r.extensionsUsed.KHR_materials_sheen) {
  ------------------
  |  Branch (1356:13): [True: 0, False: 0]
  ------------------
 1357|      0|            if (Value *curMaterialSheen = FindObject(*extensions, "KHR_materials_sheen")) {
  ------------------
  |  Branch (1357:24): [True: 0, False: 0]
  ------------------
 1358|      0|                MaterialSheen sheen;
 1359|       |
 1360|      0|                ReadMember(*curMaterialSheen, "sheenColorFactor", sheen.sheenColorFactor);
 1361|      0|                ReadTextureProperty(r, *curMaterialSheen, "sheenColorTexture", sheen.sheenColorTexture);
 1362|      0|                ReadMember(*curMaterialSheen, "sheenRoughnessFactor", sheen.sheenRoughnessFactor);
 1363|      0|                ReadTextureProperty(r, *curMaterialSheen, "sheenRoughnessTexture", sheen.sheenRoughnessTexture);
 1364|       |
 1365|      0|                this->materialSheen = Nullable<MaterialSheen>(sheen);
 1366|      0|            }
 1367|      0|        }
 1368|       |
 1369|      0|        if (r.extensionsUsed.KHR_materials_clearcoat) {
  ------------------
  |  Branch (1369:13): [True: 0, False: 0]
  ------------------
 1370|      0|            if (Value *curMaterialClearcoat = FindObject(*extensions, "KHR_materials_clearcoat")) {
  ------------------
  |  Branch (1370:24): [True: 0, False: 0]
  ------------------
 1371|      0|                MaterialClearcoat clearcoat;
 1372|       |
 1373|      0|                ReadMember(*curMaterialClearcoat, "clearcoatFactor", clearcoat.clearcoatFactor);
 1374|      0|                ReadTextureProperty(r, *curMaterialClearcoat, "clearcoatTexture", clearcoat.clearcoatTexture);
 1375|      0|                ReadMember(*curMaterialClearcoat, "clearcoatRoughnessFactor", clearcoat.clearcoatRoughnessFactor);
 1376|      0|                ReadTextureProperty(r, *curMaterialClearcoat, "clearcoatRoughnessTexture", clearcoat.clearcoatRoughnessTexture);
 1377|      0|                ReadTextureProperty(r, *curMaterialClearcoat, "clearcoatNormalTexture", clearcoat.clearcoatNormalTexture);
 1378|       |
 1379|      0|                this->materialClearcoat = Nullable<MaterialClearcoat>(clearcoat);
 1380|      0|            }
 1381|      0|        }
 1382|       |
 1383|      0|        if (r.extensionsUsed.KHR_materials_transmission) {
  ------------------
  |  Branch (1383:13): [True: 0, False: 0]
  ------------------
 1384|      0|            if (Value *curMaterialTransmission = FindObject(*extensions, "KHR_materials_transmission")) {
  ------------------
  |  Branch (1384:24): [True: 0, False: 0]
  ------------------
 1385|      0|                MaterialTransmission transmission;
 1386|       |
 1387|      0|                ReadMember(*curMaterialTransmission, "transmissionFactor", transmission.transmissionFactor);
 1388|      0|                ReadTextureProperty(r, *curMaterialTransmission, "transmissionTexture", transmission.transmissionTexture);
 1389|       |
 1390|      0|                this->materialTransmission = Nullable<MaterialTransmission>(transmission);
 1391|      0|            }
 1392|      0|        }
 1393|       |
 1394|      0|        if (r.extensionsUsed.KHR_materials_volume) {
  ------------------
  |  Branch (1394:13): [True: 0, False: 0]
  ------------------
 1395|      0|            if (Value *curMaterialVolume = FindObject(*extensions, "KHR_materials_volume")) {
  ------------------
  |  Branch (1395:24): [True: 0, False: 0]
  ------------------
 1396|      0|                MaterialVolume volume;
 1397|       |
 1398|      0|                ReadMember(*curMaterialVolume, "thicknessFactor", volume.thicknessFactor);
 1399|      0|                ReadTextureProperty(r, *curMaterialVolume, "thicknessTexture", volume.thicknessTexture);
 1400|      0|                ReadMember(*curMaterialVolume, "attenuationDistance", volume.attenuationDistance);
 1401|      0|                ReadMember(*curMaterialVolume, "attenuationColor", volume.attenuationColor);
 1402|       |
 1403|      0|                this->materialVolume = Nullable<MaterialVolume>(volume);
 1404|      0|            }
 1405|      0|        }
 1406|       |
 1407|      0|        if (r.extensionsUsed.KHR_materials_ior) {
  ------------------
  |  Branch (1407:13): [True: 0, False: 0]
  ------------------
 1408|      0|            if (Value *curMaterialIOR = FindObject(*extensions, "KHR_materials_ior")) {
  ------------------
  |  Branch (1408:24): [True: 0, False: 0]
  ------------------
 1409|      0|                MaterialIOR ior;
 1410|       |
 1411|      0|                ReadMember(*curMaterialIOR, "ior", ior.ior);
 1412|       |
 1413|      0|                this->materialIOR = Nullable<MaterialIOR>(ior);
 1414|      0|            }
 1415|      0|        }
 1416|       |
 1417|      0|        if (r.extensionsUsed.KHR_materials_emissive_strength) {
  ------------------
  |  Branch (1417:13): [True: 0, False: 0]
  ------------------
 1418|      0|            if (Value *curMaterialEmissiveStrength = FindObject(*extensions, "KHR_materials_emissive_strength")) {
  ------------------
  |  Branch (1418:24): [True: 0, False: 0]
  ------------------
 1419|      0|                MaterialEmissiveStrength emissiveStrength;
 1420|       |
 1421|      0|                ReadMember(*curMaterialEmissiveStrength, "emissiveStrength", emissiveStrength.emissiveStrength);
 1422|       |
 1423|      0|                this->materialEmissiveStrength = Nullable<MaterialEmissiveStrength>(emissiveStrength);
 1424|      0|            }
 1425|      0|        }
 1426|       |
 1427|      0|        if (r.extensionsUsed.KHR_materials_anisotropy) {
  ------------------
  |  Branch (1427:13): [True: 0, False: 0]
  ------------------
 1428|      0|            if (Value *curMaterialAnisotropy = FindObject(*extensions, "KHR_materials_anisotropy")) {
  ------------------
  |  Branch (1428:24): [True: 0, False: 0]
  ------------------
 1429|      0|                MaterialAnisotropy anisotropy;
 1430|       |
 1431|      0|                ReadMember(*curMaterialAnisotropy, "anisotropyStrength", anisotropy.anisotropyStrength);
 1432|      0|                ReadMember(*curMaterialAnisotropy, "anisotropyRotation", anisotropy.anisotropyRotation);
 1433|      0|                ReadTextureProperty(r, *curMaterialAnisotropy, "anisotropyTexture", anisotropy.anisotropyTexture);
 1434|       |
 1435|      0|                this->materialAnisotropy = Nullable<MaterialAnisotropy>(anisotropy);
 1436|      0|            }
 1437|      0|        }
 1438|       |
 1439|      0|        unlit = nullptr != FindObject(*extensions, "KHR_materials_unlit");
 1440|      0|    }
 1441|      6|}
_ZN5glTF24Mesh4ReadERN9rapidjson12GenericValueINS1_4UTF8IcEENS1_19MemoryPoolAllocatorINS1_12CrtAllocatorEEEEERNS_5AssetE:
 1498|      8|inline void Mesh::Read(Value &pJSON_Object, Asset &pAsset_Root) {
 1499|      8|    Value *curName = FindMember(pJSON_Object, "name");
 1500|      8|    if (nullptr != curName && curName->IsString()) {
  ------------------
  |  Branch (1500:9): [True: 8, False: 0]
  |  Branch (1500:31): [True: 8, False: 0]
  ------------------
 1501|      8|        name = curName->GetString();
 1502|      8|    }
 1503|       |
 1504|       |    /****************** Mesh primitives ******************/
 1505|      8|    Value *curPrimitives = FindArray(pJSON_Object, "primitives");
 1506|      8|    if (nullptr != curPrimitives) {
  ------------------
  |  Branch (1506:9): [True: 8, False: 0]
  ------------------
 1507|      8|        this->primitives.resize(curPrimitives->Size());
 1508|     15|        for (unsigned int i = 0; i < curPrimitives->Size(); ++i) {
  ------------------
  |  Branch (1508:34): [True: 8, False: 7]
  ------------------
 1509|      8|            Value &primitive = (*curPrimitives)[i];
 1510|       |
 1511|      8|            Primitive &prim = this->primitives[i];
 1512|      8|            prim.mode = MemberOrDefault(primitive, "mode", PrimitiveMode_TRIANGLES);
 1513|       |
 1514|      8|            if (Value *indices = FindUInt(primitive, "indices")) {
  ------------------
  |  Branch (1514:24): [True: 8, False: 0]
  ------------------
 1515|      8|                prim.indices = pAsset_Root.accessors.Retrieve(indices->GetUint());
 1516|      8|            }
 1517|       |
 1518|      8|            if (Value *material = FindUInt(primitive, "material")) {
  ------------------
  |  Branch (1518:24): [True: 6, False: 2]
  ------------------
 1519|      6|                prim.material = pAsset_Root.materials.Retrieve(material->GetUint());
 1520|      6|            }
 1521|       |
 1522|      8|            if (Value *attrs = FindObject(primitive, "attributes")) {
  ------------------
  |  Branch (1522:24): [True: 5, False: 3]
  ------------------
 1523|     17|                for (Value::MemberIterator it = attrs->MemberBegin(); it != attrs->MemberEnd(); ++it) {
  ------------------
  |  Branch (1523:71): [True: 13, False: 4]
  ------------------
 1524|     13|                    if (!it->value.IsUint()) continue;
  ------------------
  |  Branch (1524:25): [True: 0, False: 13]
  ------------------
 1525|     13|                    const char *attr = it->name.GetString();
 1526|       |                    // Valid attribute semantics include POSITION, NORMAL, TANGENT, TEXCOORD, COLOR, JOINT, JOINTMATRIX,
 1527|       |                    // and WEIGHT.Attribute semantics can be of the form[semantic]_[set_index], e.g., TEXCOORD_0, TEXCOORD_1, etc.
 1528|       |
 1529|     13|                    int undPos = 0;
 1530|     13|                    Mesh::AccessorList *vec = nullptr;
 1531|     13|                    if (GetAttribVector(prim, attr, vec, undPos)) {
  ------------------
  |  Branch (1531:25): [True: 13, False: 0]
  ------------------
 1532|     13|                        size_t idx = (attr[undPos] == '_') ? atoi(attr + undPos + 1) : 0;
  ------------------
  |  Branch (1532:38): [True: 3, False: 10]
  ------------------
 1533|     13|                        if ((*vec).size() != idx) {
  ------------------
  |  Branch (1533:29): [True: 1, False: 12]
  ------------------
 1534|      1|                            throw DeadlyImportError("GLTF: Invalid attribute in mesh: ", name, " primitive: ", i, "attrib: ", attr,
 1535|      1|                                    ". All indices for indexed attribute semantics must start with 0 and be continuous positive integers: TEXCOORD_0, TEXCOORD_1, etc.");
 1536|      1|                        }
 1537|     12|                        (*vec).resize(idx + 1);
 1538|     12|                        (*vec)[idx] = pAsset_Root.accessors.Retrieve(it->value.GetUint());
 1539|     12|                    }
 1540|     13|                }
 1541|      5|            }
 1542|       |
 1543|       |#ifdef ASSIMP_ENABLE_DRACO
 1544|       |            // KHR_draco_mesh_compression spec: Draco can only be used for glTF Triangles or Triangle Strips
 1545|       |            if (pAsset_Root.extensionsUsed.KHR_draco_mesh_compression && (prim.mode == PrimitiveMode_TRIANGLES || prim.mode == PrimitiveMode_TRIANGLE_STRIP)) {
 1546|       |                // Look for draco mesh compression extension and bufferView
 1547|       |                // Skip if any missing
 1548|       |                if (Value *dracoExt = FindExtension(primitive, "KHR_draco_mesh_compression")) {
 1549|       |                    if (Value *bufView = FindUInt(*dracoExt, "bufferView")) {
 1550|       |                        // Attempt to load indices and attributes using draco compression
 1551|       |                        auto bufferView = pAsset_Root.bufferViews.Retrieve(bufView->GetUint());
 1552|       |                        // Attempt to perform the draco decode on the buffer data
 1553|       |                        const char *bufferViewData = reinterpret_cast<const char *>(bufferView->buffer->GetPointer() + bufferView->byteOffset);
 1554|       |                        draco::DecoderBuffer decoderBuffer;
 1555|       |                        decoderBuffer.Init(bufferViewData, bufferView->byteLength);
 1556|       |                        draco::Decoder decoder;
 1557|       |                        auto decodeResult = decoder.DecodeMeshFromBuffer(&decoderBuffer);
 1558|       |                        if (!decodeResult.ok()) {
 1559|       |                            // A corrupt Draco isn't actually fatal if the primitive data is also provided in a standard buffer, but does anyone do that?
 1560|       |                            throw DeadlyImportError("GLTF: Invalid Draco mesh compression in mesh: ", name, " primitive: ", i, ": ", decodeResult.status().error_msg_string());
 1561|       |                        }
 1562|       |
 1563|       |                        // Now we have a draco mesh
 1564|       |                        const std::unique_ptr<draco::Mesh> &pDracoMesh = decodeResult.value();
 1565|       |
 1566|       |                        // Redirect the accessors to the decoded data
 1567|       |
 1568|       |                        // Indices
 1569|       |                        SetDecodedIndexBuffer_Draco(*pDracoMesh, prim);
 1570|       |
 1571|       |                        // Vertex attributes
 1572|       |                        if (Value *attrs = FindObject(*dracoExt, "attributes")) {
 1573|       |                            for (Value::MemberIterator it = attrs->MemberBegin(); it != attrs->MemberEnd(); ++it) {
 1574|       |                                if (!it->value.IsUint()) continue;
 1575|       |                                const char *attr = it->name.GetString();
 1576|       |
 1577|       |                                int undPos = 0;
 1578|       |                                Mesh::AccessorList *vec = nullptr;
 1579|       |                                if (GetAttribVector(prim, attr, vec, undPos)) {
 1580|       |                                    size_t idx = (attr[undPos] == '_') ? atoi(attr + undPos + 1) : 0;
 1581|       |                                    if (idx >= (*vec).size()) {
 1582|       |                                        throw DeadlyImportError("GLTF: Invalid draco attribute in mesh: ", name, " primitive: ", i, " attrib: ", attr,
 1583|       |                                                ". All indices for indexed attribute semantics must start with 0 and be continuous positive integers: TEXCOORD_0, TEXCOORD_1, etc.");
 1584|       |                                    }
 1585|       |
 1586|       |                                    if (!(*vec)[idx]) {
 1587|       |                                        throw DeadlyImportError("GLTF: Invalid draco attribute in mesh: ", name, " primitive: ", i, " attrib: ", attr,
 1588|       |                                                ". All draco-encoded attributes must also define an accessor.");
 1589|       |                                    }
 1590|       |
 1591|       |                                    Accessor &attribAccessor = *(*vec)[idx];
 1592|       |                                    if (attribAccessor.count == 0)
 1593|       |                                        throw DeadlyImportError("GLTF: Invalid draco attribute in mesh: ", name, " primitive: ", i, " attrib: ", attr);
 1594|       |
 1595|       |                                    // Redirect this accessor to the appropriate Draco vertex attribute data
 1596|       |                                    const uint32_t dracoAttribId = it->value.GetUint();
 1597|       |                                    SetDecodedAttributeBuffer_Draco(*pDracoMesh, dracoAttribId, attribAccessor);
 1598|       |                                }
 1599|       |                            }
 1600|       |                        }
 1601|       |                    }
 1602|       |                }
 1603|       |            }
 1604|       |#endif
 1605|       |
 1606|      7|            Value *targetsArray = FindArray(primitive, "targets");
 1607|      7|            if (nullptr != targetsArray) {
  ------------------
  |  Branch (1607:17): [True: 0, False: 7]
  ------------------
 1608|      0|                prim.targets.resize(targetsArray->Size());
 1609|      0|                for (unsigned int j = 0; j < targetsArray->Size(); ++j) {
  ------------------
  |  Branch (1609:42): [True: 0, False: 0]
  ------------------
 1610|      0|                    Value &target = (*targetsArray)[j];
 1611|      0|                    if (!target.IsObject()) {
  ------------------
  |  Branch (1611:25): [True: 0, False: 0]
  ------------------
 1612|      0|                        continue;
 1613|      0|                    }
 1614|      0|                    for (Value::MemberIterator it = target.MemberBegin(); it != target.MemberEnd(); ++it) {
  ------------------
  |  Branch (1614:75): [True: 0, False: 0]
  ------------------
 1615|      0|                        if (!it->value.IsUint()) {
  ------------------
  |  Branch (1615:29): [True: 0, False: 0]
  ------------------
 1616|      0|                            continue;
 1617|      0|                        }
 1618|      0|                        const char *attr = it->name.GetString();
 1619|       |                        // Valid attribute semantics include POSITION, NORMAL, TANGENT
 1620|      0|                        int undPos = 0;
 1621|      0|                        Mesh::AccessorList *vec = nullptr;
 1622|      0|                        if (GetAttribTargetVector(prim, j, attr, vec, undPos)) {
  ------------------
  |  Branch (1622:29): [True: 0, False: 0]
  ------------------
 1623|      0|                            size_t idx = (attr[undPos] == '_') ? atoi(attr + undPos + 1) : 0;
  ------------------
  |  Branch (1623:42): [True: 0, False: 0]
  ------------------
 1624|      0|                            if ((*vec).size() <= idx) {
  ------------------
  |  Branch (1624:33): [True: 0, False: 0]
  ------------------
 1625|      0|                                (*vec).resize(idx + 1);
 1626|      0|                            }
 1627|      0|                            (*vec)[idx] = pAsset_Root.accessors.Retrieve(it->value.GetUint());
 1628|      0|                        }
 1629|      0|                    }
 1630|      0|                }
 1631|      0|            }
 1632|       |
 1633|      7|            if(this->targetNames.empty())
  ------------------
  |  Branch (1633:16): [True: 4, False: 3]
  ------------------
 1634|      4|            {
 1635|      4|                Value *curExtras = FindObject(primitive, "extras");
 1636|      4|                if (nullptr != curExtras) {
  ------------------
  |  Branch (1636:21): [True: 0, False: 4]
  ------------------
 1637|      0|                    if (Value *curTargetNames = FindArray(*curExtras, "targetNames")) {
  ------------------
  |  Branch (1637:32): [True: 0, False: 0]
  ------------------
 1638|      0|                        this->targetNames.resize(curTargetNames->Size());
 1639|      0|                        for (unsigned int j = 0; j < curTargetNames->Size(); ++j) {
  ------------------
  |  Branch (1639:50): [True: 0, False: 0]
  ------------------
 1640|      0|                            Value &targetNameValue = (*curTargetNames)[j];
 1641|      0|                            if (targetNameValue.IsString()) {
  ------------------
  |  Branch (1641:33): [True: 0, False: 0]
  ------------------
 1642|      0|                                this->targetNames[j] = targetNameValue.GetString();
 1643|      0|                            }
 1644|      0|                        }
 1645|      0|                    }
 1646|      0|                }
 1647|      4|            }
 1648|      7|        }
 1649|      8|    }
 1650|       |
 1651|      7|    Value *curWeights = FindArray(pJSON_Object, "weights");
 1652|      7|    if (nullptr != curWeights) {
  ------------------
  |  Branch (1652:9): [True: 0, False: 7]
  ------------------
 1653|      0|        this->weights.resize(curWeights->Size());
 1654|      0|        for (unsigned int i = 0; i < curWeights->Size(); ++i) {
  ------------------
  |  Branch (1654:34): [True: 0, False: 0]
  ------------------
 1655|      0|            Value &weightValue = (*curWeights)[i];
 1656|      0|            if (weightValue.IsNumber()) {
  ------------------
  |  Branch (1656:17): [True: 0, False: 0]
  ------------------
 1657|      0|                this->weights[i] = weightValue.GetFloat();
 1658|      0|            }
 1659|      0|        }
 1660|      0|    }
 1661|       |
 1662|      7|    Value *curExtras = FindObject(pJSON_Object, "extras");
 1663|      7|    if (nullptr != curExtras) {
  ------------------
  |  Branch (1663:9): [True: 0, False: 7]
  ------------------
 1664|      0|        if (Value *curTargetNames = FindArray(*curExtras, "targetNames")) {
  ------------------
  |  Branch (1664:20): [True: 0, False: 0]
  ------------------
 1665|      0|            this->targetNames.resize(curTargetNames->Size());
 1666|      0|            for (unsigned int i = 0; i < curTargetNames->Size(); ++i) {
  ------------------
  |  Branch (1666:38): [True: 0, False: 0]
  ------------------
 1667|      0|                Value &targetNameValue = (*curTargetNames)[i];
 1668|      0|                if (targetNameValue.IsString()) {
  ------------------
  |  Branch (1668:21): [True: 0, False: 0]
  ------------------
 1669|      0|                    this->targetNames[i] = targetNameValue.GetString();
 1670|      0|                }
 1671|      0|            }
 1672|      0|        }
 1673|      0|    }
 1674|      7|}
_ZN5glTF24Node4ReadERN9rapidjson12GenericValueINS1_4UTF8IcEENS1_19MemoryPoolAllocatorINS1_12CrtAllocatorEEEEERNS_5AssetE:
 1733|      9|inline void Node::Read(Value &obj, Asset &r) {
 1734|      9|    if (name.empty()) {
  ------------------
  |  Branch (1734:9): [True: 0, False: 9]
  ------------------
 1735|      0|        name = id;
 1736|      0|    }
 1737|       |
 1738|      9|    Value *curChildren = FindArray(obj, "children");
 1739|      9|    if (nullptr != curChildren) {
  ------------------
  |  Branch (1739:9): [True: 1, False: 8]
  ------------------
 1740|      1|        this->children.reserve(curChildren->Size());
 1741|      2|        for (unsigned int i = 0; i < curChildren->Size(); ++i) {
  ------------------
  |  Branch (1741:34): [True: 1, False: 1]
  ------------------
 1742|      1|            Value &child = (*curChildren)[i];
 1743|      1|            if (child.IsUint()) {
  ------------------
  |  Branch (1743:17): [True: 1, False: 0]
  ------------------
 1744|       |                // get/create the child node
 1745|      1|                Ref<Node> chn = r.nodes.Retrieve(child.GetUint());
 1746|      1|                if (chn) {
  ------------------
  |  Branch (1746:21): [True: 0, False: 1]
  ------------------
 1747|      0|                    this->children.push_back(chn);
 1748|      0|                }
 1749|      1|            }
 1750|      1|        }
 1751|      1|    }
 1752|       |
 1753|      9|    Value *curMatrix = FindArray(obj, "matrix");
 1754|      9|    if (nullptr != curMatrix) {
  ------------------
  |  Branch (1754:9): [True: 0, False: 9]
  ------------------
 1755|      0|        ReadValue(*curMatrix, this->matrix);
 1756|      9|    } else {
 1757|      9|        ReadMember(obj, "translation", translation);
 1758|      9|        ReadMember(obj, "scale", scale);
 1759|      9|        ReadMember(obj, "rotation", rotation);
 1760|      9|    }
 1761|       |
 1762|      9|    Value *curMesh = FindUInt(obj, "mesh");
 1763|      9|    if (nullptr != curMesh) {
  ------------------
  |  Branch (1763:9): [True: 8, False: 1]
  ------------------
 1764|      8|        unsigned int numMeshes = 1;
 1765|      8|        this->meshes.reserve(numMeshes);
 1766|      8|        Ref<Mesh> meshRef = r.meshes.Retrieve((*curMesh).GetUint());
 1767|      8|        if (meshRef) {
  ------------------
  |  Branch (1767:13): [True: 4, False: 4]
  ------------------
 1768|      4|            this->meshes.push_back(meshRef);
 1769|      4|        }
 1770|      8|    }
 1771|       |
 1772|       |    // Do not retrieve a skin here, just take a reference, to avoid infinite recursion
 1773|       |    // Skins will be properly loaded later
 1774|      9|    Value *curSkin = FindUInt(obj, "skin");
 1775|      9|    if (nullptr != curSkin) {
  ------------------
  |  Branch (1775:9): [True: 0, False: 9]
  ------------------
 1776|      0|        this->skin = r.skins.Get(curSkin->GetUint());
 1777|      0|    }
 1778|       |
 1779|      9|    Value *curCamera = FindUInt(obj, "camera");
 1780|      9|    if (nullptr != curCamera) {
  ------------------
  |  Branch (1780:9): [True: 0, False: 9]
  ------------------
 1781|      0|        this->camera = r.cameras.Retrieve(curCamera->GetUint());
 1782|      0|        if (this->camera) {
  ------------------
  |  Branch (1782:13): [True: 0, False: 0]
  ------------------
 1783|      0|            this->camera->id = this->id;
 1784|      0|        }
 1785|      0|    }
 1786|       |
 1787|      9|    Value *curExtensions = FindObject(obj, "extensions");
 1788|      9|    if (nullptr != curExtensions) {
  ------------------
  |  Branch (1788:9): [True: 0, False: 9]
  ------------------
 1789|      0|        if (r.extensionsUsed.KHR_lights_punctual) {
  ------------------
  |  Branch (1789:13): [True: 0, False: 0]
  ------------------
 1790|      0|            if (Value *ext = FindObject(*curExtensions, "KHR_lights_punctual")) {
  ------------------
  |  Branch (1790:24): [True: 0, False: 0]
  ------------------
 1791|      0|                Value *curLight = FindUInt(*ext, "light");
 1792|      0|                if (nullptr != curLight) {
  ------------------
  |  Branch (1792:21): [True: 0, False: 0]
  ------------------
 1793|      0|                    this->light = r.lights.Retrieve(curLight->GetUint());
 1794|      0|                    if (this->light) {
  ------------------
  |  Branch (1794:25): [True: 0, False: 0]
  ------------------
 1795|      0|                        this->light->id = this->id;
 1796|      0|                    }
 1797|      0|                }
 1798|      0|            }
 1799|      0|        }
 1800|      0|    }
 1801|      9|}
_ZN5glTF25Scene4ReadERN9rapidjson12GenericValueINS1_4UTF8IcEENS1_19MemoryPoolAllocatorINS1_12CrtAllocatorEEEEERNS_5AssetE:
 1803|      4|inline void Scene::Read(Value &obj, Asset &r) {
 1804|      4|    if (Value *scene_name = FindString(obj, "name")) {
  ------------------
  |  Branch (1804:16): [True: 4, False: 0]
  ------------------
 1805|      4|        if (scene_name->IsString()) {
  ------------------
  |  Branch (1805:13): [True: 4, False: 0]
  ------------------
 1806|      4|            this->name = scene_name->GetString();
 1807|      4|        }
 1808|      4|    }
 1809|      4|    if (Value *array = FindArray(obj, "nodes")) {
  ------------------
  |  Branch (1809:16): [True: 4, False: 0]
  ------------------
 1810|     12|        for (unsigned int i = 0; i < array->Size(); ++i) {
  ------------------
  |  Branch (1810:34): [True: 8, False: 4]
  ------------------
 1811|      8|            if (!(*array)[i].IsUint()) continue;
  ------------------
  |  Branch (1811:17): [True: 0, False: 8]
  ------------------
 1812|      8|            Ref<Node> node = r.nodes.Retrieve((*array)[i].GetUint());
 1813|      8|            if (node)
  ------------------
  |  Branch (1813:17): [True: 4, False: 4]
  ------------------
 1814|      4|                this->nodes.push_back(node);
 1815|      8|        }
 1816|      4|    }
 1817|      4|}
_ZN5glTF213AssetMetadata4ReadERN9rapidjson15GenericDocumentINS1_4UTF8IcEENS1_19MemoryPoolAllocatorINS1_12CrtAllocatorEEES6_EE:
 1896|     11|inline void AssetMetadata::Read(Document &doc) {
 1897|     11|    if (Value *obj = FindObject(doc, "asset")) {
  ------------------
  |  Branch (1897:16): [True: 11, False: 0]
  ------------------
 1898|     11|        ReadMember(*obj, "copyright", copyright);
 1899|     11|        ReadMember(*obj, "generator", generator);
 1900|       |
 1901|     11|        if (Value *versionString = FindStringInContext(*obj, "version", "\"asset\"")) {
  ------------------
  |  Branch (1901:20): [True: 10, False: 1]
  ------------------
 1902|     10|            version = versionString->GetString();
 1903|     10|        }
 1904|     11|        Value *curProfile = FindObjectInContext(*obj, "profile", "\"asset\"");
 1905|     11|        if (nullptr != curProfile) {
  ------------------
  |  Branch (1905:13): [True: 0, False: 11]
  ------------------
 1906|      0|            ReadMember(*curProfile, "api", this->profile.api);
 1907|      0|            ReadMember(*curProfile, "version", this->profile.version);
 1908|      0|        }
 1909|     11|    }
 1910|       |
 1911|     11|    if (version.empty() || version[0] != '2') {
  ------------------
  |  Branch (1911:9): [True: 1, False: 10]
  |  Branch (1911:28): [True: 0, False: 10]
  ------------------
 1912|      0|        throw DeadlyImportError("GLTF: Unsupported glTF version: ", version);
 1913|      0|    }
 1914|     11|}
_ZN5glTF25Asset16ReadBinaryHeaderERN6Assimp8IOStreamERNSt3__16vectorIcNS4_9allocatorIcEEEE:
 1920|      1|inline void Asset::ReadBinaryHeader(IOStream &stream, std::vector<char> &sceneData) {
 1921|      1|    ASSIMP_LOG_DEBUG("Reading GLTF2 binary");
 1922|      1|    GLB_Header header;
 1923|      1|    if (stream.Read(&header, sizeof(header), 1) != 1) {
  ------------------
  |  Branch (1923:9): [True: 0, False: 1]
  ------------------
 1924|      0|        throw DeadlyImportError("GLTF: Unable to read the file header");
 1925|      0|    }
 1926|       |
 1927|      1|    if (strncmp((char *)header.magic, AI_GLB_MAGIC_NUMBER, sizeof(header.magic)) != 0) {
  ------------------
  |  |  147|      1|#define AI_GLB_MAGIC_NUMBER "glTF"
  ------------------
  |  Branch (1927:9): [True: 0, False: 1]
  ------------------
 1928|      0|        throw DeadlyImportError("GLTF: Invalid binary glTF file");
 1929|      0|    }
 1930|       |
 1931|      1|    AI_SWAP4(header.version);
 1932|      1|    asset.version = ai_to_string(header.version);
 1933|      1|    if (header.version != 2) {
  ------------------
  |  Branch (1933:9): [True: 1, False: 0]
  ------------------
 1934|      1|        throw DeadlyImportError("GLTF: Unsupported binary glTF version");
 1935|      1|    }
 1936|       |
 1937|      0|    GLB_Chunk chunk;
 1938|      0|    if (stream.Read(&chunk, sizeof(chunk), 1) != 1) {
  ------------------
  |  Branch (1938:9): [True: 0, False: 0]
  ------------------
 1939|      0|        throw DeadlyImportError("GLTF: Unable to read JSON chunk");
 1940|      0|    }
 1941|       |
 1942|      0|    AI_SWAP4(chunk.chunkLength);
 1943|      0|    AI_SWAP4(chunk.chunkType);
 1944|       |
 1945|      0|    if (chunk.chunkType != ChunkType_JSON) {
  ------------------
  |  Branch (1945:9): [True: 0, False: 0]
  ------------------
 1946|      0|        throw DeadlyImportError("GLTF: JSON chunk missing");
 1947|      0|    }
 1948|       |
 1949|       |    // read the scene data, ensure null termination
 1950|      0|    static_assert(std::numeric_limits<uint32_t>::max() <= std::numeric_limits<size_t>::max(), "size_t must be at least 32bits");
 1951|      0|    mSceneLength = chunk.chunkLength; // Can't be larger than 4GB (max. uint32_t)
 1952|      0|    sceneData.resize(mSceneLength + 1);
 1953|      0|    sceneData[mSceneLength] = '\0';
 1954|       |
 1955|      0|    if (stream.Read(&sceneData[0], 1, mSceneLength) != mSceneLength) {
  ------------------
  |  Branch (1955:9): [True: 0, False: 0]
  ------------------
 1956|      0|        throw DeadlyImportError("GLTF: Could not read the file contents");
 1957|      0|    }
 1958|       |
 1959|      0|    uint32_t padding = ((chunk.chunkLength + 3) & ~3) - chunk.chunkLength;
 1960|      0|    if (padding > 0) {
  ------------------
  |  Branch (1960:9): [True: 0, False: 0]
  ------------------
 1961|      0|        stream.Seek(padding, aiOrigin_CUR);
 1962|      0|    }
 1963|       |
 1964|      0|    AI_SWAP4(header.length);
 1965|      0|    mBodyOffset = 12 + 8 + chunk.chunkLength + padding + 8;
 1966|      0|    if (header.length >= mBodyOffset) {
  ------------------
  |  Branch (1966:9): [True: 0, False: 0]
  ------------------
 1967|      0|        if (stream.Read(&chunk, sizeof(chunk), 1) != 1) {
  ------------------
  |  Branch (1967:13): [True: 0, False: 0]
  ------------------
 1968|      0|            throw DeadlyImportError("GLTF: Unable to read BIN chunk");
 1969|      0|        }
 1970|       |
 1971|      0|        AI_SWAP4(chunk.chunkLength);
 1972|      0|        AI_SWAP4(chunk.chunkType);
 1973|       |
 1974|      0|        if (chunk.chunkType != ChunkType_BIN) {
  ------------------
  |  Branch (1974:13): [True: 0, False: 0]
  ------------------
 1975|      0|            throw DeadlyImportError("GLTF: BIN chunk missing");
 1976|      0|        }
 1977|       |
 1978|      0|        mBodyLength = chunk.chunkLength;
 1979|      0|    } else {
 1980|      0|        mBodyOffset = mBodyLength = 0;
 1981|      0|    }
 1982|      0|}
_ZN5glTF25Asset12ReadDocumentERN6Assimp8IOStreamEbRNSt3__16vectorIcNS4_9allocatorIcEEEE:
 1984|     53|inline rapidjson::Document Asset::ReadDocument(IOStream &stream, bool isBinary, std::vector<char> &sceneData) {
 1985|     53|    ASSIMP_LOG_DEBUG("Loading GLTF2 asset");
 1986|       |
 1987|       |    // is binary? then read the header
 1988|     53|    if (isBinary) {
  ------------------
  |  Branch (1988:9): [True: 1, False: 52]
  ------------------
 1989|      1|        SetAsBinary(); // also creates the body buffer
 1990|      1|        ReadBinaryHeader(stream, sceneData);
 1991|     52|    } else {
 1992|     52|        mSceneLength = stream.FileSize();
 1993|     52|        mBodyLength = 0;
 1994|       |
 1995|       |        // Binary format only supports up to 4GB of JSON, use that as a maximum
 1996|     52|        if (mSceneLength >= std::numeric_limits<uint32_t>::max()) {
  ------------------
  |  Branch (1996:13): [True: 0, False: 52]
  ------------------
 1997|      0|            throw DeadlyImportError("GLTF: JSON size greater than 4GB");
 1998|      0|        }
 1999|       |
 2000|       |        // read the scene data, ensure null termination
 2001|     52|        sceneData.resize(mSceneLength + 1);
 2002|     52|        sceneData[mSceneLength] = '\0';
 2003|       |
 2004|     52|        if (stream.Read(&sceneData[0], 1, mSceneLength) != mSceneLength) {
  ------------------
  |  Branch (2004:13): [True: 0, False: 52]
  ------------------
 2005|      0|            throw DeadlyImportError("GLTF: Could not read the file contents");
 2006|      0|        }
 2007|     52|    }
 2008|       |
 2009|       |    // Smallest legal JSON file is "{}" Smallest loadable glTF file is larger than that but catch it later
 2010|     53|    if (mSceneLength < 2) {
  ------------------
  |  Branch (2010:9): [True: 0, False: 53]
  ------------------
 2011|      0|        throw DeadlyImportError("GLTF: No JSON file contents");
 2012|      0|    }
 2013|       |
 2014|       |    // parse the JSON document
 2015|     53|    ASSIMP_LOG_DEBUG("Parsing GLTF2 JSON");
 2016|     53|    Document doc;
 2017|     53|    doc.ParseInsitu(&sceneData[0]);
 2018|       |
 2019|     53|    if (doc.HasParseError()) {
  ------------------
  |  Branch (2019:9): [True: 40, False: 13]
  ------------------
 2020|     40|        char buffer[32];
 2021|     40|        ai_snprintf(buffer, 32, "%d", static_cast<int>(doc.GetErrorOffset()));
 2022|     40|        throw DeadlyImportError("GLTF: JSON parse error, offset ", buffer, ": ", GetParseError_En(doc.GetParseError()));
 2023|     40|    }
 2024|       |
 2025|     13|    if (!doc.IsObject()) {
  ------------------
  |  Branch (2025:9): [True: 1, False: 12]
  ------------------
 2026|      1|        throw DeadlyImportError("GLTF: JSON document root must be a JSON object");
 2027|      1|    }
 2028|       |
 2029|     12|    return doc;
 2030|     13|}
_ZN5glTF25Asset4LoadERKNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEb:
 2033|      5|{
 2034|      5|    mCurrentAssetDir.clear();
 2035|      5|    if (0 != strncmp(pFile.c_str(), AI_MEMORYIO_MAGIC_FILENAME, AI_MEMORYIO_MAGIC_FILENAME_LENGTH)) {
  ------------------
  |  Branch (2035:9): [True: 0, False: 5]
  ------------------
 2036|      0|        mCurrentAssetDir = glTFCommon::getCurrentAssetDir(pFile);
 2037|      0|    }
 2038|       |
 2039|      5|    shared_ptr<IOStream> stream(OpenFile(pFile.c_str(), "rb", true));
 2040|      5|    if (!stream) {
  ------------------
  |  Branch (2040:9): [True: 0, False: 5]
  ------------------
 2041|      0|        throw DeadlyImportError("GLTF: Could not open file for reading");
 2042|      0|    }
 2043|       |
 2044|      5|    std::vector<char> sceneData;
 2045|      5|    rapidjson::Document doc = ReadDocument(*stream, isBinary, sceneData);
 2046|       |
 2047|       |    // If a schemaDocumentProvider is available, see if the glTF schema is present.
 2048|       |    // If so, use it to validate the document.
 2049|      5|    if (mSchemaDocumentProvider) {
  ------------------
  |  Branch (2049:9): [True: 0, False: 5]
  ------------------
 2050|      0|        if (const rapidjson::SchemaDocument *gltfSchema = mSchemaDocumentProvider->GetRemoteDocument("glTF.schema.json", 16)) {
  ------------------
  |  Branch (2050:46): [True: 0, False: 0]
  ------------------
 2051|       |            // The schemas are found here: https://github.com/KhronosGroup/glTF/tree/main/specification/2.0/schema
 2052|      0|            rapidjson::SchemaValidator validator(*gltfSchema);
 2053|      0|            if (!doc.Accept(validator)) {
  ------------------
  |  Branch (2053:17): [True: 0, False: 0]
  ------------------
 2054|      0|                rapidjson::StringBuffer pathBuffer;
 2055|      0|                validator.GetInvalidSchemaPointer().StringifyUriFragment(pathBuffer);
 2056|      0|                rapidjson::StringBuffer argumentBuffer;
 2057|      0|                validator.GetInvalidDocumentPointer().StringifyUriFragment(argumentBuffer);
 2058|      0|                throw DeadlyImportError("GLTF: The JSON document did not satisfy the glTF2 schema. Schema keyword: ", validator.GetInvalidSchemaKeyword(), ", document path: ", pathBuffer.GetString(), ", argument: ", argumentBuffer.GetString());
 2059|      0|            }
 2060|      0|        }
 2061|      0|    }
 2062|       |
 2063|       |    // Fill the buffer instance for the current file embedded contents
 2064|      5|    if (mBodyLength > 0) {
  ------------------
  |  Branch (2064:9): [True: 0, False: 5]
  ------------------
 2065|      0|        if (!mBodyBuffer->LoadFromStream(*stream, mBodyLength, mBodyOffset)) {
  ------------------
  |  Branch (2065:13): [True: 0, False: 0]
  ------------------
 2066|      0|            throw DeadlyImportError("GLTF: Unable to read gltf file");
 2067|      0|        }
 2068|      0|    }
 2069|       |
 2070|       |    // Load the metadata
 2071|      5|    asset.Read(doc);
 2072|      5|    ReadExtensionsUsed(doc);
 2073|      5|    ReadExtensionsRequired(doc);
 2074|       |
 2075|      5|#ifndef ASSIMP_ENABLE_DRACO
 2076|       |    // Is Draco required?
 2077|      5|    if (extensionsRequired.KHR_draco_mesh_compression) {
  ------------------
  |  Branch (2077:9): [True: 1, False: 4]
  ------------------
 2078|      1|        throw DeadlyImportError("GLTF: Draco mesh compression not supported.");
 2079|      1|    }
 2080|      4|#endif
 2081|       |
 2082|       |    // Prepare the dictionaries
 2083|     60|    for (size_t i = 0; i < mDicts.size(); ++i) {
  ------------------
  |  Branch (2083:24): [True: 56, False: 4]
  ------------------
 2084|     56|        mDicts[i]->AttachToDocument(doc);
 2085|     56|    }
 2086|       |
 2087|       |    // Read the "extensions" property, then add it to each scene's metadata.
 2088|      4|    CustomExtension customExtensions;
 2089|      4|    if (Value *extensionsObject = FindObject(doc, "extensions")) {
  ------------------
  |  Branch (2089:16): [True: 0, False: 4]
  ------------------
 2090|      0|        customExtensions = glTF2::ReadExtensions("extensions", *extensionsObject);
 2091|      0|    }
 2092|       |
 2093|       |    // Read the "scene" property, which specifies which scene to load
 2094|       |    // and recursively load everything referenced by it
 2095|      4|    unsigned int sceneIndex = 0;
 2096|      4|    Value *curScene = FindUInt(doc, "scene");
 2097|      4|    if (nullptr != curScene) {
  ------------------
  |  Branch (2097:9): [True: 4, False: 0]
  ------------------
 2098|      4|        sceneIndex = curScene->GetUint();
 2099|      4|    }
 2100|       |
 2101|      4|    if (Value *scenesArray = FindArray(doc, "scenes")) {
  ------------------
  |  Branch (2101:16): [True: 4, False: 0]
  ------------------
 2102|      4|        if (sceneIndex < scenesArray->Size()) {
  ------------------
  |  Branch (2102:13): [True: 4, False: 0]
  ------------------
 2103|      4|            this->scene = scenes.Retrieve(sceneIndex);
 2104|       |
 2105|      4|            this->scene->customExtensions = customExtensions;
 2106|      4|        }
 2107|      4|    }
 2108|       |
 2109|      4|    if (Value *skinsArray = FindArray(doc, "skins")) {
  ------------------
  |  Branch (2109:16): [True: 0, False: 4]
  ------------------
 2110|      0|        for (unsigned int i = 0; i < skinsArray->Size(); ++i) {
  ------------------
  |  Branch (2110:34): [True: 0, False: 0]
  ------------------
 2111|      0|            skins.Retrieve(i);
 2112|      0|        }
 2113|      0|    }
 2114|       |
 2115|      4|    if (Value *animsArray = FindArray(doc, "animations")) {
  ------------------
  |  Branch (2115:16): [True: 0, False: 4]
  ------------------
 2116|      0|        for (unsigned int i = 0; i < animsArray->Size(); ++i) {
  ------------------
  |  Branch (2116:34): [True: 0, False: 0]
  ------------------
 2117|      0|            animations.Retrieve(i);
 2118|      0|        }
 2119|      0|    }
 2120|       |
 2121|       |    // Clean up
 2122|      4|    for (size_t i = 0; i < mDicts.size(); ++i) {
  ------------------
  |  Branch (2122:24): [True: 0, False: 4]
  ------------------
 2123|      0|        mDicts[i]->DetachFromDocument();
 2124|      0|    }
 2125|      4|}
_ZN5glTF25Asset7CanReadERKNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEb:
 2127|     48|inline bool Asset::CanRead(const std::string &pFile, bool isBinary) {
 2128|     48|    try {
 2129|     48|        shared_ptr<IOStream> stream(OpenFile(pFile.c_str(), "rb", true));
 2130|     48|        if (!stream) {
  ------------------
  |  Branch (2130:13): [True: 0, False: 48]
  ------------------
 2131|      0|            return false;
 2132|      0|        }
 2133|     48|        std::vector<char> sceneData;
 2134|     48|        rapidjson::Document doc = ReadDocument(*stream, isBinary, sceneData);
 2135|     48|        asset.Read(doc);
 2136|     48|    } catch (...) {
 2137|     43|        return false;
 2138|     43|    }
 2139|      5|    return true;
 2140|     48|}
_ZN5glTF25Asset22ReadExtensionsRequiredERN9rapidjson15GenericDocumentINS1_4UTF8IcEENS1_19MemoryPoolAllocatorINS1_12CrtAllocatorEEES6_EE:
 2154|      5|inline void Asset::ReadExtensionsRequired(Document &doc) {
 2155|      5|    Value *extsRequired = FindArray(doc, "extensionsRequired");
 2156|      5|    if (nullptr == extsRequired) {
  ------------------
  |  Branch (2156:9): [True: 4, False: 1]
  ------------------
 2157|      4|        return;
 2158|      4|    }
 2159|       |
 2160|      1|    std::gltf_unordered_map<std::string, bool> exts;
 2161|      2|    for (unsigned int i = 0; i < extsRequired->Size(); ++i) {
  ------------------
  |  Branch (2161:30): [True: 1, False: 1]
  ------------------
 2162|      1|        if ((*extsRequired)[i].IsString()) {
  ------------------
  |  Branch (2162:13): [True: 1, False: 0]
  ------------------
 2163|      1|            exts[(*extsRequired)[i].GetString()] = true;
 2164|      1|        }
 2165|      1|    }
 2166|       |
 2167|      1|    CHECK_REQUIRED_EXT(KHR_draco_mesh_compression);
  ------------------
  |  | 2152|      1|    if (exts.find(#EXT) != exts.end()) extensionsRequired.EXT = true;
  |  |  ------------------
  |  |  |  Branch (2152:9): [True: 1, False: 0]
  |  |  ------------------
  ------------------
 2168|      1|    CHECK_REQUIRED_EXT(KHR_texture_basisu);
  ------------------
  |  | 2152|      1|    if (exts.find(#EXT) != exts.end()) extensionsRequired.EXT = true;
  |  |  ------------------
  |  |  |  Branch (2152:9): [True: 0, False: 1]
  |  |  ------------------
  ------------------
 2169|      1|    CHECK_REQUIRED_EXT(EXT_texture_webp);
  ------------------
  |  | 2152|      1|    if (exts.find(#EXT) != exts.end()) extensionsRequired.EXT = true;
  |  |  ------------------
  |  |  |  Branch (2152:9): [True: 0, False: 1]
  |  |  ------------------
  ------------------
 2170|       |
 2171|      1|#undef CHECK_REQUIRED_EXT
 2172|      1|}
_ZN5glTF25Asset18ReadExtensionsUsedERN9rapidjson15GenericDocumentINS1_4UTF8IcEENS1_19MemoryPoolAllocatorINS1_12CrtAllocatorEEES6_EE:
 2174|      5|inline void Asset::ReadExtensionsUsed(Document &doc) {
 2175|      5|    Value *extsUsed = FindArray(doc, "extensionsUsed");
 2176|      5|    if (!extsUsed) return;
  ------------------
  |  Branch (2176:9): [True: 3, False: 2]
  ------------------
 2177|       |
 2178|      2|    std::gltf_unordered_map<std::string, bool> exts;
 2179|       |
 2180|      4|    for (unsigned int i = 0; i < extsUsed->Size(); ++i) {
  ------------------
  |  Branch (2180:30): [True: 2, False: 2]
  ------------------
 2181|      2|        if ((*extsUsed)[i].IsString()) {
  ------------------
  |  Branch (2181:13): [True: 2, False: 0]
  ------------------
 2182|      2|            exts[(*extsUsed)[i].GetString()] = true;
 2183|      2|        }
 2184|      2|    }
 2185|       |
 2186|      2|    CHECK_EXT(KHR_materials_pbrSpecularGlossiness);
  ------------------
  |  |  237|      2|    if (exts.find(#EXT) != exts.end()) extensionsUsed.EXT = true;
  |  |  ------------------
  |  |  |  Branch (237:9): [True: 0, False: 2]
  |  |  ------------------
  ------------------
 2187|      2|    CHECK_EXT(KHR_materials_specular);
  ------------------
  |  |  237|      2|    if (exts.find(#EXT) != exts.end()) extensionsUsed.EXT = true;
  |  |  ------------------
  |  |  |  Branch (237:9): [True: 0, False: 2]
  |  |  ------------------
  ------------------
 2188|      2|    CHECK_EXT(KHR_materials_unlit);
  ------------------
  |  |  237|      2|    if (exts.find(#EXT) != exts.end()) extensionsUsed.EXT = true;
  |  |  ------------------
  |  |  |  Branch (237:9): [True: 0, False: 2]
  |  |  ------------------
  ------------------
 2189|      2|    CHECK_EXT(KHR_lights_punctual);
  ------------------
  |  |  237|      2|    if (exts.find(#EXT) != exts.end()) extensionsUsed.EXT = true;
  |  |  ------------------
  |  |  |  Branch (237:9): [True: 0, False: 2]
  |  |  ------------------
  ------------------
 2190|      2|    CHECK_EXT(KHR_texture_transform);
  ------------------
  |  |  237|      2|    if (exts.find(#EXT) != exts.end()) extensionsUsed.EXT = true;
  |  |  ------------------
  |  |  |  Branch (237:9): [True: 0, False: 2]
  |  |  ------------------
  ------------------
 2191|      2|    CHECK_EXT(KHR_materials_sheen);
  ------------------
  |  |  237|      2|    if (exts.find(#EXT) != exts.end()) extensionsUsed.EXT = true;
  |  |  ------------------
  |  |  |  Branch (237:9): [True: 0, False: 2]
  |  |  ------------------
  ------------------
 2192|      2|    CHECK_EXT(KHR_materials_clearcoat);
  ------------------
  |  |  237|      2|    if (exts.find(#EXT) != exts.end()) extensionsUsed.EXT = true;
  |  |  ------------------
  |  |  |  Branch (237:9): [True: 1, False: 1]
  |  |  ------------------
  ------------------
 2193|      2|    CHECK_EXT(KHR_materials_transmission);
  ------------------
  |  |  237|      2|    if (exts.find(#EXT) != exts.end()) extensionsUsed.EXT = true;
  |  |  ------------------
  |  |  |  Branch (237:9): [True: 0, False: 2]
  |  |  ------------------
  ------------------
 2194|      2|    CHECK_EXT(KHR_materials_volume);
  ------------------
  |  |  237|      2|    if (exts.find(#EXT) != exts.end()) extensionsUsed.EXT = true;
  |  |  ------------------
  |  |  |  Branch (237:9): [True: 0, False: 2]
  |  |  ------------------
  ------------------
 2195|      2|    CHECK_EXT(KHR_materials_ior);
  ------------------
  |  |  237|      2|    if (exts.find(#EXT) != exts.end()) extensionsUsed.EXT = true;
  |  |  ------------------
  |  |  |  Branch (237:9): [True: 0, False: 2]
  |  |  ------------------
  ------------------
 2196|      2|    CHECK_EXT(KHR_materials_emissive_strength);
  ------------------
  |  |  237|      2|    if (exts.find(#EXT) != exts.end()) extensionsUsed.EXT = true;
  |  |  ------------------
  |  |  |  Branch (237:9): [True: 0, False: 2]
  |  |  ------------------
  ------------------
 2197|      2|    CHECK_EXT(KHR_materials_anisotropy);
  ------------------
  |  |  237|      2|    if (exts.find(#EXT) != exts.end()) extensionsUsed.EXT = true;
  |  |  ------------------
  |  |  |  Branch (237:9): [True: 0, False: 2]
  |  |  ------------------
  ------------------
 2198|      2|    CHECK_EXT(KHR_draco_mesh_compression);
  ------------------
  |  |  237|      2|    if (exts.find(#EXT) != exts.end()) extensionsUsed.EXT = true;
  |  |  ------------------
  |  |  |  Branch (237:9): [True: 1, False: 1]
  |  |  ------------------
  ------------------
 2199|      2|    CHECK_EXT(KHR_texture_basisu);
  ------------------
  |  |  237|      2|    if (exts.find(#EXT) != exts.end()) extensionsUsed.EXT = true;
  |  |  ------------------
  |  |  |  Branch (237:9): [True: 0, False: 2]
  |  |  ------------------
  ------------------
 2200|      2|    CHECK_EXT(EXT_texture_webp);
  ------------------
  |  |  237|      2|    if (exts.find(#EXT) != exts.end()) extensionsUsed.EXT = true;
  |  |  ------------------
  |  |  |  Branch (237:9): [True: 0, False: 2]
  |  |  ------------------
  ------------------
 2201|       |
 2202|      2|#undef CHECK_EXT
 2203|      2|}
_ZN5glTF28LazyDictINS_6BufferEE8RetrieveEj:
  473|     20|Ref<T> LazyDict<T>::Retrieve(unsigned int i) {
  474|     20|    typename Dict::iterator it = mObjsByOIndex.find(i);
  475|     20|    if (it != mObjsByOIndex.end()) { // already created?
  ------------------
  |  Branch (475:9): [True: 16, False: 4]
  ------------------
  476|     16|        return Ref<T>(mObjs, it->second);
  477|     16|    }
  478|       |
  479|       |    // read it from the JSON object
  480|      4|    if (!mDict) {
  ------------------
  |  Branch (480:9): [True: 0, False: 4]
  ------------------
  481|      0|        throw DeadlyImportError("GLTF: Missing section \"", mDictId, "\"");
  482|      0|    }
  483|       |
  484|      4|    if (!mDict->IsArray()) {
  ------------------
  |  Branch (484:9): [True: 0, False: 4]
  ------------------
  485|      0|        throw DeadlyImportError("GLTF: Field \"", mDictId, "\"  is not an array");
  486|      0|    }
  487|       |
  488|      4|    if (i >= mDict->Size()) {
  ------------------
  |  Branch (488:9): [True: 0, False: 4]
  ------------------
  489|      0|        throw DeadlyImportError("GLTF: Array index ", i, " is out of bounds (", mDict->Size(), ") for \"", mDictId, "\"");
  490|      0|    }
  491|       |
  492|      4|    Value &obj = (*mDict)[i];
  493|       |
  494|      4|    if (!obj.IsObject()) {
  ------------------
  |  Branch (494:9): [True: 0, False: 4]
  ------------------
  495|      0|        throw DeadlyImportError("GLTF: Object at index ", i, " in array \"", mDictId, "\" is not a JSON object");
  496|      0|    }
  497|       |
  498|      4|    if (mRecursiveReferenceCheck.find(i) != mRecursiveReferenceCheck.end()) {
  ------------------
  |  Branch (498:9): [True: 0, False: 4]
  ------------------
  499|      0|        throw DeadlyImportError("GLTF: Object at index ", i, " in array \"", mDictId, "\" has recursive reference to itself");
  500|      0|    }
  501|      4|    mRecursiveReferenceCheck.insert(i);
  502|       |
  503|       |    // Unique ptr prevents memory leak in case of Read throws an exception
  504|      4|    auto inst = std::unique_ptr<T>(new T());
  505|       |    // Try to make this human readable so it can be used in error messages.
  506|      4|    inst->id = std::string(mDictId) + "[" + ai_to_string(i) + "]";
  507|      4|    inst->oIndex = i;
  508|      4|    ReadMember(obj, "name", inst->name);
  509|      4|    inst->Read(obj, mAsset);
  510|      4|    inst->ReadExtensions(obj);
  511|      4|    inst->ReadExtras(obj);
  512|       |
  513|      4|    Ref<T> result = Add(inst.release());
  514|      4|    mRecursiveReferenceCheck.erase(i);
  515|      4|    return result;
  516|      4|}
_ZN5glTF28LazyDictINS_10BufferViewEE8RetrieveEj:
  473|     20|Ref<T> LazyDict<T>::Retrieve(unsigned int i) {
  474|     20|    typename Dict::iterator it = mObjsByOIndex.find(i);
  475|     20|    if (it != mObjsByOIndex.end()) { // already created?
  ------------------
  |  Branch (475:9): [True: 0, False: 20]
  ------------------
  476|      0|        return Ref<T>(mObjs, it->second);
  477|      0|    }
  478|       |
  479|       |    // read it from the JSON object
  480|     20|    if (!mDict) {
  ------------------
  |  Branch (480:9): [True: 0, False: 20]
  ------------------
  481|      0|        throw DeadlyImportError("GLTF: Missing section \"", mDictId, "\"");
  482|      0|    }
  483|       |
  484|     20|    if (!mDict->IsArray()) {
  ------------------
  |  Branch (484:9): [True: 0, False: 20]
  ------------------
  485|      0|        throw DeadlyImportError("GLTF: Field \"", mDictId, "\"  is not an array");
  486|      0|    }
  487|       |
  488|     20|    if (i >= mDict->Size()) {
  ------------------
  |  Branch (488:9): [True: 0, False: 20]
  ------------------
  489|      0|        throw DeadlyImportError("GLTF: Array index ", i, " is out of bounds (", mDict->Size(), ") for \"", mDictId, "\"");
  490|      0|    }
  491|       |
  492|     20|    Value &obj = (*mDict)[i];
  493|       |
  494|     20|    if (!obj.IsObject()) {
  ------------------
  |  Branch (494:9): [True: 0, False: 20]
  ------------------
  495|      0|        throw DeadlyImportError("GLTF: Object at index ", i, " in array \"", mDictId, "\" is not a JSON object");
  496|      0|    }
  497|       |
  498|     20|    if (mRecursiveReferenceCheck.find(i) != mRecursiveReferenceCheck.end()) {
  ------------------
  |  Branch (498:9): [True: 0, False: 20]
  ------------------
  499|      0|        throw DeadlyImportError("GLTF: Object at index ", i, " in array \"", mDictId, "\" has recursive reference to itself");
  500|      0|    }
  501|     20|    mRecursiveReferenceCheck.insert(i);
  502|       |
  503|       |    // Unique ptr prevents memory leak in case of Read throws an exception
  504|     20|    auto inst = std::unique_ptr<T>(new T());
  505|       |    // Try to make this human readable so it can be used in error messages.
  506|     20|    inst->id = std::string(mDictId) + "[" + ai_to_string(i) + "]";
  507|     20|    inst->oIndex = i;
  508|     20|    ReadMember(obj, "name", inst->name);
  509|     20|    inst->Read(obj, mAsset);
  510|     20|    inst->ReadExtensions(obj);
  511|     20|    inst->ReadExtras(obj);
  512|       |
  513|     20|    Ref<T> result = Add(inst.release());
  514|     20|    mRecursiveReferenceCheck.erase(i);
  515|     20|    return result;
  516|     20|}
_ZN5glTF28LazyDictINS_5ImageEE8RetrieveEj:
  473|      2|Ref<T> LazyDict<T>::Retrieve(unsigned int i) {
  474|      2|    typename Dict::iterator it = mObjsByOIndex.find(i);
  475|      2|    if (it != mObjsByOIndex.end()) { // already created?
  ------------------
  |  Branch (475:9): [True: 0, False: 2]
  ------------------
  476|      0|        return Ref<T>(mObjs, it->second);
  477|      0|    }
  478|       |
  479|       |    // read it from the JSON object
  480|      2|    if (!mDict) {
  ------------------
  |  Branch (480:9): [True: 0, False: 2]
  ------------------
  481|      0|        throw DeadlyImportError("GLTF: Missing section \"", mDictId, "\"");
  482|      0|    }
  483|       |
  484|      2|    if (!mDict->IsArray()) {
  ------------------
  |  Branch (484:9): [True: 0, False: 2]
  ------------------
  485|      0|        throw DeadlyImportError("GLTF: Field \"", mDictId, "\"  is not an array");
  486|      0|    }
  487|       |
  488|      2|    if (i >= mDict->Size()) {
  ------------------
  |  Branch (488:9): [True: 0, False: 2]
  ------------------
  489|      0|        throw DeadlyImportError("GLTF: Array index ", i, " is out of bounds (", mDict->Size(), ") for \"", mDictId, "\"");
  490|      0|    }
  491|       |
  492|      2|    Value &obj = (*mDict)[i];
  493|       |
  494|      2|    if (!obj.IsObject()) {
  ------------------
  |  Branch (494:9): [True: 0, False: 2]
  ------------------
  495|      0|        throw DeadlyImportError("GLTF: Object at index ", i, " in array \"", mDictId, "\" is not a JSON object");
  496|      0|    }
  497|       |
  498|      2|    if (mRecursiveReferenceCheck.find(i) != mRecursiveReferenceCheck.end()) {
  ------------------
  |  Branch (498:9): [True: 0, False: 2]
  ------------------
  499|      0|        throw DeadlyImportError("GLTF: Object at index ", i, " in array \"", mDictId, "\" has recursive reference to itself");
  500|      0|    }
  501|      2|    mRecursiveReferenceCheck.insert(i);
  502|       |
  503|       |    // Unique ptr prevents memory leak in case of Read throws an exception
  504|      2|    auto inst = std::unique_ptr<T>(new T());
  505|       |    // Try to make this human readable so it can be used in error messages.
  506|      2|    inst->id = std::string(mDictId) + "[" + ai_to_string(i) + "]";
  507|      2|    inst->oIndex = i;
  508|      2|    ReadMember(obj, "name", inst->name);
  509|      2|    inst->Read(obj, mAsset);
  510|      2|    inst->ReadExtensions(obj);
  511|      2|    inst->ReadExtras(obj);
  512|       |
  513|      2|    Ref<T> result = Add(inst.release());
  514|      2|    mRecursiveReferenceCheck.erase(i);
  515|      2|    return result;
  516|      2|}
_ZN5glTF28LazyDictINS_7SamplerEE8RetrieveEj:
  473|      1|Ref<T> LazyDict<T>::Retrieve(unsigned int i) {
  474|      1|    typename Dict::iterator it = mObjsByOIndex.find(i);
  475|      1|    if (it != mObjsByOIndex.end()) { // already created?
  ------------------
  |  Branch (475:9): [True: 0, False: 1]
  ------------------
  476|      0|        return Ref<T>(mObjs, it->second);
  477|      0|    }
  478|       |
  479|       |    // read it from the JSON object
  480|      1|    if (!mDict) {
  ------------------
  |  Branch (480:9): [True: 0, False: 1]
  ------------------
  481|      0|        throw DeadlyImportError("GLTF: Missing section \"", mDictId, "\"");
  482|      0|    }
  483|       |
  484|      1|    if (!mDict->IsArray()) {
  ------------------
  |  Branch (484:9): [True: 0, False: 1]
  ------------------
  485|      0|        throw DeadlyImportError("GLTF: Field \"", mDictId, "\"  is not an array");
  486|      0|    }
  487|       |
  488|      1|    if (i >= mDict->Size()) {
  ------------------
  |  Branch (488:9): [True: 0, False: 1]
  ------------------
  489|      0|        throw DeadlyImportError("GLTF: Array index ", i, " is out of bounds (", mDict->Size(), ") for \"", mDictId, "\"");
  490|      0|    }
  491|       |
  492|      1|    Value &obj = (*mDict)[i];
  493|       |
  494|      1|    if (!obj.IsObject()) {
  ------------------
  |  Branch (494:9): [True: 0, False: 1]
  ------------------
  495|      0|        throw DeadlyImportError("GLTF: Object at index ", i, " in array \"", mDictId, "\" is not a JSON object");
  496|      0|    }
  497|       |
  498|      1|    if (mRecursiveReferenceCheck.find(i) != mRecursiveReferenceCheck.end()) {
  ------------------
  |  Branch (498:9): [True: 0, False: 1]
  ------------------
  499|      0|        throw DeadlyImportError("GLTF: Object at index ", i, " in array \"", mDictId, "\" has recursive reference to itself");
  500|      0|    }
  501|      1|    mRecursiveReferenceCheck.insert(i);
  502|       |
  503|       |    // Unique ptr prevents memory leak in case of Read throws an exception
  504|      1|    auto inst = std::unique_ptr<T>(new T());
  505|       |    // Try to make this human readable so it can be used in error messages.
  506|      1|    inst->id = std::string(mDictId) + "[" + ai_to_string(i) + "]";
  507|      1|    inst->oIndex = i;
  508|      1|    ReadMember(obj, "name", inst->name);
  509|      1|    inst->Read(obj, mAsset);
  510|      1|    inst->ReadExtensions(obj);
  511|      1|    inst->ReadExtras(obj);
  512|       |
  513|      1|    Ref<T> result = Add(inst.release());
  514|      1|    mRecursiveReferenceCheck.erase(i);
  515|      1|    return result;
  516|      1|}
_ZN5glTF28LazyDictINS_7TextureEE8RetrieveEj:
  473|      4|Ref<T> LazyDict<T>::Retrieve(unsigned int i) {
  474|      4|    typename Dict::iterator it = mObjsByOIndex.find(i);
  475|      4|    if (it != mObjsByOIndex.end()) { // already created?
  ------------------
  |  Branch (475:9): [True: 2, False: 2]
  ------------------
  476|      2|        return Ref<T>(mObjs, it->second);
  477|      2|    }
  478|       |
  479|       |    // read it from the JSON object
  480|      2|    if (!mDict) {
  ------------------
  |  Branch (480:9): [True: 0, False: 2]
  ------------------
  481|      0|        throw DeadlyImportError("GLTF: Missing section \"", mDictId, "\"");
  482|      0|    }
  483|       |
  484|      2|    if (!mDict->IsArray()) {
  ------------------
  |  Branch (484:9): [True: 0, False: 2]
  ------------------
  485|      0|        throw DeadlyImportError("GLTF: Field \"", mDictId, "\"  is not an array");
  486|      0|    }
  487|       |
  488|      2|    if (i >= mDict->Size()) {
  ------------------
  |  Branch (488:9): [True: 0, False: 2]
  ------------------
  489|      0|        throw DeadlyImportError("GLTF: Array index ", i, " is out of bounds (", mDict->Size(), ") for \"", mDictId, "\"");
  490|      0|    }
  491|       |
  492|      2|    Value &obj = (*mDict)[i];
  493|       |
  494|      2|    if (!obj.IsObject()) {
  ------------------
  |  Branch (494:9): [True: 0, False: 2]
  ------------------
  495|      0|        throw DeadlyImportError("GLTF: Object at index ", i, " in array \"", mDictId, "\" is not a JSON object");
  496|      0|    }
  497|       |
  498|      2|    if (mRecursiveReferenceCheck.find(i) != mRecursiveReferenceCheck.end()) {
  ------------------
  |  Branch (498:9): [True: 0, False: 2]
  ------------------
  499|      0|        throw DeadlyImportError("GLTF: Object at index ", i, " in array \"", mDictId, "\" has recursive reference to itself");
  500|      0|    }
  501|      2|    mRecursiveReferenceCheck.insert(i);
  502|       |
  503|       |    // Unique ptr prevents memory leak in case of Read throws an exception
  504|      2|    auto inst = std::unique_ptr<T>(new T());
  505|       |    // Try to make this human readable so it can be used in error messages.
  506|      2|    inst->id = std::string(mDictId) + "[" + ai_to_string(i) + "]";
  507|      2|    inst->oIndex = i;
  508|      2|    ReadMember(obj, "name", inst->name);
  509|      2|    inst->Read(obj, mAsset);
  510|      2|    inst->ReadExtensions(obj);
  511|      2|    inst->ReadExtras(obj);
  512|       |
  513|      2|    Ref<T> result = Add(inst.release());
  514|      2|    mRecursiveReferenceCheck.erase(i);
  515|      2|    return result;
  516|      2|}
_ZN5glTF28LazyDictINS_8AccessorEE8RetrieveEj:
  473|     20|Ref<T> LazyDict<T>::Retrieve(unsigned int i) {
  474|     20|    typename Dict::iterator it = mObjsByOIndex.find(i);
  475|     20|    if (it != mObjsByOIndex.end()) { // already created?
  ------------------
  |  Branch (475:9): [True: 0, False: 20]
  ------------------
  476|      0|        return Ref<T>(mObjs, it->second);
  477|      0|    }
  478|       |
  479|       |    // read it from the JSON object
  480|     20|    if (!mDict) {
  ------------------
  |  Branch (480:9): [True: 0, False: 20]
  ------------------
  481|      0|        throw DeadlyImportError("GLTF: Missing section \"", mDictId, "\"");
  482|      0|    }
  483|       |
  484|     20|    if (!mDict->IsArray()) {
  ------------------
  |  Branch (484:9): [True: 0, False: 20]
  ------------------
  485|      0|        throw DeadlyImportError("GLTF: Field \"", mDictId, "\"  is not an array");
  486|      0|    }
  487|       |
  488|     20|    if (i >= mDict->Size()) {
  ------------------
  |  Branch (488:9): [True: 0, False: 20]
  ------------------
  489|      0|        throw DeadlyImportError("GLTF: Array index ", i, " is out of bounds (", mDict->Size(), ") for \"", mDictId, "\"");
  490|      0|    }
  491|       |
  492|     20|    Value &obj = (*mDict)[i];
  493|       |
  494|     20|    if (!obj.IsObject()) {
  ------------------
  |  Branch (494:9): [True: 0, False: 20]
  ------------------
  495|      0|        throw DeadlyImportError("GLTF: Object at index ", i, " in array \"", mDictId, "\" is not a JSON object");
  496|      0|    }
  497|       |
  498|     20|    if (mRecursiveReferenceCheck.find(i) != mRecursiveReferenceCheck.end()) {
  ------------------
  |  Branch (498:9): [True: 0, False: 20]
  ------------------
  499|      0|        throw DeadlyImportError("GLTF: Object at index ", i, " in array \"", mDictId, "\" has recursive reference to itself");
  500|      0|    }
  501|     20|    mRecursiveReferenceCheck.insert(i);
  502|       |
  503|       |    // Unique ptr prevents memory leak in case of Read throws an exception
  504|     20|    auto inst = std::unique_ptr<T>(new T());
  505|       |    // Try to make this human readable so it can be used in error messages.
  506|     20|    inst->id = std::string(mDictId) + "[" + ai_to_string(i) + "]";
  507|     20|    inst->oIndex = i;
  508|     20|    ReadMember(obj, "name", inst->name);
  509|     20|    inst->Read(obj, mAsset);
  510|     20|    inst->ReadExtensions(obj);
  511|     20|    inst->ReadExtras(obj);
  512|       |
  513|     20|    Ref<T> result = Add(inst.release());
  514|     20|    mRecursiveReferenceCheck.erase(i);
  515|     20|    return result;
  516|     20|}
_ZN5glTF28LazyDictINS_8MaterialEE8RetrieveEj:
  473|      6|Ref<T> LazyDict<T>::Retrieve(unsigned int i) {
  474|      6|    typename Dict::iterator it = mObjsByOIndex.find(i);
  475|      6|    if (it != mObjsByOIndex.end()) { // already created?
  ------------------
  |  Branch (475:9): [True: 0, False: 6]
  ------------------
  476|      0|        return Ref<T>(mObjs, it->second);
  477|      0|    }
  478|       |
  479|       |    // read it from the JSON object
  480|      6|    if (!mDict) {
  ------------------
  |  Branch (480:9): [True: 0, False: 6]
  ------------------
  481|      0|        throw DeadlyImportError("GLTF: Missing section \"", mDictId, "\"");
  482|      0|    }
  483|       |
  484|      6|    if (!mDict->IsArray()) {
  ------------------
  |  Branch (484:9): [True: 0, False: 6]
  ------------------
  485|      0|        throw DeadlyImportError("GLTF: Field \"", mDictId, "\"  is not an array");
  486|      0|    }
  487|       |
  488|      6|    if (i >= mDict->Size()) {
  ------------------
  |  Branch (488:9): [True: 0, False: 6]
  ------------------
  489|      0|        throw DeadlyImportError("GLTF: Array index ", i, " is out of bounds (", mDict->Size(), ") for \"", mDictId, "\"");
  490|      0|    }
  491|       |
  492|      6|    Value &obj = (*mDict)[i];
  493|       |
  494|      6|    if (!obj.IsObject()) {
  ------------------
  |  Branch (494:9): [True: 0, False: 6]
  ------------------
  495|      0|        throw DeadlyImportError("GLTF: Object at index ", i, " in array \"", mDictId, "\" is not a JSON object");
  496|      0|    }
  497|       |
  498|      6|    if (mRecursiveReferenceCheck.find(i) != mRecursiveReferenceCheck.end()) {
  ------------------
  |  Branch (498:9): [True: 0, False: 6]
  ------------------
  499|      0|        throw DeadlyImportError("GLTF: Object at index ", i, " in array \"", mDictId, "\" has recursive reference to itself");
  500|      0|    }
  501|      6|    mRecursiveReferenceCheck.insert(i);
  502|       |
  503|       |    // Unique ptr prevents memory leak in case of Read throws an exception
  504|      6|    auto inst = std::unique_ptr<T>(new T());
  505|       |    // Try to make this human readable so it can be used in error messages.
  506|      6|    inst->id = std::string(mDictId) + "[" + ai_to_string(i) + "]";
  507|      6|    inst->oIndex = i;
  508|      6|    ReadMember(obj, "name", inst->name);
  509|      6|    inst->Read(obj, mAsset);
  510|      6|    inst->ReadExtensions(obj);
  511|      6|    inst->ReadExtras(obj);
  512|       |
  513|      6|    Ref<T> result = Add(inst.release());
  514|      6|    mRecursiveReferenceCheck.erase(i);
  515|      6|    return result;
  516|      6|}
_ZN5glTF28LazyDictINS_4NodeEE8RetrieveEj:
  473|      9|Ref<T> LazyDict<T>::Retrieve(unsigned int i) {
  474|      9|    typename Dict::iterator it = mObjsByOIndex.find(i);
  475|      9|    if (it != mObjsByOIndex.end()) { // already created?
  ------------------
  |  Branch (475:9): [True: 0, False: 9]
  ------------------
  476|      0|        return Ref<T>(mObjs, it->second);
  477|      0|    }
  478|       |
  479|       |    // read it from the JSON object
  480|      9|    if (!mDict) {
  ------------------
  |  Branch (480:9): [True: 0, False: 9]
  ------------------
  481|      0|        throw DeadlyImportError("GLTF: Missing section \"", mDictId, "\"");
  482|      0|    }
  483|       |
  484|      9|    if (!mDict->IsArray()) {
  ------------------
  |  Branch (484:9): [True: 0, False: 9]
  ------------------
  485|      0|        throw DeadlyImportError("GLTF: Field \"", mDictId, "\"  is not an array");
  486|      0|    }
  487|       |
  488|      9|    if (i >= mDict->Size()) {
  ------------------
  |  Branch (488:9): [True: 0, False: 9]
  ------------------
  489|      0|        throw DeadlyImportError("GLTF: Array index ", i, " is out of bounds (", mDict->Size(), ") for \"", mDictId, "\"");
  490|      0|    }
  491|       |
  492|      9|    Value &obj = (*mDict)[i];
  493|       |
  494|      9|    if (!obj.IsObject()) {
  ------------------
  |  Branch (494:9): [True: 0, False: 9]
  ------------------
  495|      0|        throw DeadlyImportError("GLTF: Object at index ", i, " in array \"", mDictId, "\" is not a JSON object");
  496|      0|    }
  497|       |
  498|      9|    if (mRecursiveReferenceCheck.find(i) != mRecursiveReferenceCheck.end()) {
  ------------------
  |  Branch (498:9): [True: 0, False: 9]
  ------------------
  499|      0|        throw DeadlyImportError("GLTF: Object at index ", i, " in array \"", mDictId, "\" has recursive reference to itself");
  500|      0|    }
  501|      9|    mRecursiveReferenceCheck.insert(i);
  502|       |
  503|       |    // Unique ptr prevents memory leak in case of Read throws an exception
  504|      9|    auto inst = std::unique_ptr<T>(new T());
  505|       |    // Try to make this human readable so it can be used in error messages.
  506|      9|    inst->id = std::string(mDictId) + "[" + ai_to_string(i) + "]";
  507|      9|    inst->oIndex = i;
  508|      9|    ReadMember(obj, "name", inst->name);
  509|      9|    inst->Read(obj, mAsset);
  510|      9|    inst->ReadExtensions(obj);
  511|      9|    inst->ReadExtras(obj);
  512|       |
  513|      9|    Ref<T> result = Add(inst.release());
  514|      9|    mRecursiveReferenceCheck.erase(i);
  515|      9|    return result;
  516|      9|}
_ZN5glTF28LazyDictINS_4MeshEE8RetrieveEj:
  473|      8|Ref<T> LazyDict<T>::Retrieve(unsigned int i) {
  474|      8|    typename Dict::iterator it = mObjsByOIndex.find(i);
  475|      8|    if (it != mObjsByOIndex.end()) { // already created?
  ------------------
  |  Branch (475:9): [True: 0, False: 8]
  ------------------
  476|      0|        return Ref<T>(mObjs, it->second);
  477|      0|    }
  478|       |
  479|       |    // read it from the JSON object
  480|      8|    if (!mDict) {
  ------------------
  |  Branch (480:9): [True: 0, False: 8]
  ------------------
  481|      0|        throw DeadlyImportError("GLTF: Missing section \"", mDictId, "\"");
  482|      0|    }
  483|       |
  484|      8|    if (!mDict->IsArray()) {
  ------------------
  |  Branch (484:9): [True: 0, False: 8]
  ------------------
  485|      0|        throw DeadlyImportError("GLTF: Field \"", mDictId, "\"  is not an array");
  486|      0|    }
  487|       |
  488|      8|    if (i >= mDict->Size()) {
  ------------------
  |  Branch (488:9): [True: 0, False: 8]
  ------------------
  489|      0|        throw DeadlyImportError("GLTF: Array index ", i, " is out of bounds (", mDict->Size(), ") for \"", mDictId, "\"");
  490|      0|    }
  491|       |
  492|      8|    Value &obj = (*mDict)[i];
  493|       |
  494|      8|    if (!obj.IsObject()) {
  ------------------
  |  Branch (494:9): [True: 0, False: 8]
  ------------------
  495|      0|        throw DeadlyImportError("GLTF: Object at index ", i, " in array \"", mDictId, "\" is not a JSON object");
  496|      0|    }
  497|       |
  498|      8|    if (mRecursiveReferenceCheck.find(i) != mRecursiveReferenceCheck.end()) {
  ------------------
  |  Branch (498:9): [True: 0, False: 8]
  ------------------
  499|      0|        throw DeadlyImportError("GLTF: Object at index ", i, " in array \"", mDictId, "\" has recursive reference to itself");
  500|      0|    }
  501|      8|    mRecursiveReferenceCheck.insert(i);
  502|       |
  503|       |    // Unique ptr prevents memory leak in case of Read throws an exception
  504|      8|    auto inst = std::unique_ptr<T>(new T());
  505|       |    // Try to make this human readable so it can be used in error messages.
  506|      8|    inst->id = std::string(mDictId) + "[" + ai_to_string(i) + "]";
  507|      8|    inst->oIndex = i;
  508|      8|    ReadMember(obj, "name", inst->name);
  509|      8|    inst->Read(obj, mAsset);
  510|      8|    inst->ReadExtensions(obj);
  511|      8|    inst->ReadExtras(obj);
  512|       |
  513|      8|    Ref<T> result = Add(inst.release());
  514|      8|    mRecursiveReferenceCheck.erase(i);
  515|      8|    return result;
  516|      8|}
_ZN5glTF28LazyDictINS_5SceneEE8RetrieveEj:
  473|      4|Ref<T> LazyDict<T>::Retrieve(unsigned int i) {
  474|      4|    typename Dict::iterator it = mObjsByOIndex.find(i);
  475|      4|    if (it != mObjsByOIndex.end()) { // already created?
  ------------------
  |  Branch (475:9): [True: 0, False: 4]
  ------------------
  476|      0|        return Ref<T>(mObjs, it->second);
  477|      0|    }
  478|       |
  479|       |    // read it from the JSON object
  480|      4|    if (!mDict) {
  ------------------
  |  Branch (480:9): [True: 0, False: 4]
  ------------------
  481|      0|        throw DeadlyImportError("GLTF: Missing section \"", mDictId, "\"");
  482|      0|    }
  483|       |
  484|      4|    if (!mDict->IsArray()) {
  ------------------
  |  Branch (484:9): [True: 0, False: 4]
  ------------------
  485|      0|        throw DeadlyImportError("GLTF: Field \"", mDictId, "\"  is not an array");
  486|      0|    }
  487|       |
  488|      4|    if (i >= mDict->Size()) {
  ------------------
  |  Branch (488:9): [True: 0, False: 4]
  ------------------
  489|      0|        throw DeadlyImportError("GLTF: Array index ", i, " is out of bounds (", mDict->Size(), ") for \"", mDictId, "\"");
  490|      0|    }
  491|       |
  492|      4|    Value &obj = (*mDict)[i];
  493|       |
  494|      4|    if (!obj.IsObject()) {
  ------------------
  |  Branch (494:9): [True: 0, False: 4]
  ------------------
  495|      0|        throw DeadlyImportError("GLTF: Object at index ", i, " in array \"", mDictId, "\" is not a JSON object");
  496|      0|    }
  497|       |
  498|      4|    if (mRecursiveReferenceCheck.find(i) != mRecursiveReferenceCheck.end()) {
  ------------------
  |  Branch (498:9): [True: 0, False: 4]
  ------------------
  499|      0|        throw DeadlyImportError("GLTF: Object at index ", i, " in array \"", mDictId, "\" has recursive reference to itself");
  500|      0|    }
  501|      4|    mRecursiveReferenceCheck.insert(i);
  502|       |
  503|       |    // Unique ptr prevents memory leak in case of Read throws an exception
  504|      4|    auto inst = std::unique_ptr<T>(new T());
  505|       |    // Try to make this human readable so it can be used in error messages.
  506|      4|    inst->id = std::string(mDictId) + "[" + ai_to_string(i) + "]";
  507|      4|    inst->oIndex = i;
  508|      4|    ReadMember(obj, "name", inst->name);
  509|      4|    inst->Read(obj, mAsset);
  510|      4|    inst->ReadExtensions(obj);
  511|      4|    inst->ReadExtras(obj);
  512|       |
  513|      4|    Ref<T> result = Add(inst.release());
  514|      4|    mRecursiveReferenceCheck.erase(i);
  515|      4|    return result;
  516|      4|}
glTF2Importer.cpp:_ZN5glTF212_GLOBAL__N_19SetVectorERA4_fRA4_Kf:
  176|      6|void SetVector(vec4 &v, const float (&in)[4]) {
  177|      6|    v[0] = in[0];
  178|      6|    v[1] = in[1];
  179|      6|    v[2] = in[2];
  180|      6|    v[3] = in[3];
  181|      6|}
glTF2Importer.cpp:_ZN5glTF212_GLOBAL__N_19SetVectorERA3_fRA3_Kf:
  183|      6|void SetVector(vec3 &v, const float (&in)[3]) {
  184|      6|    v[0] = in[0];
  185|      6|    v[1] = in[1];
  186|      6|    v[2] = in[2];
  187|      6|}
glTF2Importer.cpp:_ZN5glTF212_GLOBAL__N_115GetAttribVectorERNS_4Mesh9PrimitiveEPKcRPNSt3__16vectorIN10glTFCommon3RefINS_8AccessorEEENS6_9allocatorISB_EEEERi:
  199|     13|inline bool GetAttribVector(Mesh::Primitive &p, const char *attr, Mesh::AccessorList *&v, int &pos) {
  200|     13|    if ((pos = Compare(attr, "POSITION"))) {
  ------------------
  |  Branch (200:9): [True: 5, False: 8]
  ------------------
  201|      5|        v = &(p.attributes.position);
  202|      8|    } else if ((pos = Compare(attr, "NORMAL"))) {
  ------------------
  |  Branch (202:16): [True: 5, False: 3]
  ------------------
  203|      5|        v = &(p.attributes.normal);
  204|      5|    } else if ((pos = Compare(attr, "TANGENT"))) {
  ------------------
  |  Branch (204:16): [True: 0, False: 3]
  ------------------
  205|      0|        v = &(p.attributes.tangent);
  206|      3|    } else if ((pos = Compare(attr, "TEXCOORD"))) {
  ------------------
  |  Branch (206:16): [True: 3, False: 0]
  ------------------
  207|      3|        v = &(p.attributes.texcoord);
  208|      3|    } else if ((pos = Compare(attr, "COLOR"))) {
  ------------------
  |  Branch (208:16): [True: 0, False: 0]
  ------------------
  209|      0|        v = &(p.attributes.color);
  210|      0|    } else if ((pos = Compare(attr, "JOINTS"))) {
  ------------------
  |  Branch (210:16): [True: 0, False: 0]
  ------------------
  211|      0|        v = &(p.attributes.joint);
  212|      0|    } else if ((pos = Compare(attr, "JOINTMATRIX"))) {
  ------------------
  |  Branch (212:16): [True: 0, False: 0]
  ------------------
  213|      0|        v = &(p.attributes.jointmatrix);
  214|      0|    } else if ((pos = Compare(attr, "WEIGHTS"))) {
  ------------------
  |  Branch (214:16): [True: 0, False: 0]
  ------------------
  215|      0|        v = &(p.attributes.weight);
  216|      0|    } else
  217|      0|        return false;
  218|     13|    return true;
  219|     13|}
glTF2Importer.cpp:_ZN5glTF212_GLOBAL__N_17CompareILi9EEEiPKcRAT__S2_:
  190|     16|inline int Compare(const char *attr, const char (&str)[N]) {
  191|     16|    return (strncmp(attr, str, N - 1) == 0) ? N - 1 : 0;
  ------------------
  |  Branch (191:12): [True: 8, False: 8]
  ------------------
  192|     16|}
glTF2Importer.cpp:_ZN5glTF212_GLOBAL__N_17CompareILi7EEEiPKcRAT__S2_:
  190|      8|inline int Compare(const char *attr, const char (&str)[N]) {
  191|      8|    return (strncmp(attr, str, N - 1) == 0) ? N - 1 : 0;
  ------------------
  |  Branch (191:12): [True: 5, False: 3]
  ------------------
  192|      8|}
glTF2Importer.cpp:_ZN5glTF212_GLOBAL__N_17CompareILi8EEEiPKcRAT__S2_:
  190|      3|inline int Compare(const char *attr, const char (&str)[N]) {
  191|      3|    return (strncmp(attr, str, N - 1) == 0) ? N - 1 : 0;
  ------------------
  |  Branch (191:12): [True: 0, False: 3]
  ------------------
  192|      3|}

_ZN6Assimp13glTF2ImporterC2Ev:
  101|    624|        mScene(nullptr) {
  102|       |    // empty
  103|    624|}
_ZNK6Assimp13glTF2Importer7GetInfoEv:
  105|    639|const aiImporterDesc *glTF2Importer::GetInfo() const {
  106|    639|    return &desc;
  107|    639|}
_ZNK6Assimp13glTF2Importer7CanReadERKNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEPNS_8IOSystemEb:
  109|     48|bool glTF2Importer::CanRead(const std::string &filename, IOSystem *pIOHandler, bool checkSig) const {
  110|     48|    const std::string extension = GetExtension(filename);
  111|     48|    if (!checkSig && (extension != "gltf") && (extension != "glb") && (extension != "vrm")) {
  ------------------
  |  Branch (111:9): [True: 0, False: 48]
  |  Branch (111:22): [True: 0, False: 0]
  |  Branch (111:47): [True: 0, False: 0]
  |  Branch (111:71): [True: 0, False: 0]
  ------------------
  112|      0|        return false;
  113|      0|    }
  114|       |
  115|     48|    if (pIOHandler) {
  ------------------
  |  Branch (115:9): [True: 48, False: 0]
  ------------------
  116|     48|        Asset asset(pIOHandler);
  117|     48|        return asset.CanRead(
  118|     48|            filename,
  119|     48|            CheckMagicToken(
  120|     48|                pIOHandler, filename, AI_GLB_MAGIC_NUMBER, 1, 0,
  ------------------
  |  |  147|     48|#define AI_GLB_MAGIC_NUMBER "glTF"
  ------------------
  121|     48|                static_cast<unsigned int>(strlen(AI_GLB_MAGIC_NUMBER))));
  ------------------
  |  |  147|     48|#define AI_GLB_MAGIC_NUMBER "glTF"
  ------------------
  122|     48|    }
  123|       |
  124|      0|    return false;
  125|     48|}
_ZN6Assimp13glTF2Importer14InternReadFileERKNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEP7aiScenePNS_8IOSystemE:
 1771|      5|void glTF2Importer::InternReadFile(const std::string &pFile, aiScene *pScene, IOSystem *pIOHandler) {
 1772|      5|    ASSIMP_LOG_DEBUG("Reading GLTF2 file");
 1773|       |
 1774|       |    // clean all member arrays
 1775|      5|    meshOffsets.clear();
 1776|      5|    mVertexRemappingTables.clear();
 1777|      5|    mEmbeddedTexIdxs.clear();
 1778|       |
 1779|      5|    this->mScene = pScene;
 1780|       |
 1781|       |    // read the asset file
 1782|      5|    glTF2::Asset asset(pIOHandler, static_cast<rapidjson::IRemoteSchemaDocumentProvider *>(mSchemaDocumentProvider));
 1783|      5|    asset.Load(pFile,
 1784|      5|               CheckMagicToken(
 1785|      5|                   pIOHandler, pFile, AI_GLB_MAGIC_NUMBER, 1, 0,
  ------------------
  |  |  147|      5|#define AI_GLB_MAGIC_NUMBER "glTF"
  ------------------
 1786|      5|                   static_cast<unsigned int>(strlen(AI_GLB_MAGIC_NUMBER))));
  ------------------
  |  |  147|      5|#define AI_GLB_MAGIC_NUMBER "glTF"
  ------------------
 1787|      5|    if (asset.scene) {
  ------------------
  |  Branch (1787:9): [True: 0, False: 5]
  ------------------
 1788|      0|        pScene->mName = asset.scene->name;
 1789|      0|    }
 1790|       |
 1791|       |    // Copy the data out
 1792|      5|    ImportEmbeddedTextures(asset);
 1793|      5|    ImportMaterials(asset);
 1794|       |
 1795|      5|    ImportMeshes(asset);
 1796|       |
 1797|      5|    ImportCameras(asset);
 1798|      5|    ImportLights(asset);
 1799|       |
 1800|      5|    ImportNodes(asset);
 1801|       |
 1802|      5|    ImportAnimations(asset);
 1803|       |
 1804|      5|    ImportCommonMetadata(asset);
 1805|       |
 1806|      5|    if (pScene->mNumMeshes == 0) {
  ------------------
  |  Branch (1806:9): [True: 0, False: 5]
  ------------------
 1807|       |        pScene->mFlags |= AI_SCENE_FLAGS_INCOMPLETE;
 1808|      0|    }
 1809|      5|}
_ZN6Assimp13glTF2Importer15SetupPropertiesEPKNS_8ImporterE:
 1811|      5|void glTF2Importer::SetupProperties(const Importer *pImp) {
 1812|       |    mSchemaDocumentProvider = static_cast<rapidjson::IRemoteSchemaDocumentProvider *>(pImp->GetPropertyPointer(AI_CONFIG_IMPORT_SCHEMA_DOCUMENT_PROVIDER));
 1813|      5|}

_ZN6Assimp13glTF2ImporterD2Ev:
   62|    624|    ~glTF2Importer() override = default;

_ZN10glTFCommon4Util12ParseDataURIEPKcmRNS0_7DataURIE:
   47|     11|bool ParseDataURI(const char *const_uri, size_t uriLen, DataURI &out) {
   48|     11|    if (nullptr == const_uri) {
  ------------------
  |  Branch (48:9): [True: 0, False: 11]
  ------------------
   49|      0|        return false;
   50|      0|    }
   51|       |
   52|     11|    if (const_uri[0] != 0x10) { // we already parsed this uri?
  ------------------
  |  Branch (52:9): [True: 11, False: 0]
  ------------------
   53|     11|        if (strncmp(const_uri, "data:", 5) != 0) // not a data uri?
  ------------------
  |  Branch (53:13): [True: 3, False: 8]
  ------------------
   54|      3|            return false;
   55|     11|    }
   56|       |
   57|       |    // set defaults
   58|      8|    out.mediaType = "text/plain";
   59|      8|    out.charset = "US-ASCII";
   60|      8|    out.base64 = false;
   61|       |
   62|      8|    char *uri = const_cast<char *>(const_uri);
   63|      8|    if (uri[0] != 0x10) {
  ------------------
  |  Branch (63:9): [True: 8, False: 0]
  ------------------
   64|      8|        uri[0] = 0x10;
   65|      8|        uri[1] = uri[2] = uri[3] = uri[4] = 0;
   66|       |
   67|      8|        size_t i = 5, j;
   68|      8|        if (uri[i] != ';' && uri[i] != ',') { // has media type?
  ------------------
  |  Branch (68:13): [True: 8, False: 0]
  |  Branch (68:30): [True: 8, False: 0]
  ------------------
   69|      8|            uri[1] = char(i);
   70|    140|            for (;i < uriLen && uri[i] != ';' && uri[i] != ','; ++i) {
  ------------------
  |  Branch (70:19): [True: 140, False: 0]
  |  Branch (70:33): [True: 132, False: 8]
  |  Branch (70:50): [True: 132, False: 0]
  ------------------
   71|       |                // nothing to do!
   72|    132|            }
   73|      8|        }
   74|     16|        while (i < uriLen && uri[i] == ';') {
  ------------------
  |  Branch (74:16): [True: 16, False: 0]
  |  Branch (74:30): [True: 8, False: 8]
  ------------------
   75|      8|            uri[i++] = '\0';
   76|     56|            for (j = i; i < uriLen && uri[i] != ';' && uri[i] != ','; ++i) {
  ------------------
  |  Branch (76:25): [True: 56, False: 0]
  |  Branch (76:39): [True: 56, False: 0]
  |  Branch (76:56): [True: 48, False: 8]
  ------------------
   77|       |                // nothing to do!
   78|     48|            }
   79|       |
   80|      8|            if (strncmp(uri + j, "charset=", 8) == 0) {
  ------------------
  |  Branch (80:17): [True: 0, False: 8]
  ------------------
   81|      0|                uri[2] = char(j + 8);
   82|      8|            } else if (strncmp(uri + j, "base64", 6) == 0) {
  ------------------
  |  Branch (82:24): [True: 8, False: 0]
  ------------------
   83|      8|                uri[3] = char(j);
   84|      8|            }
   85|      8|        }
   86|      8|        if (i < uriLen) {
  ------------------
  |  Branch (86:13): [True: 8, False: 0]
  ------------------
   87|      8|            uri[i++] = '\0';
   88|      8|            uri[4] = char(i);
   89|      8|        } else {
   90|      0|            uri[1] = uri[2] = uri[3] = 0;
   91|      0|            uri[4] = 5;
   92|      0|        }
   93|      8|    }
   94|       |
   95|      8|    if (uri[1] != 0) {
  ------------------
  |  Branch (95:9): [True: 8, False: 0]
  ------------------
   96|      8|        out.mediaType = uri + uri[1];
   97|      8|    }
   98|      8|    if (uri[2] != 0) {
  ------------------
  |  Branch (98:9): [True: 0, False: 8]
  ------------------
   99|      0|        out.charset = uri + uri[2];
  100|      0|    }
  101|      8|    if (uri[3] != 0) {
  ------------------
  |  Branch (101:9): [True: 8, False: 0]
  ------------------
  102|      8|        out.base64 = true;
  103|      8|    }
  104|      8|    out.data = uri + uri[4];
  105|      8|    out.dataLength = (uri + uriLen) - out.data;
  106|       |
  107|      8|    return true;
  108|     11|}

_ZN10glTFCommon3RefIN4glTF6BufferEEC2ERNSt3__16vectorIPS2_NS4_9allocatorIS6_EEEEj:
  264|      5|            vector(&vec),
  265|      5|            index(idx) {}
_ZNK10glTFCommon3RefIN4glTF5SceneEEcvbEv:
  269|      1|    operator bool() const { return vector != nullptr && index < vector->size(); }
  ------------------
  |  Branch (269:36): [True: 1, False: 0]
  |  Branch (269:57): [True: 1, False: 0]
  ------------------
_ZN10glTFCommon3RefIN4glTF6BufferEEC2Ev:
  261|     55|            vector(nullptr),
  262|     55|            index(0) {}
_ZN10glTFCommon3RefIN4glTF10BufferViewEEC2ERNSt3__16vectorIPS2_NS4_9allocatorIS6_EEEEj:
  264|      8|            vector(&vec),
  265|      8|            index(idx) {}
_ZN10glTFCommon3RefIN4glTF10BufferViewEEptEv:
  271|     55|    T *operator->() { return (*vector)[index]; }
_ZN10glTFCommon3RefIN4glTF8AccessorEEC2Ev:
  261|     10|            vector(nullptr),
  262|     10|            index(0) {}
_ZN10glTFCommon3RefIN4glTF10BufferViewEEC2Ev:
  261|     11|            vector(nullptr),
  262|     11|            index(0) {}
_ZN10glTFCommon3RefIN4glTF8AccessorEEC2ERNSt3__16vectorIPS2_NS4_9allocatorIS6_EEEEj:
  264|      8|            vector(&vec),
  265|      8|            index(idx) {}
_ZN10glTFCommon3RefIN4glTF8AccessorEEptEv:
  271|      7|    T *operator->() { return (*vector)[index]; }
_ZNK10glTFCommon3RefIN4glTF6BufferEEcvbEv:
  269|      4|    operator bool() const { return vector != nullptr && index < vector->size(); }
  ------------------
  |  Branch (269:36): [True: 4, False: 0]
  |  Branch (269:57): [True: 4, False: 0]
  ------------------
_ZN10glTFCommon3RefIN4glTF6BufferEEptEv:
  271|     10|    T *operator->() { return (*vector)[index]; }
_ZN10glTFCommon3RefIN4glTF8MaterialEEC2Ev:
  261|      3|            vector(nullptr),
  262|      3|            index(0) {}
_ZN10glTFCommon3RefIN4glTF4NodeEEC2ERNSt3__16vectorIPS2_NS4_9allocatorIS6_EEEEj:
  264|      9|            vector(&vec),
  265|      9|            index(idx) {}
_ZN10glTFCommon8NullableIA16_fEC2Ev:
  246|     20|            isPresent(false) {}
_ZN10glTFCommon8NullableIA3_fEC2Ev:
  246|     40|            isPresent(false) {}
_ZN10glTFCommon8NullableIA4_fEC2Ev:
  246|     20|            isPresent(false) {}
_ZN10glTFCommon3RefIN4glTF6CameraEEC2Ev:
  261|     11|            vector(nullptr),
  262|     11|            index(0) {}
_ZN10glTFCommon3RefIN4glTF5LightEEC2Ev:
  261|     11|            vector(nullptr),
  262|     11|            index(0) {}
glTFExporter.cpp:_ZN10glTFCommonL10ReadMemberINSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEEEbRN9rapidjson12GenericValueINS8_4UTF8IcEENS8_19MemoryPoolAllocatorINS8_12CrtAllocatorEEEEEPKcRT_:
  369|     39|inline static bool ReadMember(Value &obj, const char *id, T &out) {
  370|     39|    if (!obj.IsObject()) {
  ------------------
  |  Branch (370:9): [True: 0, False: 39]
  ------------------
  371|      0|        return false;
  372|      0|    }
  373|     39|    Value::MemberIterator it = obj.FindMember(id);
  374|     39|    if (it != obj.MemberEnd()) {
  ------------------
  |  Branch (374:9): [True: 18, False: 21]
  ------------------
  375|     18|        return ReadHelper<T>::Read(it->value, out);
  376|     18|    }
  377|     21|    return false;
  378|     39|}
_ZN10glTFCommon10ReadHelperINSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEE4ReadERN9rapidjson12GenericValueINS9_4UTF8IcEENS9_19MemoryPoolAllocatorINS9_12CrtAllocatorEEEEERS7_:
  322|     81|    static bool Read(Value &val, std::string &out) {
  323|     81|        return val.IsString() ? (out = std::string(val.GetString(), val.GetStringLength()), true) : false;
  ------------------
  |  Branch (323:16): [True: 81, False: 0]
  ------------------
  324|     81|    }
_ZN10glTFCommon9FindArrayERN9rapidjson12GenericValueINS0_4UTF8IcEENS0_19MemoryPoolAllocatorINS0_12CrtAllocatorEEEEEPKc:
  521|     37|inline Value *FindArray(Value &val, const char *id) {
  522|     37|    Value::MemberIterator it = val.FindMember(id);
  523|     37|    return (it != val.MemberEnd() && it->value.IsArray()) ? &it->value : nullptr;
  ------------------
  |  Branch (523:13): [True: 29, False: 8]
  |  Branch (523:38): [True: 29, False: 0]
  ------------------
  524|     37|}
_ZNK10glTFCommon3RefIN4glTF4NodeEEcvbEv:
  269|      9|    operator bool() const { return vector != nullptr && index < vector->size(); }
  ------------------
  |  Branch (269:36): [True: 9, False: 0]
  |  Branch (269:57): [True: 9, False: 0]
  ------------------
glTFExporter.cpp:_ZN10glTFCommonL9ReadValueINS_8NullableIA16_fEEEEbRN9rapidjson12GenericValueINS4_4UTF8IcEENS4_19MemoryPoolAllocatorINS4_12CrtAllocatorEEEEERT_:
  364|      9|inline static bool ReadValue(Value &val, T &out) {
  365|      9|    return ReadHelper<T>::Read(val, out);
  366|      9|}
_ZN10glTFCommon10ReadHelperINS_8NullableIA16_fEEE4ReadERN9rapidjson12GenericValueINS5_4UTF8IcEENS5_19MemoryPoolAllocatorINS5_12CrtAllocatorEEEEERS3_:
  329|      9|    static bool Read(Value &val, Nullable<T> &out) {
  330|      9|        return out.isPresent = ReadHelper<T>::Read(val, out.value);
  331|      9|    }
_ZN10glTFCommon10ReadHelperIA16_fE4ReadERN9rapidjson12GenericValueINS3_4UTF8IcEENS3_19MemoryPoolAllocatorINS3_12CrtAllocatorEEEEERS1_:
  303|      9|    static bool Read(Value &val, float (&out)[N]) {
  304|      9|        if (!val.IsArray() || val.Size() != N) return false;
  ------------------
  |  Branch (304:13): [True: 0, False: 9]
  |  Branch (304:31): [True: 0, False: 9]
  ------------------
  305|    153|        for (unsigned int i = 0; i < N; ++i) {
  ------------------
  |  Branch (305:34): [True: 144, False: 9]
  ------------------
  306|    144|            if (val[i].IsNumber())
  ------------------
  |  Branch (306:17): [True: 144, False: 0]
  ------------------
  307|    144|                out[i] = static_cast<float>(val[i].GetDouble());
  308|    144|        }
  309|      9|        return true;
  310|      9|    }
glTFExporter.cpp:_ZN10glTFCommonL10ReadMemberINS_8NullableIA3_fEEEEbRN9rapidjson12GenericValueINS4_4UTF8IcEENS4_19MemoryPoolAllocatorINS4_12CrtAllocatorEEEEEPKcRT_:
  369|      2|inline static bool ReadMember(Value &obj, const char *id, T &out) {
  370|      2|    if (!obj.IsObject()) {
  ------------------
  |  Branch (370:9): [True: 0, False: 2]
  ------------------
  371|      0|        return false;
  372|      0|    }
  373|      2|    Value::MemberIterator it = obj.FindMember(id);
  374|      2|    if (it != obj.MemberEnd()) {
  ------------------
  |  Branch (374:9): [True: 2, False: 0]
  ------------------
  375|      2|        return ReadHelper<T>::Read(it->value, out);
  376|      2|    }
  377|      0|    return false;
  378|      2|}
_ZN10glTFCommon10ReadHelperINS_8NullableIA3_fEEE4ReadERN9rapidjson12GenericValueINS5_4UTF8IcEENS5_19MemoryPoolAllocatorINS5_12CrtAllocatorEEEEERS3_:
  329|      3|    static bool Read(Value &val, Nullable<T> &out) {
  330|      3|        return out.isPresent = ReadHelper<T>::Read(val, out.value);
  331|      3|    }
_ZN10glTFCommon10ReadHelperIA3_fE4ReadERN9rapidjson12GenericValueINS3_4UTF8IcEENS3_19MemoryPoolAllocatorINS3_12CrtAllocatorEEEEERS1_:
  303|      3|    static bool Read(Value &val, float (&out)[N]) {
  304|      3|        if (!val.IsArray() || val.Size() != N) return false;
  ------------------
  |  Branch (304:13): [True: 0, False: 3]
  |  Branch (304:31): [True: 0, False: 3]
  ------------------
  305|     12|        for (unsigned int i = 0; i < N; ++i) {
  ------------------
  |  Branch (305:34): [True: 9, False: 3]
  ------------------
  306|      9|            if (val[i].IsNumber())
  ------------------
  |  Branch (306:17): [True: 9, False: 0]
  ------------------
  307|      9|                out[i] = static_cast<float>(val[i].GetDouble());
  308|      9|        }
  309|      3|        return true;
  310|      3|    }
glTFExporter.cpp:_ZN10glTFCommonL10ReadMemberINS_8NullableIA4_fEEEEbRN9rapidjson12GenericValueINS4_4UTF8IcEENS4_19MemoryPoolAllocatorINS4_12CrtAllocatorEEEEEPKcRT_:
  369|      1|inline static bool ReadMember(Value &obj, const char *id, T &out) {
  370|      1|    if (!obj.IsObject()) {
  ------------------
  |  Branch (370:9): [True: 0, False: 1]
  ------------------
  371|      0|        return false;
  372|      0|    }
  373|      1|    Value::MemberIterator it = obj.FindMember(id);
  374|      1|    if (it != obj.MemberEnd()) {
  ------------------
  |  Branch (374:9): [True: 1, False: 0]
  ------------------
  375|      1|        return ReadHelper<T>::Read(it->value, out);
  376|      1|    }
  377|      0|    return false;
  378|      1|}
_ZN10glTFCommon10ReadHelperINS_8NullableIA4_fEEE4ReadERN9rapidjson12GenericValueINS5_4UTF8IcEENS5_19MemoryPoolAllocatorINS5_12CrtAllocatorEEEEERS3_:
  329|      1|    static bool Read(Value &val, Nullable<T> &out) {
  330|      1|        return out.isPresent = ReadHelper<T>::Read(val, out.value);
  331|      1|    }
_ZN10glTFCommon10ReadHelperIA4_fE4ReadERN9rapidjson12GenericValueINS3_4UTF8IcEENS3_19MemoryPoolAllocatorINS3_12CrtAllocatorEEEEERS1_:
  303|      9|    static bool Read(Value &val, float (&out)[N]) {
  304|      9|        if (!val.IsArray() || val.Size() != N) return false;
  ------------------
  |  Branch (304:13): [True: 0, False: 9]
  |  Branch (304:31): [True: 0, False: 9]
  ------------------
  305|     45|        for (unsigned int i = 0; i < N; ++i) {
  ------------------
  |  Branch (305:34): [True: 36, False: 9]
  ------------------
  306|     36|            if (val[i].IsNumber())
  ------------------
  |  Branch (306:17): [True: 36, False: 0]
  ------------------
  307|     36|                out[i] = static_cast<float>(val[i].GetDouble());
  308|     36|        }
  309|      9|        return true;
  310|      9|    }
_ZN10glTFCommon3RefIN4glTF4MeshEEC2ERNSt3__16vectorIPS2_NS4_9allocatorIS6_EEEEj:
  264|      2|            vector(&vec),
  265|      2|            index(idx) {}
glTFExporter.cpp:_ZN10glTFCommonL15MemberOrDefaultIN4glTF13PrimitiveModeEEET_RN9rapidjson12GenericValueINS4_4UTF8IcEENS4_19MemoryPoolAllocatorINS4_12CrtAllocatorEEEEEPKcS3_:
  381|      3|inline static T MemberOrDefault(Value &obj, const char *id, T defaultValue) {
  382|      3|    T out;
  383|      3|    return ReadMember(obj, id, out) ? out : defaultValue;
  ------------------
  |  Branch (383:12): [True: 3, False: 0]
  ------------------
  384|      3|}
glTFExporter.cpp:_ZN10glTFCommonL10ReadMemberIN4glTF13PrimitiveModeEEEbRN9rapidjson12GenericValueINS3_4UTF8IcEENS3_19MemoryPoolAllocatorINS3_12CrtAllocatorEEEEEPKcRT_:
  369|      3|inline static bool ReadMember(Value &obj, const char *id, T &out) {
  370|      3|    if (!obj.IsObject()) {
  ------------------
  |  Branch (370:9): [True: 0, False: 3]
  ------------------
  371|      0|        return false;
  372|      0|    }
  373|      3|    Value::MemberIterator it = obj.FindMember(id);
  374|      3|    if (it != obj.MemberEnd()) {
  ------------------
  |  Branch (374:9): [True: 3, False: 0]
  ------------------
  375|      3|        return ReadHelper<T>::Read(it->value, out);
  376|      3|    }
  377|      0|    return false;
  378|      3|}
_ZN10glTFCommon10ReadHelperIN4glTF13PrimitiveModeEE4ReadERN9rapidjson12GenericValueINS4_4UTF8IcEENS4_19MemoryPoolAllocatorINS4_12CrtAllocatorEEEEERS2_:
  282|      3|    static bool Read(Value &val, T &out) {
  283|      3|        return val.IsInt() ? out = static_cast<T>(val.GetInt()), true : false;
  ------------------
  |  Branch (283:16): [True: 3, False: 0]
  ------------------
  284|      3|    }
glTFExporter.cpp:_ZN10glTFCommonL15MemberOrDefaultIPKcEET_RN9rapidjson12GenericValueINS4_4UTF8IcEENS4_19MemoryPoolAllocatorINS4_12CrtAllocatorEEEEES2_S3_:
  381|     14|inline static T MemberOrDefault(Value &obj, const char *id, T defaultValue) {
  382|     14|    T out;
  383|     14|    return ReadMember(obj, id, out) ? out : defaultValue;
  ------------------
  |  Branch (383:12): [True: 14, False: 0]
  ------------------
  384|     14|}
glTFExporter.cpp:_ZN10glTFCommonL15MemberOrDefaultImEET_RN9rapidjson12GenericValueINS2_4UTF8IcEENS2_19MemoryPoolAllocatorINS2_12CrtAllocatorEEEEEPKcS1_:
  381|      3|inline static T MemberOrDefault(Value &obj, const char *id, T defaultValue) {
  382|      3|    T out;
  383|      3|    return ReadMember(obj, id, out) ? out : defaultValue;
  ------------------
  |  Branch (383:12): [True: 3, False: 0]
  ------------------
  384|      3|}
glTFExporter.cpp:_ZN10glTFCommonL15MemberOrDefaultIjEET_RN9rapidjson12GenericValueINS2_4UTF8IcEENS2_19MemoryPoolAllocatorINS2_12CrtAllocatorEEEEEPKcS1_:
  381|     32|inline static T MemberOrDefault(Value &obj, const char *id, T defaultValue) {
  382|     32|    T out;
  383|     32|    return ReadMember(obj, id, out) ? out : defaultValue;
  ------------------
  |  Branch (383:12): [True: 32, False: 0]
  ------------------
  384|     32|}
glTFExporter.cpp:_ZN10glTFCommonL10ReadMemberIjEEbRN9rapidjson12GenericValueINS1_4UTF8IcEENS1_19MemoryPoolAllocatorINS1_12CrtAllocatorEEEEEPKcRT_:
  369|     32|inline static bool ReadMember(Value &obj, const char *id, T &out) {
  370|     32|    if (!obj.IsObject()) {
  ------------------
  |  Branch (370:9): [True: 0, False: 32]
  ------------------
  371|      0|        return false;
  372|      0|    }
  373|     32|    Value::MemberIterator it = obj.FindMember(id);
  374|     32|    if (it != obj.MemberEnd()) {
  ------------------
  |  Branch (374:9): [True: 32, False: 0]
  ------------------
  375|     32|        return ReadHelper<T>::Read(it->value, out);
  376|     32|    }
  377|      0|    return false;
  378|     32|}
_ZN10glTFCommon10ReadHelperIjE4ReadERN9rapidjson12GenericValueINS2_4UTF8IcEENS2_19MemoryPoolAllocatorINS2_12CrtAllocatorEEEEERj:
  282|     32|    static bool Read(Value &val, T &out) {
  283|     32|        return val.IsInt() ? out = static_cast<T>(val.GetInt()), true : false;
  ------------------
  |  Branch (283:16): [True: 32, False: 0]
  ------------------
  284|     32|    }
glTFExporter.cpp:_ZN10glTFCommonL15MemberOrDefaultIN4glTF13ComponentTypeEEET_RN9rapidjson12GenericValueINS4_4UTF8IcEENS4_19MemoryPoolAllocatorINS4_12CrtAllocatorEEEEEPKcS3_:
  381|      8|inline static T MemberOrDefault(Value &obj, const char *id, T defaultValue) {
  382|      8|    T out;
  383|      8|    return ReadMember(obj, id, out) ? out : defaultValue;
  ------------------
  |  Branch (383:12): [True: 8, False: 0]
  ------------------
  384|      8|}
_ZN10glTFCommon3RefIN4glTF8MaterialEEC2ERNSt3__16vectorIPS2_NS4_9allocatorIS6_EEEEj:
  264|      2|            vector(&vec),
  265|      2|            index(idx) {}
_ZN10glTFCommon3RefIN4glTF7TextureEEC2Ev:
  261|      8|            vector(nullptr),
  262|      8|            index(0) {}
_ZN10glTFCommon10FindMemberERN9rapidjson12GenericValueINS0_4UTF8IcEENS0_19MemoryPoolAllocatorINS0_12CrtAllocatorEEEEEPKc:
  386|     40|inline Value *FindMember(Value &val, const char *id) {
  387|     40|    if (!val.IsObject()) {
  ------------------
  |  Branch (387:9): [True: 0, False: 40]
  ------------------
  388|      0|        return nullptr;
  389|      0|    }
  390|     40|    Value::MemberIterator it = val.FindMember(id);
  391|     40|    return (it != val.MemberEnd()) ? &it->value : nullptr;
  ------------------
  |  Branch (391:12): [True: 16, False: 24]
  ------------------
  392|     40|}
_ZN10glTFCommon3RefIN4glTF7TextureEEC2ERNSt3__16vectorIPS2_NS4_9allocatorIS6_EEEEj:
  264|      2|            vector(&vec),
  265|      2|            index(idx) {}
_ZN10glTFCommon3RefIN4glTF7SamplerEEC2Ev:
  261|      2|            vector(nullptr),
  262|      2|            index(0) {}
_ZN10glTFCommon3RefIN4glTF5ImageEEC2Ev:
  261|      2|            vector(nullptr),
  262|      2|            index(0) {}
_ZN10glTFCommon3RefIN4glTF5ImageEEC2ERNSt3__16vectorIPS2_NS4_9allocatorIS6_EEEEj:
  264|      2|            vector(&vec),
  265|      2|            index(idx) {}
_ZNK10glTFCommon3RefIN4glTF10BufferViewEEcvbEv:
  269|      4|    operator bool() const { return vector != nullptr && index < vector->size(); }
  ------------------
  |  Branch (269:36): [True: 4, False: 0]
  |  Branch (269:57): [True: 4, False: 0]
  ------------------
_ZN10glTFCommon3RefIN4glTF7SamplerEEC2ERNSt3__16vectorIPS2_NS4_9allocatorIS6_EEEEj:
  264|      2|            vector(&vec),
  265|      2|            index(idx) {}
glTFExporter.cpp:_ZN10glTFCommonL10ReadMemberIN4glTF16SamplerMagFilterEEEbRN9rapidjson12GenericValueINS3_4UTF8IcEENS3_19MemoryPoolAllocatorINS3_12CrtAllocatorEEEEEPKcRT_:
  369|      2|inline static bool ReadMember(Value &obj, const char *id, T &out) {
  370|      2|    if (!obj.IsObject()) {
  ------------------
  |  Branch (370:9): [True: 0, False: 2]
  ------------------
  371|      0|        return false;
  372|      0|    }
  373|      2|    Value::MemberIterator it = obj.FindMember(id);
  374|      2|    if (it != obj.MemberEnd()) {
  ------------------
  |  Branch (374:9): [True: 2, False: 0]
  ------------------
  375|      2|        return ReadHelper<T>::Read(it->value, out);
  376|      2|    }
  377|      0|    return false;
  378|      2|}
_ZN10glTFCommon10ReadHelperIN4glTF16SamplerMagFilterEE4ReadERN9rapidjson12GenericValueINS4_4UTF8IcEENS4_19MemoryPoolAllocatorINS4_12CrtAllocatorEEEEERS2_:
  282|      2|    static bool Read(Value &val, T &out) {
  283|      2|        return val.IsInt() ? out = static_cast<T>(val.GetInt()), true : false;
  ------------------
  |  Branch (283:16): [True: 2, False: 0]
  ------------------
  284|      2|    }
glTFExporter.cpp:_ZN10glTFCommonL10ReadMemberIN4glTF16SamplerMinFilterEEEbRN9rapidjson12GenericValueINS3_4UTF8IcEENS3_19MemoryPoolAllocatorINS3_12CrtAllocatorEEEEEPKcRT_:
  369|      2|inline static bool ReadMember(Value &obj, const char *id, T &out) {
  370|      2|    if (!obj.IsObject()) {
  ------------------
  |  Branch (370:9): [True: 0, False: 2]
  ------------------
  371|      0|        return false;
  372|      0|    }
  373|      2|    Value::MemberIterator it = obj.FindMember(id);
  374|      2|    if (it != obj.MemberEnd()) {
  ------------------
  |  Branch (374:9): [True: 2, False: 0]
  ------------------
  375|      2|        return ReadHelper<T>::Read(it->value, out);
  376|      2|    }
  377|      0|    return false;
  378|      2|}
_ZN10glTFCommon10ReadHelperIN4glTF16SamplerMinFilterEE4ReadERN9rapidjson12GenericValueINS4_4UTF8IcEENS4_19MemoryPoolAllocatorINS4_12CrtAllocatorEEEEERS2_:
  282|      2|    static bool Read(Value &val, T &out) {
  283|      2|        return val.IsInt() ? out = static_cast<T>(val.GetInt()), true : false;
  ------------------
  |  Branch (283:16): [True: 2, False: 0]
  ------------------
  284|      2|    }
glTFExporter.cpp:_ZN10glTFCommonL10ReadMemberIN4glTF11SamplerWrapEEEbRN9rapidjson12GenericValueINS3_4UTF8IcEENS3_19MemoryPoolAllocatorINS3_12CrtAllocatorEEEEEPKcRT_:
  369|      4|inline static bool ReadMember(Value &obj, const char *id, T &out) {
  370|      4|    if (!obj.IsObject()) {
  ------------------
  |  Branch (370:9): [True: 0, False: 4]
  ------------------
  371|      0|        return false;
  372|      0|    }
  373|      4|    Value::MemberIterator it = obj.FindMember(id);
  374|      4|    if (it != obj.MemberEnd()) {
  ------------------
  |  Branch (374:9): [True: 4, False: 0]
  ------------------
  375|      4|        return ReadHelper<T>::Read(it->value, out);
  376|      4|    }
  377|      0|    return false;
  378|      4|}
_ZN10glTFCommon10ReadHelperIN4glTF11SamplerWrapEE4ReadERN9rapidjson12GenericValueINS4_4UTF8IcEENS4_19MemoryPoolAllocatorINS4_12CrtAllocatorEEEEERS2_:
  282|      4|    static bool Read(Value &val, T &out) {
  283|      4|        return val.IsInt() ? out = static_cast<T>(val.GetInt()), true : false;
  ------------------
  |  Branch (283:16): [True: 4, False: 0]
  ------------------
  284|      4|    }
glTFExporter.cpp:_ZN10glTFCommonL9ReadValueIA4_fEEbRN9rapidjson12GenericValueINS2_4UTF8IcEENS2_19MemoryPoolAllocatorINS2_12CrtAllocatorEEEEERT_:
  364|      2|inline static bool ReadValue(Value &val, T &out) {
  365|      2|    return ReadHelper<T>::Read(val, out);
  366|      2|}
glTFExporter.cpp:_ZN10glTFCommonL10ReadMemberIfEEbRN9rapidjson12GenericValueINS1_4UTF8IcEENS1_19MemoryPoolAllocatorINS1_12CrtAllocatorEEEEEPKcRT_:
  369|      4|inline static bool ReadMember(Value &obj, const char *id, T &out) {
  370|      4|    if (!obj.IsObject()) {
  ------------------
  |  Branch (370:9): [True: 0, False: 4]
  ------------------
  371|      0|        return false;
  372|      0|    }
  373|      4|    Value::MemberIterator it = obj.FindMember(id);
  374|      4|    if (it != obj.MemberEnd()) {
  ------------------
  |  Branch (374:9): [True: 2, False: 2]
  ------------------
  375|      2|        return ReadHelper<T>::Read(it->value, out);
  376|      2|    }
  377|      2|    return false;
  378|      4|}
_ZN10glTFCommon10ReadHelperIfE4ReadERN9rapidjson12GenericValueINS2_4UTF8IcEENS2_19MemoryPoolAllocatorINS2_12CrtAllocatorEEEEERf:
  296|      7|    static bool Read(Value &val, float &out) {
  297|      7|        return val.IsNumber() ? out = static_cast<float>(val.GetDouble()), true : false;
  ------------------
  |  Branch (297:16): [True: 7, False: 0]
  ------------------
  298|      7|    }
_ZN10glTFCommon10ReadHelperIbE4ReadERN9rapidjson12GenericValueINS2_4UTF8IcEENS2_19MemoryPoolAllocatorINS2_12CrtAllocatorEEEEERb:
  289|      8|    static bool Read(Value &val, bool &out) {
  290|      8|        return val.IsBool() ? out = val.GetBool(), true : false;
  ------------------
  |  Branch (290:16): [True: 8, False: 0]
  ------------------
  291|      8|    }
glTFExporter.cpp:_ZN10glTFCommonL10ReadMemberImEEbRN9rapidjson12GenericValueINS1_4UTF8IcEENS1_19MemoryPoolAllocatorINS1_12CrtAllocatorEEEEEPKcRT_:
  369|      3|inline static bool ReadMember(Value &obj, const char *id, T &out) {
  370|      3|    if (!obj.IsObject()) {
  ------------------
  |  Branch (370:9): [True: 0, False: 3]
  ------------------
  371|      0|        return false;
  372|      0|    }
  373|      3|    Value::MemberIterator it = obj.FindMember(id);
  374|      3|    if (it != obj.MemberEnd()) {
  ------------------
  |  Branch (374:9): [True: 3, False: 0]
  ------------------
  375|      3|        return ReadHelper<T>::Read(it->value, out);
  376|      3|    }
  377|      0|    return false;
  378|      3|}
_ZN10glTFCommon10ReadHelperImE4ReadERN9rapidjson12GenericValueINS2_4UTF8IcEENS2_19MemoryPoolAllocatorINS2_12CrtAllocatorEEEEERm:
  336|     43|    static bool Read(Value &val, uint64_t &out) {
  337|     43|        return val.IsUint64() ? out = val.GetUint64(), true : false;
  ------------------
  |  Branch (337:16): [True: 43, False: 0]
  ------------------
  338|     43|    }
glTFExporter.cpp:_ZN10glTFCommonL10ReadMemberIN4glTF13ComponentTypeEEEbRN9rapidjson12GenericValueINS3_4UTF8IcEENS3_19MemoryPoolAllocatorINS3_12CrtAllocatorEEEEEPKcRT_:
  369|      8|inline static bool ReadMember(Value &obj, const char *id, T &out) {
  370|      8|    if (!obj.IsObject()) {
  ------------------
  |  Branch (370:9): [True: 0, False: 8]
  ------------------
  371|      0|        return false;
  372|      0|    }
  373|      8|    Value::MemberIterator it = obj.FindMember(id);
  374|      8|    if (it != obj.MemberEnd()) {
  ------------------
  |  Branch (374:9): [True: 8, False: 0]
  ------------------
  375|      8|        return ReadHelper<T>::Read(it->value, out);
  376|      8|    }
  377|      0|    return false;
  378|      8|}
_ZN10glTFCommon10ReadHelperIN4glTF13ComponentTypeEE4ReadERN9rapidjson12GenericValueINS4_4UTF8IcEENS4_19MemoryPoolAllocatorINS4_12CrtAllocatorEEEEERS2_:
  282|      8|    static bool Read(Value &val, T &out) {
  283|      8|        return val.IsInt() ? out = static_cast<T>(val.GetInt()), true : false;
  ------------------
  |  Branch (283:16): [True: 8, False: 0]
  ------------------
  284|      8|    }
glTFExporter.cpp:_ZN10glTFCommonL10ReadMemberIPKcEEbRN9rapidjson12GenericValueINS3_4UTF8IcEENS3_19MemoryPoolAllocatorINS3_12CrtAllocatorEEEEES2_RT_:
  369|     26|inline static bool ReadMember(Value &obj, const char *id, T &out) {
  370|     26|    if (!obj.IsObject()) {
  ------------------
  |  Branch (370:9): [True: 0, False: 26]
  ------------------
  371|      0|        return false;
  372|      0|    }
  373|     26|    Value::MemberIterator it = obj.FindMember(id);
  374|     26|    if (it != obj.MemberEnd()) {
  ------------------
  |  Branch (374:9): [True: 26, False: 0]
  ------------------
  375|     26|        return ReadHelper<T>::Read(it->value, out);
  376|     26|    }
  377|      0|    return false;
  378|     26|}
_ZN10glTFCommon10ReadHelperIPKcE4ReadERN9rapidjson12GenericValueINS4_4UTF8IcEENS4_19MemoryPoolAllocatorINS4_12CrtAllocatorEEEEERS2_:
  315|     44|    static bool Read(Value &val, const char *&out) {
  316|     44|        return val.IsString() ? (out = val.GetString(), true) : false;
  ------------------
  |  Branch (316:16): [True: 44, False: 0]
  ------------------
  317|     44|    }
_ZNK10glTFCommon3RefIN4glTF4MeshEEcvbEv:
  269|      2|    operator bool() const { return vector != nullptr && index < vector->size(); }
  ------------------
  |  Branch (269:36): [True: 2, False: 0]
  |  Branch (269:57): [True: 2, False: 0]
  ------------------
_ZN10glTFCommon10FindStringERN9rapidjson12GenericValueINS0_4UTF8IcEENS0_19MemoryPoolAllocatorINS0_12CrtAllocatorEEEEEPKc:
  511|     26|inline Value *FindString(Value &val, const char *id) {
  512|     26|    Value::MemberIterator it = val.FindMember(id);
  513|     26|    return (it != val.MemberEnd() && it->value.IsString()) ? &it->value : nullptr;
  ------------------
  |  Branch (513:13): [True: 17, False: 9]
  |  Branch (513:38): [True: 16, False: 1]
  ------------------
  514|     26|}
_ZNK10glTFCommon3RefIN4glTF6CameraEEcvbEv:
  269|      4|    operator bool() const { return vector != nullptr && index < vector->size(); }
  ------------------
  |  Branch (269:36): [True: 0, False: 4]
  |  Branch (269:57): [True: 0, False: 0]
  ------------------
_ZN10glTFCommon10FindObjectERN9rapidjson12GenericValueINS0_4UTF8IcEENS0_19MemoryPoolAllocatorINS0_12CrtAllocatorEEEEEPKc:
  516|     67|inline Value *FindObject(Value &val, const char *id) {
  517|     67|    Value::MemberIterator it = val.FindMember(id);
  518|     67|    return (it != val.MemberEnd() && it->value.IsObject()) ? &it->value : nullptr;
  ------------------
  |  Branch (518:13): [True: 44, False: 23]
  |  Branch (518:38): [True: 44, False: 0]
  ------------------
  519|     67|}
_ZNK10glTFCommon3RefIN4glTF8AccessorEEcvbEv:
  269|      3|    operator bool() const { return vector != nullptr && index < vector->size(); }
  ------------------
  |  Branch (269:36): [True: 3, False: 0]
  |  Branch (269:57): [True: 3, False: 0]
  ------------------
_ZNK10glTFCommon3RefIN4glTF7TextureEEcvbEv:
  269|      4|    operator bool() const { return vector != nullptr && index < vector->size(); }
  ------------------
  |  Branch (269:36): [True: 1, False: 3]
  |  Branch (269:57): [True: 1, False: 0]
  ------------------
_ZN10glTFCommon3RefIN4glTF7TextureEEptEv:
  271|      3|    T *operator->() { return (*vector)[index]; }
_ZN10glTFCommon3RefIN4glTF5ImageEEptEv:
  271|      1|    T *operator->() { return (*vector)[index]; }
_ZN10glTFCommon3RefIN4glTF5SceneEEptEv:
  271|      1|    T *operator->() { return (*vector)[index]; }
_ZN10glTFCommon10FindObjectERN9rapidjson15GenericDocumentINS0_4UTF8IcEENS0_19MemoryPoolAllocatorINS0_12CrtAllocatorEEES5_EEPKc:
  503|     30|inline Value *FindObject(Document &doc, const char *memberId) {
  504|     30|    return FindObjectInContext(doc, memberId, "the document");
  505|     30|}
_ZN10glTFCommon19FindObjectInContextERN9rapidjson12GenericValueINS0_4UTF8IcEENS0_19MemoryPoolAllocatorINS0_12CrtAllocatorEEEEEPKcSA_SA_:
  461|    195|inline Value *FindObjectInContext(Value &val, const char * memberId, const char *context, const char *extraContext = nullptr) {
  462|    195|    if (!val.IsObject()) {
  ------------------
  |  Branch (462:9): [True: 0, False: 195]
  ------------------
  463|      0|        return nullptr;
  464|      0|    }
  465|    195|    Value::MemberIterator it = val.FindMember(memberId);
  466|    195|    if (it == val.MemberEnd()) {
  ------------------
  |  Branch (466:9): [True: 165, False: 30]
  ------------------
  467|    165|        return nullptr;
  468|    165|    }
  469|     30|    if (!it->value.IsObject()) {
  ------------------
  |  Branch (469:9): [True: 0, False: 30]
  ------------------
  470|      0|        ASSIMP_LOG_ERROR("Member \"", memberId, "\" was not of type \"", context, "\" when reading ", extraContext);
  471|      0|        return nullptr;
  472|      0|   }
  473|     30|    return &it->value;
  474|     30|}
_ZNK10glTFCommon3RefIN4glTF8MaterialEEcvbEv:
  269|      1|    operator bool() const { return vector != nullptr && index < vector->size(); }
  ------------------
  |  Branch (269:36): [True: 1, False: 0]
  |  Branch (269:57): [True: 1, False: 0]
  ------------------
_ZNK10glTFCommon3RefIN4glTF5ImageEEcvbEv:
  269|      1|    operator bool() const { return vector != nullptr && index < vector->size(); }
  ------------------
  |  Branch (269:36): [True: 1, False: 0]
  |  Branch (269:57): [True: 1, False: 0]
  ------------------
_ZN10glTFCommon3RefIN4glTF5SceneEEC2Ev:
  261|     50|            vector(nullptr),
  262|     50|            index(0) {}
_ZN10glTFCommon3RefIN4glTF4NodeEEC2Ev:
  261|     11|            vector(nullptr),
  262|     11|            index(0) {}
_ZN10glTFCommon3RefIN4glTF4SkinEEC2Ev:
  261|     11|            vector(nullptr),
  262|     11|            index(0) {}
_ZN10glTFCommon3RefIN4glTF5SceneEEC2ERNSt3__16vectorIPS2_NS4_9allocatorIS6_EEEEj:
  264|      2|            vector(&vec),
  265|      2|            index(idx) {}
_ZN10glTFCommon9CopyValueERA4_KfR9aiColor4tIfE:
  145|      3|inline void CopyValue(const glTFCommon::vec4 &v, aiColor4D &out) {
  146|      3|    out.r = v[0];
  147|      3|    out.g = v[1];
  148|      3|    out.b = v[2];
  149|      3|    out.a = v[3];
  150|      3|}
_ZN10glTFCommon9CopyValueERA16_KfR12aiMatrix4x4tIfE:
  177|      4|inline void CopyValue(const glTFCommon::mat4 &v, aiMatrix4x4 &o) {
  178|      4|    o.a1 = v[0];
  179|      4|    o.b1 = v[1];
  180|      4|    o.c1 = v[2];
  181|      4|    o.d1 = v[3];
  182|      4|    o.a2 = v[4];
  183|      4|    o.b2 = v[5];
  184|      4|    o.c2 = v[6];
  185|      4|    o.d2 = v[7];
  186|      4|    o.a3 = v[8];
  187|      4|    o.b3 = v[9];
  188|      4|    o.c3 = v[10];
  189|      4|    o.d3 = v[11];
  190|      4|    o.a4 = v[12];
  191|      4|    o.b4 = v[13];
  192|      4|    o.c4 = v[14];
  193|      4|    o.d4 = v[15];
  194|      4|}
_ZN10glTFCommon19FindStringInContextERN9rapidjson12GenericValueINS0_4UTF8IcEENS0_19MemoryPoolAllocatorINS0_12CrtAllocatorEEEEEPKcSA_SA_:
  405|     24|inline Value *FindStringInContext(Value &val, const char *memberId, const char *context, const char *extraContext = nullptr) {
  406|     24|    if (!val.IsObject()) {
  ------------------
  |  Branch (406:9): [True: 0, False: 24]
  ------------------
  407|      0|        return nullptr;
  408|      0|    }
  409|     24|    Value::MemberIterator it = val.FindMember(memberId);
  410|     24|    if (it == val.MemberEnd()) {
  ------------------
  |  Branch (410:9): [True: 0, False: 24]
  ------------------
  411|      0|        return nullptr;
  412|      0|    }
  413|     24|    if (!it->value.IsString()) {
  ------------------
  |  Branch (413:9): [True: 1, False: 23]
  ------------------
  414|      1|        throwUnexpectedTypeError("string", memberId, context, extraContext);
  415|      1|    }
  416|     24|    return &it->value;
  417|     24|}
_ZN10glTFCommon17FindUIntInContextERN9rapidjson12GenericValueINS0_4UTF8IcEENS0_19MemoryPoolAllocatorINS0_12CrtAllocatorEEEEEPKcSA_SA_:
  433|    102|inline Value *FindUIntInContext(Value &val, const char *memberId, const char *context, const char *extraContext = nullptr) {
  434|    102|    if (!val.IsObject()) {
  ------------------
  |  Branch (434:9): [True: 0, False: 102]
  ------------------
  435|      0|        return nullptr;
  436|      0|    }
  437|    102|    Value::MemberIterator it = val.FindMember(memberId);
  438|    102|    if (it == val.MemberEnd()) {
  ------------------
  |  Branch (438:9): [True: 11, False: 91]
  ------------------
  439|     11|        return nullptr;
  440|     11|    }
  441|     91|    if (!it->value.IsUint()) {
  ------------------
  |  Branch (441:9): [True: 0, False: 91]
  ------------------
  442|      0|        throwUnexpectedTypeError("uint", memberId, context, extraContext);
  443|      0|    }
  444|     91|    return &it->value;
  445|    102|}
_ZN10glTFCommon18FindArrayInContextERN9rapidjson12GenericValueINS0_4UTF8IcEENS0_19MemoryPoolAllocatorINS0_12CrtAllocatorEEEEEPKcSA_SA_:
  447|    106|inline Value *FindArrayInContext(Value &val, const char *memberId, const char *context, const char *extraContext = nullptr) {
  448|    106|    if (!val.IsObject()) {
  ------------------
  |  Branch (448:9): [True: 0, False: 106]
  ------------------
  449|      0|        return nullptr;
  450|      0|    }
  451|    106|    Value::MemberIterator it = val.FindMember(memberId);
  452|    106|    if (it == val.MemberEnd()) {
  ------------------
  |  Branch (452:9): [True: 46, False: 60]
  ------------------
  453|     46|        return nullptr;
  454|     46|    }
  455|     60|    if (!it->value.IsArray()) {
  ------------------
  |  Branch (455:9): [True: 0, False: 60]
  ------------------
  456|      0|        throwUnexpectedTypeError("array", memberId, context, extraContext);
  457|      0|    }
  458|     60|    return &it->value;
  459|    106|}
_ZN10glTFCommon10FindStringERN9rapidjson15GenericDocumentINS0_4UTF8IcEENS0_19MemoryPoolAllocatorINS0_12CrtAllocatorEEES5_EEPKc:
  487|      3|inline Value *FindString(Document &doc, const char *memberId) {
  488|      3|    return FindStringInContext(doc, memberId, "the document");
  489|      3|}
_ZN10glTFCommon8FindUIntERN9rapidjson15GenericDocumentINS0_4UTF8IcEENS0_19MemoryPoolAllocatorINS0_12CrtAllocatorEEES5_EEPKc:
  495|      4|inline Value *FindUInt(Document &doc, const char *memberId) {
  496|      4|    return FindUIntInContext(doc, memberId, "the document");
  497|      4|}
_ZN10glTFCommon9FindArrayERN9rapidjson15GenericDocumentINS0_4UTF8IcEENS0_19MemoryPoolAllocatorINS0_12CrtAllocatorEEES5_EEPKc:
  499|     17|inline Value *FindArray(Document &val, const char *memberId) {
  500|     17|    return FindArrayInContext(val, memberId, "the document");
  501|     17|}
_ZN10glTFCommon10FindNumberERN9rapidjson12GenericValueINS0_4UTF8IcEENS0_19MemoryPoolAllocatorINS0_12CrtAllocatorEEEEEPKc:
  526|      1|inline Value *FindNumber(Value &val, const char *id) {
  527|      1|    Value::MemberIterator it = val.FindMember(id);
  528|      1|    return (it != val.MemberEnd() && it->value.IsNumber()) ? &it->value : nullptr;
  ------------------
  |  Branch (528:13): [True: 1, False: 0]
  |  Branch (528:38): [True: 1, False: 0]
  ------------------
  529|      1|}
_ZN10glTFCommon24throwUnexpectedTypeErrorILi7EEEvRAT__KcPS1_S4_S4_:
  395|      1|inline void throwUnexpectedTypeError(const char (&expectedTypeName)[N], const char *memberId, const char *context, const char *extraContext) {
  396|      1|    std::string fullContext = context;
  397|      1|    if (extraContext && (strlen(extraContext) > 0)) {
  ------------------
  |  Branch (397:9): [True: 0, False: 1]
  |  Branch (397:25): [True: 0, False: 0]
  ------------------
  398|      0|        fullContext = fullContext + " (" + extraContext + ")";
  399|      0|    }
  400|      1|    throw DeadlyImportError("Member \"", memberId, "\" was not of type \"", expectedTypeName, "\" when reading ", fullContext);
  401|      1|}
_ZNK10glTFCommon3RefIN5glTF210BufferViewEEcvbEv:
  269|     36|    operator bool() const { return vector != nullptr && index < vector->size(); }
  ------------------
  |  Branch (269:36): [True: 36, False: 0]
  |  Branch (269:57): [True: 36, False: 0]
  ------------------
_ZN10glTFCommon3RefIN5glTF25SceneEEC2Ev:
  261|     53|            vector(nullptr),
  262|     53|            index(0) {}
_ZN10glTFCommon3RefIN5glTF26BufferEEC2Ev:
  261|     73|            vector(nullptr),
  262|     73|            index(0) {}
_ZN10glTFCommon8NullableINSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEEC2Ev:
  246|     81|            isPresent(false) {}
_ZN10glTFCommon8NullableIdEC2Ev:
  246|     81|            isPresent(false) {}
_ZN10glTFCommon8NullableImEC2Ev:
  246|     81|            isPresent(false) {}
_ZN10glTFCommon8NullableIlEC2Ev:
  246|     81|            isPresent(false) {}
_ZN10glTFCommon8NullableIbEC2Ev:
  246|     81|            isPresent(false) {}
_ZN10glTFCommon8NullableINSt3__16vectorIN5glTF215CustomExtensionENS1_9allocatorIS4_EEEEEC2Ev:
  246|     81|            isPresent(false) {}
_ZN10glTFCommon3RefIN5glTF26BufferEEC2ERNSt3__16vectorIPS2_NS4_9allocatorIS6_EEEEj:
  264|     19|            vector(&vec),
  265|     19|            index(idx) {}
_ZN10glTFCommon3RefIN5glTF210BufferViewEEC2ERNSt3__16vectorIPS2_NS4_9allocatorIS6_EEEEj:
  264|     18|            vector(&vec),
  265|     18|            index(idx) {}
_ZN10glTFCommon3RefIN5glTF27TextureEEC2Ev:
  261|    102|            vector(nullptr),
  262|    102|            index(0) {}
_ZN10glTFCommon3RefIN5glTF210BufferViewEEC2Ev:
  261|     22|            vector(nullptr),
  262|     22|            index(0) {}
_ZN10glTFCommon3RefIN5glTF28AccessorEEC2ERNSt3__16vectorIPS2_NS4_9allocatorIS6_EEEEj:
  264|     18|            vector(&vec),
  265|     18|            index(idx) {}
_ZN10glTFCommon3RefIN5glTF28AccessorEEC2Ev:
  261|     21|            vector(nullptr),
  262|     21|            index(0) {}
_ZNK10glTFCommon3RefIN5glTF26BufferEEcvbEv:
  269|     19|    operator bool() const { return vector != nullptr && index < vector->size(); }
  ------------------
  |  Branch (269:36): [True: 18, False: 1]
  |  Branch (269:57): [True: 18, False: 0]
  ------------------
_ZN10glTFCommon3RefIN5glTF26BufferEEptEv:
  271|     37|    T *operator->() { return (*vector)[index]; }
_ZN10glTFCommon3RefIN5glTF210BufferViewEEptEv:
  271|     72|    T *operator->() { return (*vector)[index]; }
_ZN10glTFCommon3RefIN5glTF28MaterialEEC2Ev:
  261|      9|            vector(nullptr),
  262|      9|            index(0) {}
_ZNK10glTFCommon3RefIN5glTF24NodeEEcvbEv:
  269|      4|    operator bool() const { return vector != nullptr && index < vector->size(); }
  ------------------
  |  Branch (269:36): [True: 4, False: 0]
  |  Branch (269:57): [True: 4, False: 0]
  ------------------
_ZN10glTFCommon3RefIN5glTF24NodeEEC2Ev:
  261|      9|            vector(nullptr),
  262|      9|            index(0) {}
_ZN10glTFCommon3RefIN5glTF27SamplerEEC2ERNSt3__16vectorIPS2_NS4_9allocatorIS6_EEEEj:
  264|      1|            vector(&vec),
  265|      1|            index(idx) {}
_ZN10glTFCommon3RefIN5glTF27SamplerEEC2Ev:
  261|      2|            vector(nullptr),
  262|      2|            index(0) {}
_ZN10glTFCommon3RefIN5glTF27TextureEEC2ERNSt3__16vectorIPS2_NS4_9allocatorIS6_EEEEj:
  264|      3|            vector(&vec),
  265|      3|            index(idx) {}
_ZN10glTFCommon3RefIN5glTF25ImageEEC2Ev:
  261|      2|            vector(nullptr),
  262|      2|            index(0) {}
_ZN10glTFCommon3RefIN5glTF25ImageEEC2ERNSt3__16vectorIPS2_NS4_9allocatorIS6_EEEEj:
  264|      1|            vector(&vec),
  265|      1|            index(idx) {}
_ZN10glTFCommon8NullableIN5glTF221PbrSpecularGlossinessEEC2Ev:
  246|      6|            isPresent(false) {}
_ZN10glTFCommon8NullableIN5glTF216MaterialSpecularEEC2Ev:
  246|      6|            isPresent(false) {}
_ZN10glTFCommon8NullableIN5glTF213MaterialSheenEEC2Ev:
  246|      6|            isPresent(false) {}
_ZN10glTFCommon8NullableIN5glTF217MaterialClearcoatEEC2Ev:
  246|      6|            isPresent(false) {}
_ZN10glTFCommon8NullableIN5glTF220MaterialTransmissionEEC2Ev:
  246|      6|            isPresent(false) {}
_ZN10glTFCommon8NullableIN5glTF214MaterialVolumeEEC2Ev:
  246|      6|            isPresent(false) {}
_ZN10glTFCommon8NullableIN5glTF211MaterialIOREEC2Ev:
  246|      6|            isPresent(false) {}
_ZN10glTFCommon8NullableIN5glTF224MaterialEmissiveStrengthEEC2Ev:
  246|      6|            isPresent(false) {}
_ZN10glTFCommon8NullableIN5glTF218MaterialAnisotropyEEC2Ev:
  246|      6|            isPresent(false) {}
_ZN10glTFCommon3RefIN5glTF28MaterialEEC2ERNSt3__16vectorIPS2_NS4_9allocatorIS6_EEEEj:
  264|      5|            vector(&vec),
  265|      5|            index(idx) {}
_ZN10glTFCommon3RefIN5glTF24NodeEEC2ERNSt3__16vectorIPS2_NS4_9allocatorIS6_EEEEj:
  264|      4|            vector(&vec),
  265|      4|            index(idx) {}
_ZN10glTFCommon3RefIN5glTF24SkinEEC2Ev:
  261|      9|            vector(nullptr),
  262|      9|            index(0) {}
_ZN10glTFCommon3RefIN5glTF24MeshEEC2ERNSt3__16vectorIPS2_NS4_9allocatorIS6_EEEEj:
  264|      4|            vector(&vec),
  265|      4|            index(idx) {}
_ZN10glTFCommon3RefIN5glTF26CameraEEC2Ev:
  261|      9|            vector(nullptr),
  262|      9|            index(0) {}
_ZN10glTFCommon3RefIN5glTF25LightEEC2Ev:
  261|      9|            vector(nullptr),
  262|      9|            index(0) {}
_ZN10glTFCommon10ReadHelperIN5glTF213ComponentTypeEE4ReadERN9rapidjson12GenericValueINS4_4UTF8IcEENS4_19MemoryPoolAllocatorINS4_12CrtAllocatorEEEEERS2_:
  282|     18|    static bool Read(Value &val, T &out) {
  283|     18|        return val.IsInt() ? out = static_cast<T>(val.GetInt()), true : false;
  ------------------
  |  Branch (283:16): [True: 18, False: 0]
  ------------------
  284|     18|    }
_ZNK10glTFCommon3RefIN5glTF24MeshEEcvbEv:
  269|      4|    operator bool() const { return vector != nullptr && index < vector->size(); }
  ------------------
  |  Branch (269:36): [True: 4, False: 0]
  |  Branch (269:57): [True: 4, False: 0]
  ------------------
glTFImporter.cpp:_ZN10glTFCommonL10ReadMemberINSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEEEbRN9rapidjson12GenericValueINS8_4UTF8IcEENS8_19MemoryPoolAllocatorINS8_12CrtAllocatorEEEEEPKcRT_:
  369|     25|inline static bool ReadMember(Value &obj, const char *id, T &out) {
  370|     25|    if (!obj.IsObject()) {
  ------------------
  |  Branch (370:9): [True: 0, False: 25]
  ------------------
  371|      0|        return false;
  372|      0|    }
  373|     25|    Value::MemberIterator it = obj.FindMember(id);
  374|     25|    if (it != obj.MemberEnd()) {
  ------------------
  |  Branch (374:9): [True: 17, False: 8]
  ------------------
  375|     17|        return ReadHelper<T>::Read(it->value, out);
  376|     17|    }
  377|      8|    return false;
  378|     25|}
glTFImporter.cpp:_ZN10glTFCommonL15MemberOrDefaultIbEET_RN9rapidjson12GenericValueINS2_4UTF8IcEENS2_19MemoryPoolAllocatorINS2_12CrtAllocatorEEEEEPKcS1_:
  381|      8|inline static T MemberOrDefault(Value &obj, const char *id, T defaultValue) {
  382|      8|    T out;
  383|      8|    return ReadMember(obj, id, out) ? out : defaultValue;
  ------------------
  |  Branch (383:12): [True: 3, False: 5]
  ------------------
  384|      8|}
glTFImporter.cpp:_ZN10glTFCommonL10ReadMemberIbEEbRN9rapidjson12GenericValueINS1_4UTF8IcEENS1_19MemoryPoolAllocatorINS1_12CrtAllocatorEEEEEPKcRT_:
  369|      8|inline static bool ReadMember(Value &obj, const char *id, T &out) {
  370|      8|    if (!obj.IsObject()) {
  ------------------
  |  Branch (370:9): [True: 0, False: 8]
  ------------------
  371|      0|        return false;
  372|      0|    }
  373|      8|    Value::MemberIterator it = obj.FindMember(id);
  374|      8|    if (it != obj.MemberEnd()) {
  ------------------
  |  Branch (374:9): [True: 3, False: 5]
  ------------------
  375|      3|        return ReadHelper<T>::Read(it->value, out);
  376|      3|    }
  377|      5|    return false;
  378|      8|}
_ZNK10glTFCommon3RefIN4glTF5ImageEE8GetIndexEv:
  267|      1|    inline unsigned int GetIndex() const { return index; }
_ZNK10glTFCommon3RefIN4glTF8MaterialEE8GetIndexEv:
  267|      1|    inline unsigned int GetIndex() const { return index; }
_ZN10glTFCommon3RefIN4glTF4NodeEEdeEv:
  273|      4|    T &operator*() { return *((*vector)[index]); }
_ZNK10glTFCommon3RefIN4glTF4MeshEE8GetIndexEv:
  267|      2|    inline unsigned int GetIndex() const { return index; }
_ZNK10glTFCommon3RefIN4glTF5LightEEcvbEv:
  269|      4|    operator bool() const { return vector != nullptr && index < vector->size(); }
  ------------------
  |  Branch (269:36): [True: 0, False: 4]
  |  Branch (269:57): [True: 0, False: 0]
  ------------------
glTF2Importer.cpp:_ZN10glTFCommonL10ReadMemberINSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEEEbRN9rapidjson12GenericValueINS8_4UTF8IcEENS8_19MemoryPoolAllocatorINS8_12CrtAllocatorEEEEEPKcRT_:
  369|    104|inline static bool ReadMember(Value &obj, const char *id, T &out) {
  370|    104|    if (!obj.IsObject()) {
  ------------------
  |  Branch (370:9): [True: 0, False: 104]
  ------------------
  371|      0|        return false;
  372|      0|    }
  373|    104|    Value::MemberIterator it = obj.FindMember(id);
  374|    104|    if (it != obj.MemberEnd()) {
  ------------------
  |  Branch (374:9): [True: 46, False: 58]
  ------------------
  375|     46|        return ReadHelper<T>::Read(it->value, out);
  376|     46|    }
  377|     58|    return false;
  378|    104|}
glTF2Importer.cpp:_ZN10glTFCommonL10ReadMemberINS_8NullableIA3_fEEEEbRN9rapidjson12GenericValueINS4_4UTF8IcEENS4_19MemoryPoolAllocatorINS4_12CrtAllocatorEEEEEPKcRT_:
  369|     16|inline static bool ReadMember(Value &obj, const char *id, T &out) {
  370|     16|    if (!obj.IsObject()) {
  ------------------
  |  Branch (370:9): [True: 0, False: 16]
  ------------------
  371|      0|        return false;
  372|      0|    }
  373|     16|    Value::MemberIterator it = obj.FindMember(id);
  374|     16|    if (it != obj.MemberEnd()) {
  ------------------
  |  Branch (374:9): [True: 1, False: 15]
  ------------------
  375|      1|        return ReadHelper<T>::Read(it->value, out);
  376|      1|    }
  377|     15|    return false;
  378|     16|}
glTF2Importer.cpp:_ZN10glTFCommonL10ReadMemberINS_8NullableIA4_fEEEEbRN9rapidjson12GenericValueINS4_4UTF8IcEENS4_19MemoryPoolAllocatorINS4_12CrtAllocatorEEEEEPKcRT_:
  369|      8|inline static bool ReadMember(Value &obj, const char *id, T &out) {
  370|      8|    if (!obj.IsObject()) {
  ------------------
  |  Branch (370:9): [True: 0, False: 8]
  ------------------
  371|      0|        return false;
  372|      0|    }
  373|      8|    Value::MemberIterator it = obj.FindMember(id);
  374|      8|    if (it != obj.MemberEnd()) {
  ------------------
  |  Branch (374:9): [True: 0, False: 8]
  ------------------
  375|      0|        return ReadHelper<T>::Read(it->value, out);
  376|      0|    }
  377|      8|    return false;
  378|      8|}
glTF2Importer.cpp:_ZN10glTFCommonL15MemberOrDefaultIN5glTF213PrimitiveModeEEET_RN9rapidjson12GenericValueINS4_4UTF8IcEENS4_19MemoryPoolAllocatorINS4_12CrtAllocatorEEEEEPKcS3_:
  381|      8|inline static T MemberOrDefault(Value &obj, const char *id, T defaultValue) {
  382|      8|    T out;
  383|      8|    return ReadMember(obj, id, out) ? out : defaultValue;
  ------------------
  |  Branch (383:12): [True: 0, False: 8]
  ------------------
  384|      8|}
glTF2Importer.cpp:_ZN10glTFCommonL10ReadMemberIN5glTF213PrimitiveModeEEEbRN9rapidjson12GenericValueINS3_4UTF8IcEENS3_19MemoryPoolAllocatorINS3_12CrtAllocatorEEEEEPKcRT_:
  369|      8|inline static bool ReadMember(Value &obj, const char *id, T &out) {
  370|      8|    if (!obj.IsObject()) {
  ------------------
  |  Branch (370:9): [True: 0, False: 8]
  ------------------
  371|      0|        return false;
  372|      0|    }
  373|      8|    Value::MemberIterator it = obj.FindMember(id);
  374|      8|    if (it != obj.MemberEnd()) {
  ------------------
  |  Branch (374:9): [True: 0, False: 8]
  ------------------
  375|      0|        return ReadHelper<T>::Read(it->value, out);
  376|      0|    }
  377|      8|    return false;
  378|      8|}
glTF2Importer.cpp:_ZN10glTFCommonL15MemberOrDefaultIjEET_RN9rapidjson12GenericValueINS2_4UTF8IcEENS2_19MemoryPoolAllocatorINS2_12CrtAllocatorEEEEEPKcS1_:
  381|     18|inline static T MemberOrDefault(Value &obj, const char *id, T defaultValue) {
  382|     18|    T out;
  383|     18|    return ReadMember(obj, id, out) ? out : defaultValue;
  ------------------
  |  Branch (383:12): [True: 0, False: 18]
  ------------------
  384|     18|}
glTF2Importer.cpp:_ZN10glTFCommonL10ReadMemberIjEEbRN9rapidjson12GenericValueINS1_4UTF8IcEENS1_19MemoryPoolAllocatorINS1_12CrtAllocatorEEEEEPKcRT_:
  369|     18|inline static bool ReadMember(Value &obj, const char *id, T &out) {
  370|     18|    if (!obj.IsObject()) {
  ------------------
  |  Branch (370:9): [True: 0, False: 18]
  ------------------
  371|      0|        return false;
  372|      0|    }
  373|     18|    Value::MemberIterator it = obj.FindMember(id);
  374|     18|    if (it != obj.MemberEnd()) {
  ------------------
  |  Branch (374:9): [True: 0, False: 18]
  ------------------
  375|      0|        return ReadHelper<T>::Read(it->value, out);
  376|      0|    }
  377|     18|    return false;
  378|     18|}
glTF2Importer.cpp:_ZN10glTFCommonL15MemberOrDefaultImEET_RN9rapidjson12GenericValueINS2_4UTF8IcEENS2_19MemoryPoolAllocatorINS2_12CrtAllocatorEEEEEPKcS1_:
  381|     58|inline static T MemberOrDefault(Value &obj, const char *id, T defaultValue) {
  382|     58|    T out;
  383|     58|    return ReadMember(obj, id, out) ? out : defaultValue;
  ------------------
  |  Branch (383:12): [True: 40, False: 18]
  ------------------
  384|     58|}
glTF2Importer.cpp:_ZN10glTFCommonL15MemberOrDefaultIN5glTF213ComponentTypeEEET_RN9rapidjson12GenericValueINS4_4UTF8IcEENS4_19MemoryPoolAllocatorINS4_12CrtAllocatorEEEEEPKcS3_:
  381|     18|inline static T MemberOrDefault(Value &obj, const char *id, T defaultValue) {
  382|     18|    T out;
  383|     18|    return ReadMember(obj, id, out) ? out : defaultValue;
  ------------------
  |  Branch (383:12): [True: 18, False: 0]
  ------------------
  384|     18|}
glTF2Importer.cpp:_ZN10glTFCommonL10ReadMemberIN5glTF213ComponentTypeEEEbRN9rapidjson12GenericValueINS3_4UTF8IcEENS3_19MemoryPoolAllocatorINS3_12CrtAllocatorEEEEEPKcRT_:
  369|     18|inline static bool ReadMember(Value &obj, const char *id, T &out) {
  370|     18|    if (!obj.IsObject()) {
  ------------------
  |  Branch (370:9): [True: 0, False: 18]
  ------------------
  371|      0|        return false;
  372|      0|    }
  373|     18|    Value::MemberIterator it = obj.FindMember(id);
  374|     18|    if (it != obj.MemberEnd()) {
  ------------------
  |  Branch (374:9): [True: 18, False: 0]
  ------------------
  375|     18|        return ReadHelper<T>::Read(it->value, out);
  376|     18|    }
  377|      0|    return false;
  378|     18|}
glTF2Importer.cpp:_ZN10glTFCommonL10ReadMemberIPKcEEbRN9rapidjson12GenericValueINS3_4UTF8IcEENS3_19MemoryPoolAllocatorINS3_12CrtAllocatorEEEEES2_RT_:
  369|     18|inline static bool ReadMember(Value &obj, const char *id, T &out) {
  370|     18|    if (!obj.IsObject()) {
  ------------------
  |  Branch (370:9): [True: 0, False: 18]
  ------------------
  371|      0|        return false;
  372|      0|    }
  373|     18|    Value::MemberIterator it = obj.FindMember(id);
  374|     18|    if (it != obj.MemberEnd()) {
  ------------------
  |  Branch (374:9): [True: 18, False: 0]
  ------------------
  375|     18|        return ReadHelper<T>::Read(it->value, out);
  376|     18|    }
  377|      0|    return false;
  378|     18|}
glTF2Importer.cpp:_ZN10glTFCommonL10ReadMemberImEEbRN9rapidjson12GenericValueINS1_4UTF8IcEENS1_19MemoryPoolAllocatorINS1_12CrtAllocatorEEEEEPKcRT_:
  369|     58|inline static bool ReadMember(Value &obj, const char *id, T &out) {
  370|     58|    if (!obj.IsObject()) {
  ------------------
  |  Branch (370:9): [True: 0, False: 58]
  ------------------
  371|      0|        return false;
  372|      0|    }
  373|     58|    Value::MemberIterator it = obj.FindMember(id);
  374|     58|    if (it != obj.MemberEnd()) {
  ------------------
  |  Branch (374:9): [True: 40, False: 18]
  ------------------
  375|     40|        return ReadHelper<T>::Read(it->value, out);
  376|     40|    }
  377|     18|    return false;
  378|     58|}
glTF2Importer.cpp:_ZN10glTFCommonL10ReadMemberIA4_fEEbRN9rapidjson12GenericValueINS2_4UTF8IcEENS2_19MemoryPoolAllocatorINS2_12CrtAllocatorEEEEEPKcRT_:
  369|      6|inline static bool ReadMember(Value &obj, const char *id, T &out) {
  370|      6|    if (!obj.IsObject()) {
  ------------------
  |  Branch (370:9): [True: 0, False: 6]
  ------------------
  371|      0|        return false;
  372|      0|    }
  373|      6|    Value::MemberIterator it = obj.FindMember(id);
  374|      6|    if (it != obj.MemberEnd()) {
  ------------------
  |  Branch (374:9): [True: 6, False: 0]
  ------------------
  375|      6|        return ReadHelper<T>::Read(it->value, out);
  376|      6|    }
  377|      0|    return false;
  378|      6|}
glTF2Importer.cpp:_ZN10glTFCommonL10ReadMemberIN5glTF216SamplerMagFilterEEEbRN9rapidjson12GenericValueINS3_4UTF8IcEENS3_19MemoryPoolAllocatorINS3_12CrtAllocatorEEEEEPKcRT_:
  369|      1|inline static bool ReadMember(Value &obj, const char *id, T &out) {
  370|      1|    if (!obj.IsObject()) {
  ------------------
  |  Branch (370:9): [True: 0, False: 1]
  ------------------
  371|      0|        return false;
  372|      0|    }
  373|      1|    Value::MemberIterator it = obj.FindMember(id);
  374|      1|    if (it != obj.MemberEnd()) {
  ------------------
  |  Branch (374:9): [True: 0, False: 1]
  ------------------
  375|      0|        return ReadHelper<T>::Read(it->value, out);
  376|      0|    }
  377|      1|    return false;
  378|      1|}
glTF2Importer.cpp:_ZN10glTFCommonL10ReadMemberIN5glTF216SamplerMinFilterEEEbRN9rapidjson12GenericValueINS3_4UTF8IcEENS3_19MemoryPoolAllocatorINS3_12CrtAllocatorEEEEEPKcRT_:
  369|      1|inline static bool ReadMember(Value &obj, const char *id, T &out) {
  370|      1|    if (!obj.IsObject()) {
  ------------------
  |  Branch (370:9): [True: 0, False: 1]
  ------------------
  371|      0|        return false;
  372|      0|    }
  373|      1|    Value::MemberIterator it = obj.FindMember(id);
  374|      1|    if (it != obj.MemberEnd()) {
  ------------------
  |  Branch (374:9): [True: 0, False: 1]
  ------------------
  375|      0|        return ReadHelper<T>::Read(it->value, out);
  376|      0|    }
  377|      1|    return false;
  378|      1|}
glTF2Importer.cpp:_ZN10glTFCommonL10ReadMemberIN5glTF211SamplerWrapEEEbRN9rapidjson12GenericValueINS3_4UTF8IcEENS3_19MemoryPoolAllocatorINS3_12CrtAllocatorEEEEEPKcRT_:
  369|      2|inline static bool ReadMember(Value &obj, const char *id, T &out) {
  370|      2|    if (!obj.IsObject()) {
  ------------------
  |  Branch (370:9): [True: 0, False: 2]
  ------------------
  371|      0|        return false;
  372|      0|    }
  373|      2|    Value::MemberIterator it = obj.FindMember(id);
  374|      2|    if (it != obj.MemberEnd()) {
  ------------------
  |  Branch (374:9): [True: 0, False: 2]
  ------------------
  375|      0|        return ReadHelper<T>::Read(it->value, out);
  376|      0|    }
  377|      2|    return false;
  378|      2|}
glTF2Importer.cpp:_ZN10glTFCommonL10ReadMemberIfEEbRN9rapidjson12GenericValueINS1_4UTF8IcEENS1_19MemoryPoolAllocatorINS1_12CrtAllocatorEEEEEPKcRT_:
  369|     15|inline static bool ReadMember(Value &obj, const char *id, T &out) {
  370|     15|    if (!obj.IsObject()) {
  ------------------
  |  Branch (370:9): [True: 0, False: 15]
  ------------------
  371|      0|        return false;
  372|      0|    }
  373|     15|    Value::MemberIterator it = obj.FindMember(id);
  374|     15|    if (it != obj.MemberEnd()) {
  ------------------
  |  Branch (374:9): [True: 5, False: 10]
  ------------------
  375|      5|        return ReadHelper<T>::Read(it->value, out);
  376|      5|    }
  377|     10|    return false;
  378|     15|}
glTF2Importer.cpp:_ZN10glTFCommonL10ReadMemberIA3_fEEbRN9rapidjson12GenericValueINS2_4UTF8IcEENS2_19MemoryPoolAllocatorINS2_12CrtAllocatorEEEEEPKcRT_:
  369|      5|inline static bool ReadMember(Value &obj, const char *id, T &out) {
  370|      5|    if (!obj.IsObject()) {
  ------------------
  |  Branch (370:9): [True: 0, False: 5]
  ------------------
  371|      0|        return false;
  372|      0|    }
  373|      5|    Value::MemberIterator it = obj.FindMember(id);
  374|      5|    if (it != obj.MemberEnd()) {
  ------------------
  |  Branch (374:9): [True: 0, False: 5]
  ------------------
  375|      0|        return ReadHelper<T>::Read(it->value, out);
  376|      0|    }
  377|      5|    return false;
  378|      5|}
glTF2Importer.cpp:_ZN10glTFCommonL10ReadMemberIbEEbRN9rapidjson12GenericValueINS1_4UTF8IcEENS1_19MemoryPoolAllocatorINS1_12CrtAllocatorEEEEEPKcRT_:
  369|      5|inline static bool ReadMember(Value &obj, const char *id, T &out) {
  370|      5|    if (!obj.IsObject()) {
  ------------------
  |  Branch (370:9): [True: 0, False: 5]
  ------------------
  371|      0|        return false;
  372|      0|    }
  373|      5|    Value::MemberIterator it = obj.FindMember(id);
  374|      5|    if (it != obj.MemberEnd()) {
  ------------------
  |  Branch (374:9): [True: 5, False: 0]
  ------------------
  375|      5|        return ReadHelper<T>::Read(it->value, out);
  376|      5|    }
  377|      0|    return false;
  378|      5|}

_ZN6Assimp6Base646DecodeEPKcmRPh:
  122|      8|size_t Decode(const char *in, size_t inLength, uint8_t *&out) {
  123|      8|    if (in == nullptr) {
  ------------------
  |  Branch (123:9): [True: 0, False: 8]
  ------------------
  124|      0|        out = nullptr;
  125|      0|        return 0;
  126|      0|    }
  127|       |
  128|      8|    if (inLength % 4 != 0) {
  ------------------
  |  Branch (128:9): [True: 1, False: 7]
  ------------------
  129|      1|        throw DeadlyImportError("Invalid base64 encoded data: \"", std::string(in, std::min(size_t(32), inLength)),
  130|      1|            "\", length:", inLength);
  131|      1|    }
  132|       |
  133|      7|    if (inLength < 4) {
  ------------------
  |  Branch (133:9): [True: 0, False: 7]
  ------------------
  134|      0|        out = nullptr;
  135|      0|        return 0;
  136|      0|    }
  137|       |
  138|      7|    int nEquals = int(in[inLength - 1] == '=') +
  139|      7|                  int(in[inLength - 2] == '=');
  140|       |
  141|      7|    size_t outLength = (inLength * 3) / 4 - nEquals;
  142|      7|    out = new uint8_t[outLength];
  143|      7|    memset(out, 0, outLength);
  144|       |
  145|      7|    size_t i, j = 0;
  146|       |
  147|  18.1k|    for (i = 0; i + 4 < inLength; i += 4) {
  ------------------
  |  Branch (147:17): [True: 18.1k, False: 7]
  ------------------
  148|  18.1k|        uint8_t b0 = DecodeChar(in[i]);
  149|  18.1k|        uint8_t b1 = DecodeChar(in[i + 1]);
  150|  18.1k|        uint8_t b2 = DecodeChar(in[i + 2]);
  151|  18.1k|        uint8_t b3 = DecodeChar(in[i + 3]);
  152|       |
  153|  18.1k|        out[j++] = (uint8_t)((b0 << 2) | (b1 >> 4));
  154|  18.1k|        out[j++] = (uint8_t)((b1 << 4) | (b2 >> 2));
  155|  18.1k|        out[j++] = (uint8_t)((b2 << 6) | b3);
  156|  18.1k|    }
  157|       |
  158|      7|    {
  159|      7|        uint8_t b0 = DecodeChar(in[i]);
  160|      7|        uint8_t b1 = DecodeChar(in[i + 1]);
  161|      7|        uint8_t b2 = DecodeChar(in[i + 2]);
  162|      7|        uint8_t b3 = DecodeChar(in[i + 3]);
  163|       |
  164|      7|        out[j++] = (uint8_t)((b0 << 2) | (b1 >> 4));
  165|      7|        if (b2 < 64) out[j++] = (uint8_t)((b1 << 4) | (b2 >> 2));
  ------------------
  |  Branch (165:13): [True: 5, False: 2]
  ------------------
  166|      7|        if (b3 < 64) out[j++] = (uint8_t)((b2 << 6) | b3);
  ------------------
  |  Branch (166:13): [True: 5, False: 2]
  ------------------
  167|      7|    }
  168|       |
  169|      7|    return outLength;
  170|      7|}
_ZN6Assimp6Base6410DecodeCharEc:
   66|  72.4k|inline uint8_t DecodeChar(char c) {
   67|  72.4k|    if (c & 0x80) {
  ------------------
  |  Branch (67:9): [True: 0, False: 72.4k]
  ------------------
   68|      0|        throw DeadlyImportError("Invalid base64 char value: ", size_t(c));
   69|      0|    }
   70|  72.4k|    return tableDecodeBase64[size_t(c & 0x7F)]; // TODO faster with lookup table or ifs?
   71|  72.4k|}

_ZN6Assimp12BaseImporterC2Ev:
   92|  29.9k|        : m_progress() {
   93|       |    // empty
   94|  29.9k|}
_ZN6Assimp12BaseImporter19UpdateImporterScaleEPNS_8ImporterE:
   96|    290|void BaseImporter::UpdateImporterScale(Importer *pImp) {
   97|    290|    ai_assert(pImp != nullptr);
   98|    290|    ai_assert(importerScale != 0.0);
   99|    290|    ai_assert(fileScale != 0.0);
  100|       |
  101|    290|    double activeScale = importerScale * fileScale;
  102|       |
  103|       |    // Set active scaling
  104|    290|    pImp->SetPropertyFloat(AI_CONFIG_APP_SCALE_KEY, static_cast<float>(activeScale));
  105|       |
  106|       |    ASSIMP_LOG_DEBUG("UpdateImporterScale scale set: ", activeScale);
  107|    290|}
_ZN6Assimp12BaseImporter8ReadFileEPNS_8ImporterERKNSt3__112basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEEPNS_8IOSystemE:
  111|    582|aiScene *BaseImporter::ReadFile(Importer *pImp, const std::string &pFile, IOSystem *pIOHandler) {
  112|       |
  113|    582|    m_progress = pImp->GetProgressHandler();
  114|    582|    if (nullptr == m_progress) {
  ------------------
  |  Branch (114:9): [True: 0, False: 582]
  ------------------
  115|      0|        return nullptr;
  116|      0|    }
  117|       |
  118|    582|    ai_assert(m_progress);
  119|       |
  120|       |    // Gather configuration properties for this run
  121|    582|    SetupProperties(pImp);
  122|       |
  123|       |    // Construct a file system filter to improve our success ratio at reading external files
  124|    582|    FileSystemFilter filter(pFile, pIOHandler);
  125|       |
  126|       |    // create a scene object to hold the data
  127|    582|    std::unique_ptr<aiScene> sc(new aiScene());
  128|       |
  129|       |    // dispatch importing
  130|    582|    try {
  131|    582|        InternReadFile(pFile, sc.get(), &filter);
  132|       |
  133|       |        // Calculate import scale hook - required because pImp not available anywhere else
  134|       |        // passes scale into ScaleProcess
  135|    582|        UpdateImporterScale(pImp);
  136|       |
  137|    582|    } catch( const std::exception &err ) {
  138|       |        // extract error description
  139|    292|        m_ErrorText = err.what();
  140|    292|        ASSIMP_LOG_ERROR(err.what());
  141|    292|        m_Exception = std::current_exception();
  142|    292|        return nullptr;
  143|    292|    }
  144|       |
  145|       |    // return what we gathered from the import.
  146|    290|    return sc.release();
  147|    582|}
_ZN6Assimp12BaseImporter15SetupPropertiesEPKNS_8ImporterE:
  150|    202|void BaseImporter::SetupProperties(const Importer *) {
  151|       |    // the default implementation does nothing
  152|    202|}
_ZN6Assimp12BaseImporter16GetExtensionListERNSt3__13setINS1_12basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEENS1_4lessIS8_EENS6_IS8_EEEE:
  155|  30.4k|void BaseImporter::GetExtensionList(std::set<std::string> &extensions) {
  156|  30.4k|    const aiImporterDesc *desc = GetInfo();
  157|  30.4k|    ai_assert(desc != nullptr);
  158|       |
  159|  30.4k|    const char *ext = desc->mFileExtensions;
  160|  30.4k|    ai_assert(ext != nullptr);
  161|       |
  162|  30.4k|    const char *last = ext;
  163|   212k|    do {
  164|   212k|        if (!*ext || *ext == ' ') {
  ------------------
  |  Branch (164:13): [True: 30.4k, False: 181k]
  |  Branch (164:22): [True: 17.1k, False: 164k]
  ------------------
  165|  47.5k|            extensions.insert(std::string(last, ext - last));
  166|  47.5k|            ai_assert(ext - last > 0);
  167|  47.5k|            last = ext;
  168|  64.6k|            while (*last == ' ') {
  ------------------
  |  Branch (168:20): [True: 17.1k, False: 47.5k]
  ------------------
  169|  17.1k|                ++last;
  170|  17.1k|            }
  171|  47.5k|        }
  172|   212k|    } while (*ext++);
  ------------------
  |  Branch (172:14): [True: 181k, False: 30.4k]
  ------------------
  173|  30.4k|}
_ZN6Assimp12BaseImporter24SearchFileHeaderForTokenEPNS_8IOSystemERKNSt3__112basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEEPPKcmjbb:
  182|  6.37k|        bool noGraphBeforeTokens /* false */) {
  183|  6.37k|    ai_assert(nullptr != tokens);
  184|  6.37k|    ai_assert(0 != numTokens);
  185|  6.37k|    ai_assert(0 != searchBytes);
  186|       |
  187|  6.37k|    if (nullptr == pIOHandler) {
  ------------------
  |  Branch (187:9): [True: 0, False: 6.37k]
  ------------------
  188|      0|        return false;
  189|      0|    }
  190|       |
  191|  6.37k|    std::unique_ptr<IOStream> pStream(pIOHandler->Open(pFile));
  192|  6.37k|    if (pStream) {
  ------------------
  |  Branch (192:9): [True: 6.37k, False: 0]
  ------------------
  193|       |        // read 200 characters from the file
  194|  6.37k|        std::unique_ptr<char[]> _buffer(new char[searchBytes + 1 /* for the '\0' */]);
  195|  6.37k|        char *buffer(_buffer.get());
  196|  6.37k|        const size_t read(pStream->Read(buffer, 1, searchBytes));
  197|  6.37k|        if (0 == read) {
  ------------------
  |  Branch (197:13): [True: 0, False: 6.37k]
  ------------------
  198|      0|            return false;
  199|      0|        }
  200|       |
  201|  1.13M|        for (size_t i = 0; i < read; ++i) {
  ------------------
  |  Branch (201:28): [True: 1.13M, False: 6.37k]
  ------------------
  202|  1.13M|            buffer[i] = static_cast<char>(::tolower((unsigned char)buffer[i]));
  203|  1.13M|        }
  204|       |
  205|       |        // It is not a proper handling of unicode files here ...
  206|       |        // ehm ... but it works in most cases.
  207|  6.37k|        char *cur = buffer, *cur2 = buffer, *end = &buffer[read];
  208|  1.13M|        while (cur != end) {
  ------------------
  |  Branch (208:16): [True: 1.13M, False: 6.37k]
  ------------------
  209|  1.13M|            if (*cur) {
  ------------------
  |  Branch (209:17): [True: 968k, False: 162k]
  ------------------
  210|   968k|                *cur2++ = *cur;
  211|   968k|            }
  212|  1.13M|            ++cur;
  213|  1.13M|        }
  214|  6.37k|        *cur2 = '\0';
  215|       |
  216|  6.37k|        std::string token;
  217|  18.7k|        for (unsigned int i = 0; i < numTokens; ++i) {
  ------------------
  |  Branch (217:34): [True: 12.6k, False: 6.10k]
  ------------------
  218|  12.6k|            ai_assert(nullptr != tokens[i]);
  219|  12.6k|            const size_t len(strlen(tokens[i]));
  220|  12.6k|            token.clear();
  221|  12.6k|            const char *ptr(tokens[i]);
  222|  88.3k|            for (size_t tokIdx = 0; tokIdx < len; ++tokIdx) {
  ------------------
  |  Branch (222:37): [True: 75.7k, False: 12.6k]
  ------------------
  223|  75.7k|                token.push_back(static_cast<char>(tolower(static_cast<unsigned char>(*ptr))));
  224|  75.7k|                ++ptr;
  225|  75.7k|            }
  226|  12.6k|            const char *r = strstr(buffer, token.c_str());
  227|  12.6k|            if (!r) {
  ------------------
  |  Branch (227:17): [True: 12.2k, False: 358]
  ------------------
  228|  12.2k|                continue;
  229|  12.2k|            }
  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|    358|            if (noGraphBeforeTokens && (r != buffer && isgraph(static_cast<unsigned char>(r[-1])))) {
  ------------------
  |  Branch (233:17): [True: 163, False: 195]
  |  Branch (233:41): [True: 158, False: 5]
  |  Branch (233:56): [True: 89, False: 69]
  ------------------
  234|     89|                continue;
  235|     89|            }
  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|    269|            if (!tokensSol || r == buffer || r[-1] == '\r' || r[-1] == '\n') {
  ------------------
  |  Branch (238:17): [True: 269, False: 0]
  |  Branch (238:31): [True: 0, False: 0]
  |  Branch (238:46): [True: 0, False: 0]
  |  Branch (238:63): [True: 0, False: 0]
  ------------------
  239|    269|                ASSIMP_LOG_DEBUG("Found positive match for header keyword: ", tokens[i]);
  240|    269|                return true;
  241|    269|            }
  242|    269|        }
  243|  6.37k|    }
  244|       |
  245|  6.10k|    return false;
  246|  6.37k|}
_ZN6Assimp12BaseImporter20SimpleExtensionCheckERKNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEPKcSB_SB_SB_:
  254|  1.75k|        const char *ext3) {
  255|  1.75k|    std::set<std::string> extensions;
  256|  7.02k|    for (const char* ext : {ext0, ext1, ext2, ext3}) {
  ------------------
  |  Branch (256:26): [True: 7.02k, False: 1.75k]
  ------------------
  257|  7.02k|        if (ext == nullptr) continue;
  ------------------
  |  Branch (257:13): [True: 4.21k, False: 2.80k]
  ------------------
  258|  2.80k|        extensions.emplace(ext);
  259|  2.80k|    }
  260|  1.75k|    return HasExtension(pFile, extensions);
  261|  1.75k|}
_ZN6Assimp12BaseImporter12HasExtensionERKNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEERKNS1_3setIS7_NS1_4lessIS7_EENS5_IS7_EEEE:
  265|  32.1k|/*static*/ bool BaseImporter::HasExtension(const std::string &pFile, const std::set<std::string> &extensions) {
  266|  32.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|  50.3k|    for (const std::string& ext : extensions) {
  ------------------
  |  Branch (271:33): [True: 50.3k, False: 32.1k]
  ------------------
  272|       |        // Yay for C++<20 not having std::string::ends_with()
  273|  50.3k|        const std::string dotExt = "." + ext;
  274|  50.3k|        if (dotExt.length() > file.length()) continue;
  ------------------
  |  Branch (274:13): [True: 0, False: 50.3k]
  ------------------
  275|       |        // Possible optimization: Fetch the lowercase filename!
  276|  50.3k|        if (0 == ASSIMP_stricmp(file.c_str() + file.length() - dotExt.length(), dotExt.c_str())) {
  ------------------
  |  Branch (276:13): [True: 62, False: 50.2k]
  ------------------
  277|     62|            return true;
  278|     62|        }
  279|  50.3k|    }
  280|  32.1k|    return false;
  281|  32.1k|}
_ZN6Assimp12BaseImporter12GetExtensionERKNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEE:
  285|    398|std::string BaseImporter::GetExtension(const std::string &pFile) {
  286|    398|    const std::string file = StripVersionHash(pFile);
  287|    398|    std::string::size_type pos = file.find_last_of('.');
  288|       |
  289|       |    // no file extension at all
  290|    398|    if (pos == std::string::npos) {
  ------------------
  |  Branch (290:9): [True: 8, False: 390]
  ------------------
  291|      8|        return std::string();
  292|      8|    }
  293|       |
  294|       |    // thanks to Andy Maloney for the hint
  295|    390|    std::string ret = file.substr(pos + 1);
  296|    390|    ret = ai_tolower(ret);
  297|       |
  298|    390|    return ret;
  299|    398|}
_ZN6Assimp12BaseImporter15CheckMagicTokenEPNS_8IOSystemERKNSt3__112basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEEPKvmjj:
  305|  4.41k|        const void *_magic, std::size_t num, unsigned int offset, unsigned int size) {
  306|  4.41k|    ai_assert(size <= 16);
  307|  4.41k|    ai_assert(_magic);
  308|       |
  309|  4.41k|    if (!pIOHandler) {
  ------------------
  |  Branch (309:9): [True: 0, False: 4.41k]
  ------------------
  310|      0|        return false;
  311|      0|    }
  312|  4.41k|    const char *magic = reinterpret_cast<const char *>(_magic);
  313|  4.41k|    std::unique_ptr<IOStream> pStream(pIOHandler->Open(pFile));
  314|  4.41k|    if (pStream) {
  ------------------
  |  Branch (314:9): [True: 4.41k, False: 0]
  ------------------
  315|       |
  316|       |        // skip to offset
  317|  4.41k|        pStream->Seek(offset, aiOrigin_SET);
  318|       |
  319|       |        // read 'size' characters from the file
  320|  4.41k|        union {
  321|  4.41k|            char data[16];
  322|  4.41k|            uint16_t data_u16[8];
  323|  4.41k|            uint32_t data_u32[4];
  324|  4.41k|        };
  325|  4.41k|        if (size != pStream->Read(data, 1, size)) {
  ------------------
  |  Branch (325:13): [True: 0, False: 4.41k]
  ------------------
  326|      0|            return false;
  327|      0|        }
  328|       |
  329|  14.1k|        for (unsigned int i = 0; i < num; ++i) {
  ------------------
  |  Branch (329:34): [True: 9.96k, False: 4.20k]
  ------------------
  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|  9.96k|            if (2 == size) {
  ------------------
  |  Branch (333:17): [True: 957, False: 9.01k]
  ------------------
  334|    957|                uint16_t magic_u16;
  335|    957|                memcpy(&magic_u16, magic, 2);
  336|    957|                if (data_u16[0] == magic_u16 || data_u16[0] == ByteSwap::Swapped(magic_u16)) {
  ------------------
  |  Branch (336:21): [True: 9, False: 948]
  |  Branch (336:49): [True: 0, False: 948]
  ------------------
  337|      9|                    return true;
  338|      9|                }
  339|  9.01k|            } else if (4 == size) {
  ------------------
  |  Branch (339:24): [True: 9.01k, False: 0]
  ------------------
  340|  9.01k|                uint32_t magic_u32;
  341|  9.01k|                memcpy(&magic_u32, magic, 4);
  342|  9.01k|                if (data_u32[0] == magic_u32 || data_u32[0] == ByteSwap::Swapped(magic_u32)) {
  ------------------
  |  Branch (342:21): [True: 15, False: 8.99k]
  |  Branch (342:49): [True: 187, False: 8.80k]
  ------------------
  343|    202|                    return true;
  344|    202|                }
  345|  9.01k|            } else {
  346|       |                // any length ... just compare
  347|      0|                if (!memcmp(magic, data, size)) {
  ------------------
  |  Branch (347:21): [True: 0, False: 0]
  ------------------
  348|      0|                    return true;
  349|      0|                }
  350|      0|            }
  351|  9.75k|            magic += size;
  352|  9.75k|        }
  353|  4.41k|    }
  354|  4.20k|    return false;
  355|  4.41k|}
_ZN6Assimp12BaseImporter13ConvertToUTF8ERNSt3__16vectorIcNS1_9allocatorIcEEEE:
  361|  8.00k|void BaseImporter::ConvertToUTF8(std::vector<char> &data) {
  362|       |    //ConversionResult result;
  363|  8.00k|    if (data.size() < 8) {
  ------------------
  |  Branch (363:9): [True: 0, False: 8.00k]
  ------------------
  364|      0|        throw DeadlyImportError("File is too small");
  365|      0|    }
  366|       |
  367|       |    // UTF 8 with BOM
  368|  8.00k|    if ((uint8_t)data[0] == 0xEF && (uint8_t)data[1] == 0xBB && (uint8_t)data[2] == 0xBF) {
  ------------------
  |  Branch (368:9): [True: 0, False: 8.00k]
  |  Branch (368:37): [True: 0, False: 0]
  |  Branch (368:65): [True: 0, False: 0]
  ------------------
  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|  8.00k|    if (*((uint32_t *)&data.front()) == 0xFFFE0000) {
  ------------------
  |  Branch (377:9): [True: 0, False: 8.00k]
  ------------------
  378|      0|        if (data.size() % sizeof(uint32_t) != 0) {
  ------------------
  |  Branch (378:13): [True: 0, False: 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) {
  ------------------
  |  Branch (383:88): [True: 0, False: 0]
  ------------------
  384|      0|            AI_SWAP4P(p);
  385|      0|        }
  386|      0|    }
  387|       |
  388|       |    // UTF 32 LE with BOM
  389|  8.00k|    if (*((uint32_t *)&data.front()) == 0x0000FFFE) {
  ------------------
  |  Branch (389:9): [True: 0, False: 8.00k]
  ------------------
  390|      0|        if (data.size() % sizeof(uint32_t) != 0) {
  ------------------
  |  Branch (390:13): [True: 0, False: 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|  8.00k|    if (*((uint16_t *)&data.front()) == 0xFFFE) {
  ------------------
  |  Branch (403:9): [True: 1, False: 8.00k]
  ------------------
  404|       |        // Check to ensure no overflow can happen
  405|      1|        if (data.size() % sizeof(uint16_t) != 0) {
  ------------------
  |  Branch (405:13): [True: 0, False: 1]
  ------------------
  406|      0|            throw DeadlyImportError("Not valid UTF-16 BE");
  407|      0|        }
  408|       |        // swap the endianness ..
  409|  8.92k|        for (uint16_t *p = (uint16_t *)&data.front(), *end = (uint16_t *)&data.back(); p <= end; ++p) {
  ------------------
  |  Branch (409:88): [True: 8.92k, False: 1]
  ------------------
  410|  8.92k|            ByteSwap::Swap2(p);
  411|  8.92k|        }
  412|      1|    }
  413|       |
  414|       |    // UTF 16 LE with BOM
  415|  8.00k|    if (*((uint16_t *)&data.front()) == 0xFEFF) {
  ------------------
  |  Branch (415:9): [True: 1, False: 8.00k]
  ------------------
  416|      1|        if (data.size() % sizeof(uint16_t) != 0) {
  ------------------
  |  Branch (416:13): [True: 0, False: 1]
  ------------------
  417|      0|            throw DeadlyImportError("Not valid UTF-16 LE");
  418|      0|        }
  419|      1|        ASSIMP_LOG_DEBUG("Found UTF-16 BOM ...");
  420|       |
  421|      1|        std::vector<unsigned char> output;
  422|      1|        utf8::utf16to8(data.begin(), data.end(), back_inserter(output));
  423|      1|        return;
  424|      1|    }
  425|  8.00k|}
_ZN6Assimp12BaseImporter16TextFileToBufferEPNS_8IOStreamERNSt3__16vectorIcNS3_9allocatorIcEEEENS0_12TextFileModeE:
  465|  7.98k|        TextFileMode mode) {
  466|  7.98k|    ai_assert(nullptr != stream);
  467|       |
  468|  7.98k|    const size_t fileSize = stream->FileSize();
  469|  7.98k|    if (mode == FORBID_EMPTY) {
  ------------------
  |  Branch (469:9): [True: 5.37k, False: 2.60k]
  ------------------
  470|  5.37k|        if (!fileSize) {
  ------------------
  |  Branch (470:13): [True: 0, False: 5.37k]
  ------------------
  471|      0|            throw DeadlyImportError("File is empty");
  472|      0|        }
  473|  5.37k|    }
  474|       |
  475|  7.98k|    data.reserve(fileSize + 1);
  476|  7.98k|    data.resize(fileSize);
  477|  7.98k|    if (fileSize > 0) {
  ------------------
  |  Branch (477:9): [True: 7.98k, False: 0]
  ------------------
  478|  7.98k|        if (fileSize != stream->Read(&data[0], 1, fileSize)) {
  ------------------
  |  Branch (478:13): [True: 0, False: 7.98k]
  ------------------
  479|      0|            throw DeadlyImportError("File read error");
  480|      0|        }
  481|       |
  482|  7.98k|        ConvertToUTF8(data);
  483|  7.98k|    }
  484|       |
  485|       |    // append a binary zero to simplify string parsing
  486|  7.98k|    data.push_back(0);
  487|  7.98k|}
_ZN6Assimp11BatchLoaderC2EPNS_8IOSystemEb:
  557|    155|BatchLoader::BatchLoader(IOSystem *pIO, bool validate) {
  558|    155|    ai_assert(nullptr != pIO);
  559|       |
  560|    155|    m_data = new BatchData(pIO, validate);
  561|    155|}
_ZN6Assimp11BatchLoaderD2Ev:
  564|    155|BatchLoader::~BatchLoader() {
  565|       |    // delete all scenes what have not been polled by the user
  566|  1.23k|    for (LoadReqIt it = m_data->requests.begin(); it != m_data->requests.end(); ++it) {
  ------------------
  |  Branch (566:51): [True: 1.08k, False: 155]
  ------------------
  567|  1.08k|        delete (*it).scene;
  568|  1.08k|    }
  569|    155|    delete m_data;
  570|    155|}
_ZN6Assimp11BatchLoader14AddLoadRequestERKNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEjPKNS0_11PropertyMapE:
  584|  17.6k|        unsigned int steps /*= 0*/, const PropertyMap *map /*= nullptr*/) {
  585|  17.6k|    ai_assert(!file.empty());
  586|       |
  587|       |    // check whether we have this loading request already
  588|   113k|    for (LoadReqIt it = m_data->requests.begin(); it != m_data->requests.end(); ++it) {
  ------------------
  |  Branch (588:51): [True: 111k, False: 1.51k]
  ------------------
  589|       |        // Call IOSystem's path comparison function here
  590|   111k|        if (m_data->pIOSystem->ComparePaths((*it).file, file)) {
  ------------------
  |  Branch (590:13): [True: 16.1k, False: 95.4k]
  ------------------
  591|  16.1k|            if (map) {
  ------------------
  |  Branch (591:17): [True: 4.35k, False: 11.8k]
  ------------------
  592|  4.35k|                if (!((*it).map == *map)) {
  ------------------
  |  Branch (592:21): [True: 5, False: 4.35k]
  ------------------
  593|      5|                    continue;
  594|      5|                }
  595|  11.8k|            } else if (!(*it).map.empty()) {
  ------------------
  |  Branch (595:24): [True: 0, False: 11.8k]
  ------------------
  596|      0|                continue;
  597|      0|            }
  598|       |
  599|  16.1k|            (*it).refCnt++;
  600|  16.1k|            return (*it).id;
  601|  16.1k|        }
  602|   111k|    }
  603|       |
  604|       |    // no, we don't have it. So add it to the queue ...
  605|  1.51k|    m_data->requests.emplace_back(file, steps, map, m_data->next_id);
  606|  1.51k|    return m_data->next_id++;
  607|  17.6k|}
_ZN6Assimp11BatchLoader9GetImportEj:
  610|  11.0k|aiScene *BatchLoader::GetImport(unsigned int which) {
  611|  26.4k|    for (LoadReqIt it = m_data->requests.begin(); it != m_data->requests.end(); ++it) {
  ------------------
  |  Branch (611:51): [True: 26.4k, False: 0]
  ------------------
  612|  26.4k|        if ((*it).id == which && (*it).loaded) {
  ------------------
  |  Branch (612:13): [True: 11.0k, False: 15.4k]
  |  Branch (612:34): [True: 11.0k, False: 0]
  ------------------
  613|  11.0k|            aiScene *sc = (*it).scene;
  614|  11.0k|            if (!(--(*it).refCnt)) {
  ------------------
  |  Branch (614:17): [True: 435, False: 10.6k]
  ------------------
  615|    435|                m_data->requests.erase(it);
  616|    435|            }
  617|  11.0k|            return sc;
  618|  11.0k|        }
  619|  26.4k|    }
  620|      0|    return nullptr;
  621|  11.0k|}
_ZN6Assimp11BatchLoader7LoadAllEv:
  624|     50|void BatchLoader::LoadAll() {
  625|       |    // no threaded implementation for the moment
  626|    490|    for (LoadReqIt it = m_data->requests.begin(); it != m_data->requests.end(); ++it) {
  ------------------
  |  Branch (626:51): [True: 440, False: 50]
  ------------------
  627|       |        // force validation in debug builds
  628|    440|        unsigned int pp = (*it).flags;
  629|    440|        if (m_data->validate) {
  ------------------
  |  Branch (629:13): [True: 0, False: 440]
  ------------------
  630|      0|            pp |= aiProcess_ValidateDataStructure;
  631|      0|        }
  632|       |
  633|       |        // setup config properties if necessary
  634|    440|        ImporterPimpl *pimpl = m_data->pImporter->Pimpl();
  635|    440|        pimpl->mFloatProperties = (*it).map.floats;
  636|    440|        pimpl->mIntProperties = (*it).map.ints;
  637|    440|        pimpl->mStringProperties = (*it).map.strings;
  638|    440|        pimpl->mMatrixProperties = (*it).map.matrices;
  639|       |
  640|    440|        if (!DefaultLogger::isNullLogger()) {
  ------------------
  |  Branch (640:13): [True: 0, False: 440]
  ------------------
  641|      0|            ASSIMP_LOG_INFO("%%% BEGIN EXTERNAL FILE %%%");
  642|      0|            ASSIMP_LOG_INFO("File: ", (*it).file);
  643|      0|        }
  644|    440|        m_data->pImporter->ReadFile((*it).file, pp);
  645|    440|        (*it).scene = m_data->pImporter->GetOrphanedScene();
  646|    440|        (*it).loaded = true;
  647|       |
  648|       |        ASSIMP_LOG_INFO("%%% END EXTERNAL FILE %%%");
  649|    440|    }
  650|     50|}
BaseImporter.cpp:_ZN12_GLOBAL__N_116StripVersionHashERKNSt3__112basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEE:
   75|  32.5k|std::string StripVersionHash(const std::string &filename) {
   76|  32.5k|    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|  32.5k|    if (pos != std::string::npos && pos > filename.find_last_of('.') &&
  ------------------
  |  Branch (79:9): [True: 351, False: 32.2k]
  |  Branch (79:9): [True: 0, False: 32.5k]
  |  Branch (79:37): [True: 106, False: 245]
  ------------------
   80|    106|        IsGcsVersion(filename.substr(pos + 1))) {
  ------------------
  |  Branch (80:9): [True: 0, False: 106]
  ------------------
   81|      0|        return filename.substr(0, pos);
   82|      0|    }
   83|  32.5k|    return filename;
   84|  32.5k|}
BaseImporter.cpp:_ZN12_GLOBAL__N_112IsGcsVersionERKNSt3__112basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEE:
   64|    106|bool IsGcsVersion(const std::string &s) {
   65|    106|    if (s.empty()) return false;
  ------------------
  |  Branch (65:9): [True: 0, False: 106]
  ------------------
   66|    106|    return std::all_of(s.cbegin(), s.cend(), [](const char c) {
   67|       |        // gcs only permits numeric characters.
   68|    106|        return std::isdigit(static_cast<int>(c));
   69|    106|    });
   70|    106|}
BaseImporter.cpp:_ZZN12_GLOBAL__N_112IsGcsVersionERKNSt3__112basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEEENK3$_0clEc:
   66|    106|    return std::all_of(s.cbegin(), s.cend(), [](const char c) {
   67|       |        // gcs only permits numeric characters.
   68|    106|        return std::isdigit(static_cast<int>(c));
   69|    106|    });
_ZN6Assimp9BatchDataC2EPNS_8IOSystemEb:
  523|    155|            pIOSystem(pIO), pImporter(nullptr), next_id(0xffff), validate(validate) {
  524|    155|        ai_assert(nullptr != pIO);
  525|       |
  526|    155|        pImporter = new Importer();
  527|    155|        pImporter->SetIOHandler(pIO);
  528|    155|    }
_ZN6Assimp9BatchDataD2Ev:
  530|    155|    ~BatchData() {
  531|    155|        pImporter->SetIOHandler(nullptr); /* get pointer back into our possession */
  532|    155|        delete pImporter;
  533|    155|    }
_ZN6Assimp11LoadRequestC2ERKNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEjPKNS_11BatchLoader11PropertyMapEj:
  494|  1.51k|            file(_file),
  495|  1.51k|            flags(_flags),
  496|  1.51k|            refCnt(1),
  497|  1.51k|            scene(nullptr),
  498|  1.51k|            loaded(false),
  499|  1.51k|            id(_id) {
  500|  1.51k|        if (_map) {
  ------------------
  |  Branch (500:13): [True: 704, False: 815]
  ------------------
  501|    704|            map = *_map;
  502|    704|        }
  503|  1.51k|    }

_ZN6Assimp11BaseProcessC2Ev:
   56|  27.8k|          progress() {
   57|       |    // empty
   58|  27.8k|}
_ZN6Assimp11BaseProcess14ExecuteOnSceneEPNS_8ImporterE:
   61|  3.43k|void BaseProcess::ExecuteOnScene(Importer *pImp) {
   62|  3.43k|    ai_assert( nullptr != pImp );
   63|  3.43k|    if (pImp == nullptr) {
  ------------------
  |  Branch (63:9): [True: 0, False: 3.43k]
  ------------------
   64|      0|        return;
   65|      0|    }
   66|       |
   67|  3.43k|    ai_assert(nullptr != pImp->Pimpl()->mScene);
   68|  3.43k|    if (pImp->Pimpl()->mScene == nullptr) {
  ------------------
  |  Branch (68:9): [True: 0, False: 3.43k]
  ------------------
   69|      0|        return;
   70|      0|    }
   71|       |
   72|  3.43k|    progress = pImp->GetProgressHandler();
   73|  3.43k|    ai_assert(nullptr != progress);
   74|  3.43k|    if (progress == nullptr) {
  ------------------
  |  Branch (74:9): [True: 0, False: 3.43k]
  ------------------
   75|      0|        return;
   76|      0|    }
   77|       |
   78|  3.43k|    SetupProperties(pImp);
   79|       |
   80|       |    // catch exceptions thrown inside the PostProcess-Step
   81|  3.43k|    try {
   82|  3.43k|        Execute(pImp->Pimpl()->mScene);
   83|  3.43k|    } catch (const std::exception &err) {
   84|       |
   85|       |        // extract error description
   86|     58|        pImp->Pimpl()->mErrorString = err.what();
   87|     58|        ASSIMP_LOG_ERROR(pImp->Pimpl()->mErrorString);
   88|       |
   89|       |        // and kill the partially imported data
   90|     58|        delete pImp->Pimpl()->mScene;
   91|     58|        pImp->Pimpl()->mScene = nullptr;
   92|     58|    }
   93|  3.43k|}
_ZN6Assimp11BaseProcess15SetupPropertiesEPKNS_8ImporterE:
   96|  1.32k|void BaseProcess::SetupProperties(const Importer * /*pImp*/) {
   97|       |    // the default implementation does nothing
   98|  1.32k|}

_ZN6Assimp11BaseProcess13SetSharedDataEPNS_21SharedPostProcessInfoE:
  234|  20.5k|    inline void SetSharedData(SharedPostProcessInfo *sh) {
  235|  20.5k|        shared = sh;
  236|  20.5k|    }
_ZN6Assimp21SharedPostProcessInfoD2Ev:
   98|    624|    ~SharedPostProcessInfo() {
   99|    624|        Clean();
  100|    624|    }
_ZN6Assimp11BaseProcessD2Ev:
  186|  27.8k|    virtual ~BaseProcess() = default;
_ZN6Assimp21SharedPostProcessInfo5CleanEv:
  103|  1.37k|    void Clean() {
  104|       |        // invoke the virtual destructor for all stored properties
  105|  1.37k|        for (PropertyMap::iterator it = pmap.begin(), end = pmap.end();
  106|  1.37k|                it != end; ++it) {
  ------------------
  |  Branch (106:17): [True: 0, False: 1.37k]
  ------------------
  107|      0|            delete (*it).second;
  108|      0|        }
  109|  1.37k|        pmap.clear();
  110|  1.37k|    }
_ZN6Assimp21SharedPostProcessInfo14RemovePropertyEPKc:
  148|    208|    void RemoveProperty(const char *name) {
  149|    208|        SetGenericPropertyPtr<Base>(pmap, name, nullptr );
  150|    208|    }
_ZN6Assimp21SharedPostProcessInfo11AddPropertyEPKcPNS0_4BaseE:
  153|    208|    void AddProperty(const char *name, Base *data) {
  154|    208|        SetGenericPropertyPtr<Base>(pmap, name, data);
  155|    208|    }
_ZNK6Assimp21SharedPostProcessInfo19GetPropertyInternalEPKc:
  157|  2.47k|    Base *GetPropertyInternal(const char *name) const {
  158|  2.47k|        return GetGenericProperty<Base *>(pmap, name, nullptr );
  159|  2.47k|    }
_ZN6Assimp21SharedPostProcessInfo11AddPropertyINSt3__16vectorINS2_4pairINS_11SpatialSortEfEENS2_9allocatorIS6_EEEEEEvPKcPT_:
  114|    208|    void AddProperty(const char *name, T *in) {
  115|    208|        AddProperty(name, (Base *)new THeapData<T>(in));
  116|    208|    }
_ZN6Assimp21SharedPostProcessInfo9THeapDataINSt3__16vectorINS2_4pairINS_11SpatialSortEfEENS2_9allocatorIS6_EEEEEC2EPS9_:
   73|    208|                data(in) {}
_ZN6Assimp21SharedPostProcessInfo4BaseD2Ev:
   66|    208|        virtual ~Base() = default;
_ZN6Assimp21SharedPostProcessInfo9THeapDataINSt3__16vectorINS2_4pairINS_11SpatialSortEfEENS2_9allocatorIS6_EEEEED2Ev:
   75|    208|        ~THeapData() override {
   76|    208|            delete data;
   77|    208|        }
_ZNK6Assimp21SharedPostProcessInfo11GetPropertyINSt3__16vectorINS2_4pairINS_11SpatialSortEfEENS2_9allocatorIS6_EEEEEEbPKcRPT_:
  126|  2.47k|    bool GetProperty(const char *name, T *&out) const {
  127|  2.47k|        THeapData<T> *t = (THeapData<T> *)GetPropertyInternal(name);
  128|  2.47k|        if (!t) {
  ------------------
  |  Branch (128:13): [True: 0, False: 2.47k]
  ------------------
  129|      0|            out = nullptr;
  130|      0|            return false;
  131|      0|        }
  132|  2.47k|        out = t->data;
  133|  2.47k|        return true;
  134|  2.47k|    }

_ZN6Assimp11CompressionC2Ev:
   62|     18|        mImpl(new impl) {
   63|       |    // empty
   64|     18|}
_ZN6Assimp11CompressionD2Ev:
   66|     18|Compression::~Compression() {
   67|     18|    ai_assert(mImpl != nullptr);
  ------------------
  |  |   67|     18|#   define ai_assert(expression) (void)((!!(expression)) || (Assimp::aiAssertViolation(#expression, __FILE__, __LINE__), 0))
  |  |  ------------------
  |  |  |  Branch (67:41): [True: 18, False: 0]
  |  |  |  Branch (67:61): [True: 0, False: 0]
  |  |  ------------------
  ------------------
   68|       |
   69|     18|    if (mImpl->mOpen) {
  ------------------
  |  Branch (69:9): [True: 10, False: 8]
  ------------------
   70|     10|        close();
   71|     10|    }
   72|       |
   73|     18|    delete mImpl;
   74|     18|}
_ZN6Assimp11Compression4openENS0_6FormatENS0_9FlushModeEi:
   76|     18|bool Compression::open(Format format, FlushMode flush, int windowBits) {
   77|     18|    ai_assert(mImpl != nullptr);
  ------------------
  |  |   67|     18|#   define ai_assert(expression) (void)((!!(expression)) || (Assimp::aiAssertViolation(#expression, __FILE__, __LINE__), 0))
  |  |  ------------------
  |  |  |  Branch (67:41): [True: 18, False: 0]
  |  |  |  Branch (67:61): [True: 0, False: 0]
  |  |  ------------------
  ------------------
   78|       |
   79|     18|    if (mImpl->mOpen) {
  ------------------
  |  Branch (79:9): [True: 0, False: 18]
  ------------------
   80|      0|        return false;
   81|      0|    }
   82|       |
   83|       |    // build a zlib stream
   84|     18|    mImpl->mZSstream.opaque = Z_NULL;
  ------------------
  |  |  212|     18|#define Z_NULL  0  /* for initializing zalloc, zfree, opaque */
  ------------------
   85|     18|    mImpl->mZSstream.zalloc = Z_NULL;
  ------------------
  |  |  212|     18|#define Z_NULL  0  /* for initializing zalloc, zfree, opaque */
  ------------------
   86|     18|    mImpl->mZSstream.zfree = Z_NULL;
  ------------------
  |  |  212|     18|#define Z_NULL  0  /* for initializing zalloc, zfree, opaque */
  ------------------
   87|     18|    mImpl->mFlushMode = flush;
   88|     18|    if (format == Format::Binary) {
  ------------------
  |  Branch (88:9): [True: 18, False: 0]
  ------------------
   89|     18|        mImpl->mZSstream.data_type = Z_BINARY;
  ------------------
  |  |  203|     18|#define Z_BINARY   0
  ------------------
   90|     18|    } else {
   91|      0|        mImpl->mZSstream.data_type = Z_ASCII;
  ------------------
  |  |  205|      0|#define Z_ASCII    Z_TEXT   /* for compatibility with 1.2.2 and earlier */
  |  |  ------------------
  |  |  |  |  204|      0|#define Z_TEXT     1
  |  |  ------------------
  ------------------
   92|      0|    }
   93|       |
   94|       |    // raw decompression without a zlib or gzip header
   95|     18|    if (windowBits == 0) {
  ------------------
  |  Branch (95:9): [True: 0, False: 18]
  ------------------
   96|      0|        inflateInit(&mImpl->mZSstream);
  ------------------
  |  | 1813|      0|          inflateInit_((strm), ZLIB_VERSION, (int)sizeof(z_stream))
  |  |  ------------------
  |  |  |  |   40|      0|#define ZLIB_VERSION "1.2.13"
  |  |  ------------------
  ------------------
   97|     18|    } else {
   98|     18|        inflateInit2(&mImpl->mZSstream, windowBits);
  ------------------
  |  | 1818|     18|          inflateInit2_((strm), (windowBits), ZLIB_VERSION, \
  |  |  ------------------
  |  |  |  |   40|     18|#define ZLIB_VERSION "1.2.13"
  |  |  ------------------
  |  | 1819|     18|                        (int)sizeof(z_stream))
  ------------------
   99|     18|    }
  100|     18|    mImpl->mOpen = true;
  101|       |
  102|     18|    return mImpl->mOpen;
  103|     18|}
_ZN6Assimp11Compression10decompressEPKvmRNSt3__16vectorIcNS3_9allocatorIcEEEE:
  133|     18|size_t Compression::decompress(const void *data, size_t in, std::vector<char> &uncompressed) {
  134|     18|    ai_assert(mImpl != nullptr);
  ------------------
  |  |   67|     18|#   define ai_assert(expression) (void)((!!(expression)) || (Assimp::aiAssertViolation(#expression, __FILE__, __LINE__), 0))
  |  |  ------------------
  |  |  |  Branch (67:41): [True: 18, False: 0]
  |  |  |  Branch (67:61): [True: 0, False: 0]
  |  |  ------------------
  ------------------
  135|     18|    if (data == nullptr || in == 0) {
  ------------------
  |  Branch (135:9): [True: 0, False: 18]
  |  Branch (135:28): [True: 0, False: 18]
  ------------------
  136|      0|        return 0l;
  137|      0|    }
  138|       |
  139|     18|    mImpl->mZSstream.next_in = (Bytef*)(data);
  140|     18|    mImpl->mZSstream.avail_in = (uInt)in;
  141|       |
  142|     18|    int ret = 0;
  143|     18|    size_t total = 0l;
  144|     18|    const int flushMode = getFlushMode(mImpl->mFlushMode);
  145|     18|    if (flushMode == Z_FINISH) {
  ------------------
  |  |  172|     18|#define Z_FINISH        4
  ------------------
  |  Branch (145:9): [True: 0, False: 18]
  ------------------
  146|      0|        mImpl->mZSstream.avail_out = static_cast<uInt>(uncompressed.size());
  147|      0|        mImpl->mZSstream.next_out = reinterpret_cast<Bytef *>(&*uncompressed.begin());
  148|      0|        ret = inflate(&mImpl->mZSstream, Z_FINISH);
  ------------------
  |  |  172|      0|#define Z_FINISH        4
  ------------------
  149|       |
  150|      0|        if (ret != Z_STREAM_END && ret != Z_OK) {
  ------------------
  |  |  178|      0|#define Z_STREAM_END    1
  ------------------
                      if (ret != Z_STREAM_END && ret != Z_OK) {
  ------------------
  |  |  177|      0|#define Z_OK            0
  ------------------
  |  Branch (150:13): [True: 0, False: 0]
  |  Branch (150:36): [True: 0, False: 0]
  ------------------
  151|      0|            throw DeadlyImportError("Compression", "Failure decompressing this file using gzip.");
  152|      0|        }
  153|      0|        total = mImpl->mZSstream.avail_out;
  154|     18|    } else {
  155|  3.15k|        do {
  156|  3.15k|            Bytef block[MYBLOCK] = {};
  157|  3.15k|            mImpl->mZSstream.avail_out = MYBLOCK;
  158|  3.15k|            mImpl->mZSstream.next_out = block;
  159|       |
  160|  3.15k|            ret = inflate(&mImpl->mZSstream, flushMode);
  161|       |
  162|  3.15k|            if (ret != Z_STREAM_END && ret != Z_OK) {
  ------------------
  |  |  178|  6.31k|#define Z_STREAM_END    1
  ------------------
                          if (ret != Z_STREAM_END && ret != Z_OK) {
  ------------------
  |  |  177|  3.15k|#define Z_OK            0
  ------------------
  |  Branch (162:17): [True: 3.15k, False: 8]
  |  Branch (162:40): [True: 10, False: 3.14k]
  ------------------
  163|     10|                throw DeadlyImportError("Compression", "Failure decompressing this file using gzip.");
  164|     10|            }
  165|  3.14k|            const size_t have = MYBLOCK - mImpl->mZSstream.avail_out;
  166|  3.14k|            total += have;
  167|  3.14k|            uncompressed.resize(total);
  168|  3.14k|            ::memcpy(uncompressed.data() + total - have, block, have);
  169|  3.14k|        } while (ret != Z_STREAM_END);
  ------------------
  |  |  178|  3.14k|#define Z_STREAM_END    1
  ------------------
  |  Branch (169:18): [True: 3.14k, False: 8]
  ------------------
  170|     18|    }
  171|       |
  172|      8|    return total;
  173|     18|}
_ZN6Assimp11Compression5closeEv:
  205|     18|bool Compression::close() {
  206|     18|    ai_assert(mImpl != nullptr);
  ------------------
  |  |   67|     18|#   define ai_assert(expression) (void)((!!(expression)) || (Assimp::aiAssertViolation(#expression, __FILE__, __LINE__), 0))
  |  |  ------------------
  |  |  |  Branch (67:41): [True: 18, False: 0]
  |  |  |  Branch (67:61): [True: 0, False: 0]
  |  |  ------------------
  ------------------
  207|       |
  208|     18|    if (!mImpl->mOpen) {
  ------------------
  |  Branch (208:9): [True: 0, False: 18]
  ------------------
  209|      0|        return false;
  210|      0|    }
  211|       |
  212|     18|    inflateEnd(&mImpl->mZSstream);
  213|     18|    mImpl->mOpen = false;
  214|       |
  215|     18|    return true;
  216|     18|}
_ZN6Assimp11Compression4implC2Ev:
   54|     18|            mOpen(false),
   55|     18|            mZSstream(),
   56|     18|            mFlushMode(Compression::FlushMode::NoFlush) {
   57|       |        // empty
   58|     18|    }
Compression.cpp:_ZN6AssimpL12getFlushModeENS_11Compression9FlushModeE:
  105|     18|static int getFlushMode(Compression::FlushMode flush) {
  106|     18|    int z_flush = 0;
  107|     18|    switch (flush) {
  108|     18|        case Compression::FlushMode::NoFlush:
  ------------------
  |  Branch (108:9): [True: 18, False: 0]
  ------------------
  109|     18|            z_flush = Z_NO_FLUSH;
  ------------------
  |  |  168|     18|#define Z_NO_FLUSH      0
  ------------------
  110|     18|            break;
  111|      0|        case Compression::FlushMode::Block:
  ------------------
  |  Branch (111:9): [True: 0, False: 18]
  ------------------
  112|      0|            z_flush = Z_BLOCK;
  ------------------
  |  |  173|      0|#define Z_BLOCK         5
  ------------------
  113|      0|            break;
  114|      0|        case Compression::FlushMode::Tree:
  ------------------
  |  Branch (114:9): [True: 0, False: 18]
  ------------------
  115|      0|            z_flush = Z_TREES;
  ------------------
  |  |  174|      0|#define Z_TREES         6
  ------------------
  116|      0|            break;
  117|      0|        case Compression::FlushMode::SyncFlush:
  ------------------
  |  Branch (117:9): [True: 0, False: 18]
  ------------------
  118|      0|            z_flush = Z_SYNC_FLUSH;
  ------------------
  |  |  170|      0|#define Z_SYNC_FLUSH    2
  ------------------
  119|      0|            break;
  120|      0|        case Compression::FlushMode::Finish:
  ------------------
  |  Branch (120:9): [True: 0, False: 18]
  ------------------
  121|      0|            z_flush = Z_FINISH;
  ------------------
  |  |  172|      0|#define Z_FINISH        4
  ------------------
  122|      0|            break;
  123|      0|        default:
  ------------------
  |  Branch (123:9): [True: 0, False: 18]
  ------------------
  124|      0|            ai_assert(false);
  ------------------
  |  |   67|      0|#   define ai_assert(expression) (void)((!!(expression)) || (Assimp::aiAssertViolation(#expression, __FILE__, __LINE__), 0))
  |  |  ------------------
  |  |  |  Branch (67:41): [Folded, False: 0]
  |  |  |  Branch (67:61): [True: 0, False: 0]
  |  |  ------------------
  ------------------
  125|      0|            break;
  126|     18|    }
  127|       |
  128|     18|    return z_flush;
  129|     18|}

_ZNK6Assimp15DefaultIOSystem6ExistsEPKc:
   95|   266k|bool DefaultIOSystem::Exists(const char *pFile) const {
   96|   266k|    if (pFile == nullptr) {
  ------------------
  |  Branch (96:9): [True: 0, False: 266k]
  ------------------
   97|      0|        return false;
   98|      0|    }
   99|       |
  100|       |#ifdef _WIN32
  101|       |    struct __stat64 filestat;
  102|       |    if (_wstat64(Utf8ToWide(pFile).c_str(), &filestat) != 0) {
  103|       |        return false;
  104|       |    }
  105|       |#else
  106|   266k|	struct stat statbuf;
  107|   266k|    if (stat(pFile, &statbuf) != 0) {
  ------------------
  |  Branch (107:9): [True: 264k, False: 1.78k]
  ------------------
  108|   264k|        return false;
  109|   264k|    }
  110|       |    // test for a regular file
  111|  1.78k|    if (!S_ISREG(statbuf.st_mode)) {
  ------------------
  |  Branch (111:9): [True: 1.78k, False: 0]
  ------------------
  112|  1.78k|        return false;
  113|  1.78k|    }
  114|      0|#endif
  115|       |
  116|      0|    return true;
  117|  1.78k|}
_ZN6Assimp15DefaultIOSystem4OpenEPKcS2_:
  121|  12.3k|IOStream *DefaultIOSystem::Open(const char *strFile, const char *strMode) {
  122|  12.3k|    ai_assert(strFile != nullptr);
  123|  12.3k|    ai_assert(strMode != nullptr);
  124|  12.3k|    FILE *file;
  125|       |
  126|       |#ifdef _WIN32
  127|       |    std::wstring name = Utf8ToWide(strFile);
  128|       |    if (name.empty()) {
  129|       |        return nullptr;
  130|       |    }
  131|       |
  132|       |    file = ::_wfopen(name.c_str(), Utf8ToWide(strMode).c_str());
  133|       |#else
  134|  12.3k|    file = ::fopen(strFile, strMode);
  135|  12.3k|#endif
  136|       |
  137|  12.3k|    if (!file) {
  ------------------
  |  Branch (137:9): [True: 12.3k, False: 0]
  ------------------
  138|  12.3k|        return nullptr;
  139|  12.3k|    }
  140|       |
  141|      0|    return new DefaultIOStream(file, strFile);
  142|  12.3k|}
_ZNK6Assimp15DefaultIOSystem14getOsSeparatorEv:
  152|  4.27k|char DefaultIOSystem::getOsSeparator() const {
  153|  4.27k|#ifndef _WIN32
  154|  4.27k|    return '/';
  155|       |#else
  156|       |    return '\\';
  157|       |#endif
  158|  4.27k|}
_ZNK6Assimp15DefaultIOSystem12ComparePathsEPKcS2_:
  195|   111k|bool DefaultIOSystem::ComparePaths(const char *one, const char *second) const {
  196|       |    // chances are quite good both paths are formatted identically,
  197|       |    // so we can hopefully return here already
  198|   111k|    if (!ASSIMP_stricmp(one, second))
  ------------------
  |  Branch (198:9): [True: 16.1k, False: 95.4k]
  ------------------
  199|  16.1k|        return true;
  200|       |
  201|  95.4k|    std::string temp1 = MakeAbsolutePath(one);
  202|  95.4k|    std::string temp2 = MakeAbsolutePath(second);
  203|       |
  204|  95.4k|    return !ASSIMP_stricmp(temp1, temp2);
  205|   111k|}
_ZN6Assimp15DefaultIOSystem8fileNameERKNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEE:
  208|  3.43k|std::string DefaultIOSystem::fileName(const std::string &path) {
  209|  3.43k|    std::string ret = path;
  210|  3.43k|    std::size_t last = ret.find_last_of("\\/");
  211|  3.43k|    if (last != std::string::npos) ret = ret.substr(last + 1);
  ------------------
  |  Branch (211:9): [True: 0, False: 3.43k]
  ------------------
  212|  3.43k|    return ret;
  213|  3.43k|}
_ZN6Assimp15DefaultIOSystem16completeBaseNameERKNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEE:
  216|  3.43k|std::string DefaultIOSystem::completeBaseName(const std::string &path) {
  217|  3.43k|    std::string ret = fileName(path);
  218|  3.43k|    std::size_t pos = ret.find_last_of('.');
  219|  3.43k|    if (pos != std::string::npos) ret = ret.substr(0, pos);
  ------------------
  |  Branch (219:9): [True: 835, False: 2.59k]
  ------------------
  220|  3.43k|    return ret;
  221|  3.43k|}
_ZN6Assimp15DefaultIOSystem12absolutePathERKNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEE:
  224|      7|std::string DefaultIOSystem::absolutePath(const std::string &path) {
  225|      7|    std::string ret = path;
  226|      7|    std::size_t last = ret.find_last_of("\\/");
  227|      7|    if (last != std::string::npos) ret = ret.substr(0, last);
  ------------------
  |  Branch (227:9): [True: 0, False: 7]
  ------------------
  228|      7|    return ret;
  229|      7|}
DefaultIOSystem.cpp:_ZL16MakeAbsolutePathPKc:
  168|   190k|inline static std::string MakeAbsolutePath(const char *in) {
  169|   190k|    ai_assert(in);
  170|   190k|    std::string out;
  171|       |#ifdef _WIN32
  172|       |    wchar_t *ret = ::_wfullpath(nullptr, Utf8ToWide(in).c_str(), 0);
  173|       |    if (ret) {
  174|       |        out = WideToUtf8(ret);
  175|       |        free(ret);
  176|       |    }
  177|       |#else
  178|   190k|    char *ret = realpath(in, nullptr);
  179|   190k|    if (ret) {
  ------------------
  |  Branch (179:9): [True: 2, False: 190k]
  ------------------
  180|      2|        out = ret;
  181|      2|        free(ret);
  182|      2|    }
  183|   190k|#endif
  184|   190k|    else {
  185|       |        // preserve the input path, maybe someone else is able to fix
  186|       |        // the path before it is accessed (e.g. our file system filter)
  187|       |        ASSIMP_LOG_WARN("Invalid path: ", std::string(in));
  188|   190k|        out = in;
  189|   190k|    }
  190|   190k|    return out;
  191|   190k|}

_ZN6Assimp6Logger5debugEPKc:
  166|  7.15k|void Logger::debug(const char *message) {
  167|       |
  168|       |    // SECURITY FIX: otherwise it's easy to produce overruns since
  169|       |    // sometimes importers will include data from the input file
  170|       |    // (i.e. node names) in their messages.
  171|  7.15k|    if (strlen(message) > MAX_LOG_MESSAGE_LENGTH) {
  ------------------
  |  Branch (171:9): [True: 0, False: 7.15k]
  ------------------
  172|      0|        return OnDebug("<fixme: long message discarded>");
  173|      0|    }
  174|  7.15k|    return OnDebug(message);
  175|  7.15k|}
_ZN6Assimp6Logger12verboseDebugEPKc:
  178|  22.5k|void Logger::verboseDebug(const char *message) {
  179|       |
  180|       |    // SECURITY FIX: see above
  181|  22.5k|    if (strlen(message) > MAX_LOG_MESSAGE_LENGTH) {
  ------------------
  |  Branch (181:9): [True: 0, False: 22.5k]
  ------------------
  182|      0|        return OnVerboseDebug("<fixme: long message discarded>");
  183|      0|    }
  184|  22.5k|    return OnVerboseDebug(message);
  185|  22.5k|}
_ZN6Assimp6Logger4infoEPKc:
  188|  8.48k|void Logger::info(const char *message) {
  189|       |
  190|       |    // SECURITY FIX: see above
  191|  8.48k|    if (strlen(message) > MAX_LOG_MESSAGE_LENGTH) {
  ------------------
  |  Branch (191:9): [True: 9, False: 8.47k]
  ------------------
  192|      9|        return OnInfo("<fixme: long message discarded>");
  193|      9|    }
  194|  8.47k|    return OnInfo(message);
  195|  8.48k|}
_ZN6Assimp6Logger4warnEPKc:
  198|   738k|void Logger::warn(const char *message) {
  199|       |
  200|       |    // SECURITY FIX: see above
  201|   738k|    if (strlen(message) > MAX_LOG_MESSAGE_LENGTH) {
  ------------------
  |  Branch (201:9): [True: 99, False: 738k]
  ------------------
  202|     99|        return OnWarn("<fixme: long message discarded>");
  203|     99|    }
  204|   738k|    return OnWarn(message);
  205|   738k|}
_ZN6Assimp6Logger5errorEPKc:
  208|  94.1k|void Logger::error(const char *message) {
  209|       |    // SECURITY FIX: see above
  210|  94.1k|    if (strlen(message) > MAX_LOG_MESSAGE_LENGTH) {
  ------------------
  |  Branch (210:9): [True: 33, False: 94.1k]
  ------------------
  211|     33|        return OnError("<fixme: long message discarded>");
  212|     33|    }
  213|  94.1k|    return OnError(message);
  214|  94.1k|}
_ZN6Assimp13DefaultLogger12isNullLoggerEv:
  232|  9.43k|bool DefaultLogger::isNullLogger() {
  233|  9.43k|    return m_pLogger == &s_pNullLogger;
  234|  9.43k|}
_ZN6Assimp13DefaultLogger3getEv:
  237|   871k|Logger *DefaultLogger::get() {
  238|   871k|    return m_pLogger;
  239|   871k|}

_ZN6Assimp22DefaultProgressHandler6UpdateEf:
   59|  9.52k|    bool Update(float) override {
   60|  9.52k|        return false;
   61|  9.52k|    }

_ZN15DeadlyErrorBaseC2EN6Assimp9Formatter15basic_formatterIcNSt3__111char_traitsIcEENS3_9allocatorIcEEEE:
   52|  2.39k|        runtime_error(std::string(f)){}

_ZN6Assimp8ExporterC2Ev:
  286|    208|: pimpl(new ExporterPimpl()) {
  287|    208|    pimpl->mProgressHandler = new DefaultProgressHandler();
  288|    208|}
_ZN6Assimp8ExporterD2Ev:
  291|    208|Exporter::~Exporter() {
  292|       |	ai_assert(nullptr != pimpl);
  293|    208|	FreeBlob();
  294|    208|    delete pimpl;
  295|    208|}
_ZN6Assimp8Exporter12ExportToBlobEPK7aiScenePKcjPKNS_16ExportPropertiesE:
  338|    208|                                                unsigned int pPreprocessing, const ExportProperties* pProperties) {
  339|    208|	ai_assert(nullptr != pimpl);
  340|    208|    if (pimpl->blob) {
  ------------------
  |  Branch (340:9): [True: 0, False: 208]
  ------------------
  341|      0|        delete pimpl->blob;
  342|      0|        pimpl->blob = nullptr;
  343|      0|    }
  344|       |
  345|    208|    auto baseName = pProperties ? pProperties->GetPropertyString(AI_CONFIG_EXPORT_BLOB_NAME, AI_BLOBIO_MAGIC) : AI_BLOBIO_MAGIC;
  ------------------
  |  Branch (345:21): [True: 0, False: 208]
  ------------------
  346|       |
  347|    208|    std::shared_ptr<IOSystem> old = pimpl->mIOSystem;
  348|    208|    BlobIOSystem *blobio = new BlobIOSystem(baseName);
  349|    208|    pimpl->mIOSystem = std::shared_ptr<IOSystem>( blobio );
  350|       |
  351|    208|    if (AI_SUCCESS != Export(pScene,pFormatId,blobio->GetMagicFileName(), pPreprocessing, pProperties)) {
  ------------------
  |  Branch (351:9): [True: 1, False: 207]
  ------------------
  352|      1|        pimpl->mIOSystem = old;
  353|      1|        return nullptr;
  354|      1|    }
  355|       |
  356|    207|    pimpl->blob = blobio->GetBlobChain();
  357|    207|    pimpl->mIOSystem = old;
  358|       |
  359|    207|    return pimpl->blob;
  360|    208|}
_ZN6Assimp8Exporter6ExportEPK7aiScenePKcS5_jPKNS_16ExportPropertiesE:
  364|    208|        unsigned int pPreprocessing, const ExportProperties* pProperties) {
  365|    208|    ASSIMP_BEGIN_EXCEPTION_REGION();
  366|    208|	ai_assert(nullptr != pimpl);
  367|       |    // when they create scenes from scratch, users will likely create them not in verbose
  368|       |    // format. They will likely not be aware that there is a flag in the scene to indicate
  369|       |    // this, however. To avoid surprises and bug reports, we check for duplicates in
  370|       |    // meshes upfront.
  371|    208|    const bool is_verbose_format = !(pScene->mFlags & AI_SCENE_FLAGS_NON_VERBOSE_FORMAT) || MakeVerboseFormatProcess::IsVerboseFormat(pScene);
  ------------------
  |  Branch (371:36): [True: 0, False: 208]
  |  Branch (371:93): [True: 54, False: 154]
  ------------------
  372|       |
  373|    208|    pimpl->mProgressHandler->UpdateFileWrite(0, 4);
  374|       |
  375|    208|    pimpl->mError = "";
  376|  3.74k|    for (size_t i = 0; i < pimpl->mExporters.size(); ++i) {
  ------------------
  |  Branch (376:24): [True: 3.74k, False: 0]
  ------------------
  377|  3.74k|        const Exporter::ExportFormatEntry& exp = pimpl->mExporters[i];
  378|  3.74k|        if (!strcmp(exp.mDescription.id,pFormatId)) {
  ------------------
  |  Branch (378:13): [True: 208, False: 3.53k]
  ------------------
  379|    208|            try {
  380|       |                // Always create a full copy of the scene. We might optimize this one day,
  381|       |                // but for now it is the most pragmatic way.
  382|    208|                aiScene* scenecopy_tmp = nullptr;
  383|    208|                SceneCombiner::CopyScene(&scenecopy_tmp,pScene);
  384|       |
  385|    208|                pimpl->mProgressHandler->UpdateFileWrite(1, 4);
  386|       |
  387|    208|                std::unique_ptr<aiScene> scenecopy(scenecopy_tmp);
  388|    208|                const ScenePrivateData* const priv = ScenePriv(pScene);
  389|       |
  390|       |                // steps that are not idempotent, i.e. we might need to run them again, usually to get back to the
  391|       |                // original state before the step was applied first. When checking which steps we don't need
  392|       |                // to run, those are excluded.
  393|    208|                const unsigned int nonIdempotentSteps = aiProcess_FlipWindingOrder | aiProcess_FlipUVs | aiProcess_MakeLeftHanded;
  394|       |
  395|       |                // Erase all pp steps that were already applied to this scene
  396|    208|                const unsigned int pp = (exp.mEnforcePP | pPreprocessing) & ~(priv && !priv->mIsCopy
  ------------------
  |  Branch (396:79): [True: 208, False: 0]
  |  Branch (396:87): [True: 208, False: 0]
  ------------------
  397|    208|                    ? (priv->mPPStepsApplied & ~nonIdempotentSteps)
  398|    208|                    : 0u);
  399|       |
  400|       |                // If no extra post-processing was specified, and we obtained this scene from an
  401|       |                // Assimp importer, apply the reverse steps automatically.
  402|       |                // TODO: either drop this, or document it. Otherwise it is just a bad surprise.
  403|       |                //if (!pPreprocessing && priv) {
  404|       |                //  pp |= (nonIdempotentSteps & priv->mPPStepsApplied);
  405|       |                //}
  406|       |
  407|       |                // If the input scene is not in verbose format, but there is at least post-processing step that relies on it,
  408|       |                // we need to run the MakeVerboseFormat step first.
  409|    208|                bool must_join_again = false;
  410|    208|                if (!is_verbose_format) {
  ------------------
  |  Branch (410:21): [True: 154, False: 54]
  ------------------
  411|    154|                    bool verbosify = false;
  412|  5.23k|                    for( unsigned int a = 0; a < pimpl->mPostProcessingSteps.size(); a++) {
  ------------------
  |  Branch (412:46): [True: 5.08k, False: 154]
  ------------------
  413|  5.08k|                        BaseProcess* const p = pimpl->mPostProcessingSteps[a];
  414|       |
  415|  5.08k|                        if (p->IsActive(pp) && p->RequireVerboseFormat()) {
  ------------------
  |  Branch (415:29): [True: 0, False: 5.08k]
  |  Branch (415:48): [True: 0, False: 0]
  ------------------
  416|      0|                            verbosify = true;
  417|      0|                            break;
  418|      0|                        }
  419|  5.08k|                    }
  420|       |
  421|    154|                    if (verbosify || (exp.mEnforcePP & aiProcess_JoinIdenticalVertices)) {
  ------------------
  |  Branch (421:25): [True: 0, False: 154]
  |  Branch (421:38): [True: 0, False: 154]
  ------------------
  422|      0|                        ASSIMP_LOG_DEBUG("export: Scene data not in verbose format, applying MakeVerboseFormat step first");
  423|       |
  424|      0|                        MakeVerboseFormatProcess proc;
  425|      0|                        proc.Execute(scenecopy.get());
  426|       |
  427|      0|                        if(!(exp.mEnforcePP & aiProcess_JoinIdenticalVertices)) {
  ------------------
  |  Branch (427:28): [True: 0, False: 0]
  ------------------
  428|      0|                            must_join_again = true;
  429|      0|                        }
  430|      0|                    }
  431|    154|                }
  432|       |
  433|    208|                pimpl->mProgressHandler->UpdateFileWrite(2, 4);
  434|       |
  435|    208|                if (pp) {
  ------------------
  |  Branch (435:21): [True: 0, False: 208]
  ------------------
  436|       |                    // the three 'conversion' steps need to be executed first because all other steps rely on the standard data layout
  437|      0|                    {
  438|      0|                        FlipWindingOrderProcess step;
  439|      0|                        if (step.IsActive(pp)) {
  ------------------
  |  Branch (439:29): [True: 0, False: 0]
  ------------------
  440|      0|                            step.Execute(scenecopy.get());
  441|      0|                        }
  442|      0|                    }
  443|       |
  444|      0|                    {
  445|      0|                        FlipUVsProcess step;
  446|      0|                        if (step.IsActive(pp)) {
  ------------------
  |  Branch (446:29): [True: 0, False: 0]
  ------------------
  447|      0|                            step.Execute(scenecopy.get());
  448|      0|                        }
  449|      0|                    }
  450|       |
  451|      0|                    {
  452|      0|                        MakeLeftHandedProcess step;
  453|      0|                        if (step.IsActive(pp)) {
  ------------------
  |  Branch (453:29): [True: 0, False: 0]
  ------------------
  454|      0|                            step.Execute(scenecopy.get());
  455|      0|                        }
  456|      0|                    }
  457|       |
  458|      0|                    bool exportPointCloud(false);
  459|      0|                    if (nullptr != pProperties) {
  ------------------
  |  Branch (459:25): [True: 0, False: 0]
  ------------------
  460|      0|                        exportPointCloud = pProperties->GetPropertyBool(AI_CONFIG_EXPORT_POINT_CLOUDS);
  461|      0|                    }
  462|       |
  463|       |                    // dispatch other processes
  464|      0|                    for( unsigned int a = 0; a < pimpl->mPostProcessingSteps.size(); a++) {
  ------------------
  |  Branch (464:46): [True: 0, False: 0]
  ------------------
  465|      0|                        BaseProcess* const p = pimpl->mPostProcessingSteps[a];
  466|       |
  467|      0|                        if (p->IsActive(pp)
  ------------------
  |  Branch (467:29): [True: 0, False: 0]
  ------------------
  468|      0|                            && !dynamic_cast<FlipUVsProcess*>(p)
  ------------------
  |  Branch (468:32): [True: 0, False: 0]
  ------------------
  469|      0|                            && !dynamic_cast<FlipWindingOrderProcess*>(p)
  ------------------
  |  Branch (469:32): [True: 0, False: 0]
  ------------------
  470|      0|                            && !dynamic_cast<MakeLeftHandedProcess*>(p)) {
  ------------------
  |  Branch (470:32): [True: 0, False: 0]
  ------------------
  471|      0|                            if (dynamic_cast<PretransformVertices*>(p) && exportPointCloud) {
  ------------------
  |  Branch (471:33): [True: 0, False: 0]
  |  Branch (471:75): [True: 0, False: 0]
  ------------------
  472|      0|                                continue;
  473|      0|                            }
  474|      0|                            p->Execute(scenecopy.get());
  475|      0|                        }
  476|      0|                    }
  477|      0|                    ScenePrivateData* const privOut = ScenePriv(scenecopy.get());
  478|      0|                    ai_assert(nullptr != privOut);
  479|       |
  480|      0|                    privOut->mPPStepsApplied |= pp;
  481|      0|                }
  482|       |
  483|    208|                pimpl->mProgressHandler->UpdateFileWrite(3, 4);
  484|       |
  485|    208|                if(must_join_again) {
  ------------------
  |  Branch (485:20): [True: 0, False: 208]
  ------------------
  486|      0|                    JoinVerticesProcess proc;
  487|      0|                    proc.Execute(scenecopy.get());
  488|      0|                }
  489|       |
  490|    208|                ExportProperties emptyProperties;  // Never pass nullptr ExportProperties so Exporters don't have to worry.
  491|    208|                ExportProperties* pProp = pProperties ? (ExportProperties*)pProperties : &emptyProperties;
  ------------------
  |  Branch (491:43): [True: 0, False: 208]
  ------------------
  492|    208|        		pProp->SetPropertyBool("bJoinIdenticalVertices", pp & aiProcess_JoinIdenticalVertices);
  493|    208|                exp.mExportFunction(pPath,pimpl->mIOSystem.get(),scenecopy.get(), pProp);
  494|       |
  495|    208|                pimpl->mProgressHandler->UpdateFileWrite(4, 4);
  496|    208|            } catch (DeadlyExportError& err) {
  497|      1|                pimpl->mError = err.what();
  498|      1|                return AI_FAILURE;
  499|      1|            }
  500|    207|            return AI_SUCCESS;
  501|    208|        }
  502|  3.74k|    }
  503|       |
  504|      0|    pimpl->mError = std::string("Found no exporter to handle this file format: ") + pFormatId;
  505|      0|    ASSIMP_END_EXCEPTION_REGION(aiReturn);
  506|       |
  507|       |    return AI_FAILURE;
  508|    208|}
_ZN6Assimp8Exporter8FreeBlobEv:
  517|    208|void Exporter::FreeBlob() {
  518|    208|	ai_assert(nullptr != pimpl);
  519|    208|    delete pimpl->blob;
  520|    208|    pimpl->blob = nullptr;
  521|       |
  522|    208|    pimpl->mError = "";
  523|    208|}
_ZN6Assimp16ExportPropertiesC2Ev:
  586|    208|ExportProperties::ExportProperties() = default;
_ZN6Assimp16ExportProperties18SetPropertyIntegerEPKci:
  605|    208|bool ExportProperties::SetPropertyInteger(const char* szName, int iValue) {
  606|    208|    return SetGenericProperty<int>(mIntProperties, szName,iValue);
  607|    208|}
_ZNK6Assimp16ExportProperties18GetPropertyIntegerEPKci:
  629|    416|int ExportProperties::GetPropertyInteger(const char* szName, int iErrorReturn /*= 0xffffffff*/) const {
  630|    416|    return GetGenericProperty<int>(mIntProperties,szName,iErrorReturn);
  631|    416|}
_ZN6Assimp13ExporterPimplC2Ev:
  238|    208|    , mIOSystem(new Assimp::DefaultIOSystem())
  239|    208|    , mIsDefaultIOHandler(true)
  240|    208|    , mProgressHandler( nullptr )
  241|    208|    , mIsDefaultProgressHandler( true )
  242|    208|    , mPostProcessingSteps()
  243|    208|    , mError()
  244|    208|    , mExporters() {
  245|    208|        GetPostProcessingStepInstanceList(mPostProcessingSteps);
  246|       |
  247|       |        // grab all built-in exporters
  248|    208|		setupExporterArray(mExporters);
  249|    208|    }
Exporter.cpp:_ZN6AssimpL18setupExporterArrayERNSt3__16vectorINS_8Exporter17ExportFormatEntryENS0_9allocatorIS3_EEEE:
  145|    208|static void setupExporterArray(std::vector<Exporter::ExportFormatEntry> &exporters) {
  146|    208|	(void)exporters;
  147|       |
  148|    208|#ifndef ASSIMP_BUILD_NO_COLLADA_EXPORTER
  149|    208|	exporters.emplace_back("collada", "COLLADA - Digital Asset Exchange Schema", "dae", &ExportSceneCollada);
  150|    208|#endif
  151|       |
  152|    208|#ifndef ASSIMP_BUILD_NO_X_EXPORTER
  153|    208|	exporters.emplace_back("x", "X Files", "x", &ExportSceneXFile,
  154|    208|			aiProcess_MakeLeftHanded | aiProcess_FlipWindingOrder | aiProcess_FlipUVs);
  155|    208|#endif
  156|       |
  157|    208|#ifndef ASSIMP_BUILD_NO_STEP_EXPORTER
  158|    208|	exporters.emplace_back("stp", "Step Files", "stp", &ExportSceneStep, 0);
  159|    208|#endif
  160|       |
  161|    208|#ifndef ASSIMP_BUILD_NO_OBJ_EXPORTER
  162|    208|	exporters.emplace_back("obj", "Wavefront OBJ format", "obj", &ExportSceneObj);
  163|    208|	exporters.emplace_back("objnomtl", "Wavefront OBJ format without material file", "obj", &ExportSceneObjNoMtl);
  164|    208|#endif
  165|       |
  166|    208|#ifndef ASSIMP_BUILD_NO_STL_EXPORTER
  167|    208|	exporters.emplace_back("stl", "Stereolithography", "stl", &ExportSceneSTL,
  168|    208|			aiProcess_Triangulate | aiProcess_GenNormals | aiProcess_PreTransformVertices);
  169|    208|	exporters.emplace_back("stlb", "Stereolithography (binary)", "stl", &ExportSceneSTLBinary,
  170|    208|			aiProcess_Triangulate | aiProcess_GenNormals | aiProcess_PreTransformVertices);
  171|    208|#endif
  172|       |
  173|    208|#ifndef ASSIMP_BUILD_NO_PLY_EXPORTER
  174|    208|	exporters.emplace_back("ply", "Stanford Polygon Library", "ply", &ExportScenePly,
  175|    208|			aiProcess_PreTransformVertices);
  176|    208|	exporters.emplace_back("plyb", "Stanford Polygon Library (binary)", "ply", &ExportScenePlyBinary,
  177|    208|			aiProcess_PreTransformVertices);
  178|    208|#endif
  179|       |
  180|    208|#ifndef ASSIMP_BUILD_NO_3DS_EXPORTER
  181|    208|	exporters.emplace_back("3ds", "Autodesk 3DS (legacy)", "3ds", &ExportScene3DS,
  182|    208|			aiProcess_Triangulate | aiProcess_SortByPType | aiProcess_JoinIdenticalVertices);
  183|    208|#endif
  184|       |
  185|    208|#if !defined(ASSIMP_BUILD_NO_GLTF_EXPORTER) && !defined(ASSIMP_BUILD_NO_GLTF2_EXPORTER)
  186|    208|	exporters.emplace_back("gltf2", "GL Transmission Format v. 2", "gltf", &ExportSceneGLTF2,
  187|    208|			aiProcess_JoinIdenticalVertices | aiProcess_Triangulate | aiProcess_SortByPType);
  188|    208|	exporters.emplace_back("glb2", "GL Transmission Format v. 2 (binary)", "glb", &ExportSceneGLB2,
  189|    208|			aiProcess_JoinIdenticalVertices | aiProcess_Triangulate | aiProcess_SortByPType);
  190|    208|#endif
  191|       |
  192|    208|#if !defined(ASSIMP_BUILD_NO_GLTF_EXPORTER) && !defined(ASSIMP_BUILD_NO_GLTF1_EXPORTER)
  193|    208|	exporters.emplace_back("gltf", "GL Transmission Format", "gltf", &ExportSceneGLTF,
  194|    208|			aiProcess_JoinIdenticalVertices | aiProcess_Triangulate | aiProcess_SortByPType);
  195|    208|	exporters.emplace_back("glb", "GL Transmission Format (binary)", "glb", &ExportSceneGLB,
  196|    208|			aiProcess_JoinIdenticalVertices | aiProcess_Triangulate | aiProcess_SortByPType);
  197|    208|#endif
  198|       |
  199|    208|#ifndef ASSIMP_BUILD_NO_ASSBIN_EXPORTER
  200|    208|	exporters.emplace_back("assbin", "Assimp Binary File", "assbin", &ExportSceneAssbin, 0);
  201|    208|#endif
  202|       |
  203|    208|#ifndef ASSIMP_BUILD_NO_ASSXML_EXPORTER
  204|    208|	exporters.emplace_back("assxml", "Assimp XML Document", "assxml", &ExportSceneAssxml, 0);
  205|    208|#endif
  206|       |
  207|    208|#ifndef ASSIMP_BUILD_NO_X3D_EXPORTER
  208|    208|	exporters.emplace_back("x3d", "Extensible 3D", "x3d", &ExportSceneX3D, 0);
  209|    208|#endif
  210|       |
  211|    208|#ifndef ASSIMP_BUILD_NO_FBX_EXPORTER
  212|    208|	exporters.emplace_back("fbx", "Autodesk FBX (binary)", "fbx", &ExportSceneFBX, 0);
  213|    208|	exporters.emplace_back("fbxa", "Autodesk FBX (ascii)", "fbx", &ExportSceneFBXA, 0);
  214|    208|#endif
  215|       |
  216|       |#ifndef ASSIMP_BUILD_NO_M3D_EXPORTER
  217|       |	exporters.push_back(Exporter::ExportFormatEntry("m3d", "Model 3D (binary)", "m3d", &ExportSceneM3D, 0));
  218|       |	exporters.push_back(Exporter::ExportFormatEntry("m3da", "Model 3D (ascii)", "a3d", &ExportSceneM3DA, 0));
  219|       |#endif
  220|       |
  221|    208|#ifndef ASSIMP_BUILD_NO_3MF_EXPORTER
  222|    208|	exporters.emplace_back("3mf", "The 3MF-File-Format", "3mf", &ExportScene3MF, 0);
  223|    208|#endif
  224|       |
  225|    208|#ifndef ASSIMP_BUILD_NO_PBRT_EXPORTER
  226|    208|	exporters.emplace_back("pbrt", "pbrt-v4 scene description file", "pbrt", &ExportScenePbrt, aiProcess_ConvertToLeftHanded | aiProcess_Triangulate | aiProcess_SortByPType);
  227|    208|#endif
  228|       |
  229|    208|#ifndef ASSIMP_BUILD_NO_ASSJSON_EXPORTER
  230|    208|	exporters.emplace_back("assjson", "Assimp JSON Document", "json", &ExportAssimp2Json, 0);
  231|    208|#endif
  232|    208|}
_ZN6Assimp13ExporterPimplD2Ev:
  251|    208|    ~ExporterPimpl() {
  252|    208|        delete blob;
  253|       |
  254|       |        // Delete all post-processing plug-ins
  255|  7.07k|        for( unsigned int a = 0; a < mPostProcessingSteps.size(); a++) {
  ------------------
  |  Branch (255:34): [True: 6.86k, False: 208]
  ------------------
  256|  6.86k|            delete mPostProcessingSteps[a];
  257|  6.86k|        }
  258|    208|        delete mProgressHandler;
  259|    208|    }

_ZN6Assimp16FileSystemFilterC2ERKNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEPNS_8IOSystemE:
   68|    582|    : mWrapped  (old)
   69|    582|    , mSrc_file(file)
   70|    582|    , mSep(mWrapped->getOsSeparator()) {
   71|    582|        ai_assert(nullptr != mWrapped);
   72|       |
   73|       |        // Determine base directory
   74|    582|        mBase = mSrc_file;
   75|    582|        std::string::size_type ss2;
   76|    582|        if (std::string::npos != (ss2 = mBase.find_last_of("\\/")))  {
  ------------------
  |  Branch (76:13): [True: 107, False: 475]
  ------------------
   77|    107|            mBase.erase(ss2,mBase.length()-ss2);
   78|    475|        } else {
   79|    475|            mBase = std::string();
   80|    475|        }
   81|       |
   82|       |        // make sure the directory is terminated properly
   83|    582|        char s;
   84|       |
   85|    582|        if ( mBase.empty() ) {
  ------------------
  |  Branch (85:14): [True: 475, False: 107]
  ------------------
   86|    475|            mBase = ".";
   87|    475|            mBase += getOsSeparator();
   88|    475|        } else if ((s = *(mBase.end()-1)) != '\\' && s != '/') {
  ------------------
  |  Branch (88:20): [True: 107, False: 0]
  |  Branch (88:20): [True: 49, False: 58]
  |  Branch (88:54): [True: 49, False: 58]
  ------------------
   89|     49|            mBase += getOsSeparator();
   90|     49|        }
   91|       |
   92|    582|        DefaultLogger::get()->info("Import root directory is \'", mBase, "\'");
   93|    582|    }
_ZNK6Assimp16FileSystemFilter6ExistsEPKc:
  100|  79.0k|    bool Exists( const char* pFile) const {
  101|  79.0k|        ai_assert( nullptr != mWrapped );
  102|       |
  103|  79.0k|        std::string tmp = pFile;
  104|       |
  105|       |        // Currently this IOSystem is also used to open THE ONE FILE.
  106|  79.0k|        if (tmp != mSrc_file)    {
  ------------------
  |  Branch (106:13): [True: 78.9k, False: 103]
  ------------------
  107|  78.9k|            BuildPath(tmp);
  108|  78.9k|            Cleanup(tmp);
  109|  78.9k|        }
  110|       |
  111|  79.0k|        return mWrapped->Exists(tmp);
  112|  79.0k|    }
_ZNK6Assimp16FileSystemFilter9BuildPathERNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEE:
  222|  87.2k|    void BuildPath (std::string& in) const {
  223|  87.2k|        ai_assert( nullptr != mWrapped );
  224|       |        // if we can already access the file, great.
  225|  87.2k|        if (in.length() < 3 || mWrapped->Exists(in)) {
  ------------------
  |  Branch (225:13): [True: 4.12k, False: 83.1k]
  |  Branch (225:32): [True: 14.0k, False: 69.0k]
  ------------------
  226|  18.1k|            return;
  227|  18.1k|        }
  228|       |
  229|       |        // Determine whether this is a relative path (Windows-specific - most assets are packaged on Windows).
  230|  69.0k|        if (in[1] != ':') {
  ------------------
  |  Branch (230:13): [True: 66.7k, False: 2.30k]
  ------------------
  231|       |
  232|       |            // append base path and try
  233|  66.7k|            const std::string tmp = mBase + in;
  234|  66.7k|            if (mWrapped->Exists(tmp)) {
  ------------------
  |  Branch (234:17): [True: 1.83k, False: 64.9k]
  ------------------
  235|  1.83k|                in = tmp;
  236|  1.83k|                return;
  237|  1.83k|            }
  238|  66.7k|        }
  239|       |
  240|       |        // Chop of the file name and look in the model directory, if
  241|       |        // this fails try all sub paths of the given path, i.e.
  242|       |        // if the given path is foo/bar/something.lwo, try
  243|       |        // <base>/something.lwo
  244|       |        // <base>/bar/something.lwo
  245|       |        // <base>/foo/bar/something.lwo
  246|  67.2k|        std::string::size_type pos = in.rfind('/');
  247|  67.2k|        if (std::string::npos == pos) {
  ------------------
  |  Branch (247:13): [True: 18.2k, False: 48.9k]
  ------------------
  248|  18.2k|            pos = in.rfind('\\');
  249|  18.2k|        }
  250|       |
  251|  67.2k|        if (std::string::npos != pos)   {
  ------------------
  |  Branch (251:13): [True: 49.4k, False: 17.8k]
  ------------------
  252|  49.4k|            std::string tmp;
  253|  49.4k|            std::string::size_type last_dirsep = std::string::npos;
  254|       |
  255|   147k|            while(true) {
  ------------------
  |  Branch (255:19): [True: 147k, Folded]
  ------------------
  256|   147k|                tmp = mBase;
  257|   147k|                tmp += mSep;
  258|       |
  259|   147k|                std::string::size_type dirsep = in.rfind('/', last_dirsep);
  260|   147k|                if (std::string::npos == dirsep) {
  ------------------
  |  Branch (260:21): [True: 50.1k, False: 97.1k]
  ------------------
  261|  50.1k|                    dirsep = in.rfind('\\', last_dirsep);
  262|  50.1k|                }
  263|       |
  264|   147k|                if (std::string::npos == dirsep || dirsep == 0) {
  ------------------
  |  Branch (264:21): [True: 49.4k, False: 97.8k]
  |  Branch (264:52): [True: 2, False: 97.8k]
  ------------------
  265|       |                    // we did try this already.
  266|  49.4k|                    break;
  267|  49.4k|                }
  268|       |
  269|  97.8k|                last_dirsep = dirsep-1;
  270|       |
  271|  97.8k|                tmp += in.substr(dirsep+1, in.length()-pos);
  272|  97.8k|                if (mWrapped->Exists(tmp)) {
  ------------------
  |  Branch (272:21): [True: 0, False: 97.8k]
  ------------------
  273|      0|                    in = tmp;
  274|      0|                    return;
  275|      0|                }
  276|  97.8k|            }
  277|  49.4k|        }
  278|       |
  279|       |        // hopefully the underlying file system has another few tricks to access this file ...
  280|  67.2k|    }
_ZNK6Assimp16FileSystemFilter7CleanupERNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEE:
  285|  83.0k|    void Cleanup (std::string& in) const {
  286|  83.0k|        if(in.empty()) {
  ------------------
  |  Branch (286:12): [True: 0, False: 83.0k]
  ------------------
  287|      0|            return;
  288|      0|        }
  289|       |
  290|       |        // Remove a very common issue when we're parsing file names: spaces at the
  291|       |        // beginning of the path.
  292|  83.0k|        char last = 0;
  293|  83.0k|        std::string::iterator it = in.begin();
  294|  83.0k|        while (IsSpaceOrNewLine( *it ))++it;
  ------------------
  |  Branch (294:16): [True: 0, False: 83.0k]
  ------------------
  295|  83.0k|        if (it != in.begin()) {
  ------------------
  |  Branch (295:13): [True: 0, False: 83.0k]
  ------------------
  296|      0|            in.erase(in.begin(),it+1);
  297|      0|        }
  298|       |
  299|  83.0k|        const char separator = getOsSeparator();
  300|  3.12M|        for (it = in.begin(); it < in.end(); ++it) {
  ------------------
  |  Branch (300:31): [True: 3.04M, False: 83.0k]
  ------------------
  301|  3.04M|            const size_t remaining = std::distance(in.end(), it);
  302|       |            // Exclude :// and \\, which remain untouched.
  303|       |            // https://sourceforge.net/tracker/?func=detail&aid=3031725&group_id=226462&atid=1067632
  304|  3.04M|            if (remaining >= 3u && !strncmp(&*it, "://", 3 )) {
  ------------------
  |  Branch (304:17): [True: 3.04M, False: 0]
  |  Branch (304:36): [True: 7.01k, False: 3.03M]
  ------------------
  305|  7.01k|                it += 3;
  306|  7.01k|                continue;
  307|  7.01k|            }
  308|  3.03M|            if (it == in.begin() && remaining >= 2 && !strncmp(&*it, "\\\\", 2)) {
  ------------------
  |  Branch (308:17): [True: 83.0k, False: 2.95M]
  |  Branch (308:17): [True: 0, False: 3.03M]
  |  Branch (308:37): [True: 83.0k, False: 0]
  |  Branch (308:55): [True: 0, False: 83.0k]
  ------------------
  309|      0|                it += 2;
  310|      0|                continue;
  311|      0|            }
  312|       |
  313|       |            // Cleanup path delimiters
  314|  3.03M|            if (*it == '/' || (*it) == '\\') {
  ------------------
  |  Branch (314:17): [True: 116k, False: 2.91M]
  |  Branch (314:31): [True: 2.77k, False: 2.91M]
  ------------------
  315|   118k|                *it = separator;
  316|       |
  317|       |                // And we're removing double delimiters, frequent issue with
  318|       |                // incorrectly composited paths ...
  319|   118k|                if (last == *it) {
  ------------------
  |  Branch (319:21): [True: 16.6k, False: 102k]
  ------------------
  320|  16.6k|                    it = in.erase(it);
  321|  16.6k|                    --it;
  322|  16.6k|                }
  323|  2.91M|            } else if (*it == '%' && in.end() - it > 2) {
  ------------------
  |  Branch (323:24): [True: 1.10k, False: 2.91M]
  |  Branch (323:24): [True: 1.02k, False: 2.91M]
  |  Branch (323:38): [True: 1.02k, False: 76]
  ------------------
  324|       |                // Hex sequence in URIs
  325|  1.02k|                if( IsHex((&*it)[0]) && IsHex((&*it)[1]) ) {
  ------------------
  |  Branch (325:21): [True: 0, False: 1.02k]
  |  Branch (325:41): [True: 0, False: 0]
  ------------------
  326|      0|                    *it = HexOctetToDecimal(&*it);
  327|      0|                    it = in.erase(it+1,it+2);
  328|      0|                    --it;
  329|      0|                }
  330|  1.02k|            }
  331|       |
  332|  3.03M|            last = *it;
  333|  3.03M|        }
  334|  83.0k|    }
_ZN6Assimp5IsHexEc:
   56|  1.02k|inline bool IsHex(char s) {
   57|  1.02k|    return (s>='0' && s<='9') || (s>='a' && s<='f') || (s>='A' && s<='F');
  ------------------
  |  Branch (57:13): [True: 0, False: 1.02k]
  |  Branch (57:23): [True: 0, False: 0]
  |  Branch (57:35): [True: 0, False: 1.02k]
  |  Branch (57:45): [True: 0, False: 0]
  |  Branch (57:57): [True: 0, False: 1.02k]
  |  Branch (57:67): [True: 0, False: 0]
  ------------------
   58|  1.02k|}
_ZNK6Assimp16FileSystemFilter14getOsSeparatorEv:
  116|   106k|    char getOsSeparator() const {
  117|   106k|        return mSep;
  118|   106k|    }
_ZN6Assimp16FileSystemFilter4OpenEPKcS2_:
  122|  20.8k|    IOStream* Open( const char* pFile, const char* pMode = "rb") {
  123|  20.8k|        ai_assert( nullptr != mWrapped );
  124|  20.8k|        if ( nullptr == pFile || nullptr == pMode ) {
  ------------------
  |  Branch (124:14): [True: 0, False: 20.8k]
  |  Branch (124:34): [True: 0, False: 20.8k]
  ------------------
  125|      0|            return nullptr;
  126|      0|        }
  127|       |
  128|  20.8k|        ai_assert( nullptr != pFile );
  129|  20.8k|        ai_assert( nullptr != pMode );
  130|       |
  131|       |        // First try the unchanged path
  132|  20.8k|        IOStream* s = mWrapped->Open(pFile,pMode);
  133|       |
  134|  20.8k|        if (nullptr == s) {
  ------------------
  |  Branch (134:13): [True: 4.17k, False: 16.6k]
  ------------------
  135|  4.17k|            std::string tmp = pFile;
  136|       |
  137|       |            // Try to convert between absolute and relative paths
  138|  4.17k|            BuildPath(tmp);
  139|  4.17k|            s = mWrapped->Open(tmp,pMode);
  140|       |
  141|  4.17k|            if (nullptr == s) {
  ------------------
  |  Branch (141:17): [True: 4.15k, False: 18]
  ------------------
  142|       |                // Finally, look for typical issues with paths
  143|       |                // and try to correct them. This is our last
  144|       |                // resort.
  145|  4.15k|                tmp = pFile;
  146|  4.15k|                Cleanup(tmp);
  147|  4.15k|                BuildPath(tmp);
  148|  4.15k|                s = mWrapped->Open(tmp,pMode);
  149|  4.15k|            }
  150|  4.17k|        }
  151|       |
  152|  20.8k|        return s;
  153|  20.8k|    }
_ZN6Assimp16FileSystemFilter5CloseEPNS_8IOStreamE:
  157|    401|    void Close( IOStream* pFile) {
  158|       |        ai_assert( nullptr != mWrapped );
  159|    401|        return mWrapped->Close(pFile);
  160|    401|    }
_ZNK6Assimp16FileSystemFilter12ComparePathsEPKcS2_:
  164|   160k|    bool ComparePaths (const char* one, const char* second) const {
  165|       |        ai_assert( nullptr != mWrapped );
  166|   160k|        return mWrapped->ComparePaths (one,second);
  167|   160k|    }
_ZN6Assimp16FileSystemFilter13PushDirectoryERKNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEE:
  171|     34|    bool PushDirectory(const std::string &path ) {
  172|       |        ai_assert( nullptr != mWrapped );
  173|     34|        return mWrapped->PushDirectory(path);
  174|     34|    }
_ZNK6Assimp16FileSystemFilter16CurrentDirectoryEv:
  178|     12|    const std::string &CurrentDirectory() const {
  179|       |        ai_assert( nullptr != mWrapped );
  180|     12|        return mWrapped->CurrentDirectory();
  181|     12|    }
_ZNK6Assimp16FileSystemFilter9StackSizeEv:
  185|  4.75k|    size_t StackSize() const {
  186|       |        ai_assert( nullptr != mWrapped );
  187|  4.75k|        return mWrapped->StackSize();
  188|  4.75k|    }
_ZN6Assimp16FileSystemFilter12PopDirectoryEv:
  192|     28|    bool PopDirectory() {
  193|       |        ai_assert( nullptr != mWrapped );
  194|     28|        return mWrapped->PopDirectory();
  195|     28|    }
_ZN6Assimp16FileSystemFilterD2Ev:
   96|    582|    ~FileSystemFilter() = default;

_ZN6Assimp3IFF9LoadChunkERPh:
   63|    291|{
   64|    291|    ChunkHeader head;
   65|    291|    ::memcpy(&head.type, outFile, 4);
   66|    291|    outFile += 4;
   67|    291|    ::memcpy(&head.length, outFile, 4);
   68|    291|    outFile += 4;
   69|    291|    AI_LSWAP4(head.length);
   70|       |    AI_LSWAP4(head.type);
   71|    291|    return head;
   72|    291|}
_ZN6Assimp3IFF12LoadSubChunkERPh:
   80|    108|{
   81|    108|    SubChunkHeader head;
   82|    108|    ::memcpy(&head.type, outFile, 4);
   83|    108|    outFile += 4;
   84|    108|    ::memcpy(&head.length, outFile, 2);
   85|    108|    outFile += 2;
   86|    108|    AI_LSWAP2(head.length);
   87|       |    AI_LSWAP4(head.type);
   88|    108|    return head;
   89|    108|}
_ZN6Assimp3IFF10ReadHeaderEPhRj:
  117|     15|{
  118|     15|    ChunkHeader head = LoadChunk(outFile);
  119|     15|    if(AI_IFF_FOURCC_FORM != head.type)
  ------------------
  |  |   54|     15|#define AI_IFF_FOURCC_FORM AI_IFF_FOURCC('F','O','R','M')
  |  |  ------------------
  |  |  |  |   50|     15|#define AI_IFF_FOURCC(a,b,c,d) ((uint32_t) (((uint8_t)a << 24u) | \
  |  |  |  |   51|     15|    ((uint8_t)b << 16u) | ((uint8_t)c << 8u) | ((uint8_t)d)))
  |  |  ------------------
  ------------------
  |  Branch (119:8): [True: 0, False: 15]
  ------------------
  120|      0|    {
  121|      0|        return "The file is not an IFF file: FORM chunk is missing";
  122|      0|    }
  123|     15|    ::memcpy(&fileType, outFile, 4);
  124|       |    AI_LSWAP4(fileType);
  125|     15|    return nullptr;
  126|     15|}

_ZNK6Assimp8IOSystem16CurrentDirectoryEv:
   47|      6|const std::string &IOSystem::CurrentDirectory() const {
   48|      6|    if ( m_pathStack.empty() ) {
  ------------------
  |  Branch (48:10): [True: 0, False: 6]
  ------------------
   49|      0|        static const std::string Dummy = std::string();
   50|      0|        return Dummy;
   51|      0|    }
   52|      6|    return m_pathStack[ m_pathStack.size()-1 ];
   53|      6|}

_ZN6Assimp6Intern22AllocateFromAssimpHeapnwEm:
  114|  23.1k|void* AllocateFromAssimpHeap::operator new ( size_t num_bytes)  {
  115|  23.1k|    return ::operator new(num_bytes);
  116|  23.1k|}
_ZN6Assimp6Intern22AllocateFromAssimpHeapdlEPv:
  127|  23.1k|void AllocateFromAssimpHeap::operator delete ( void* data)  {
  128|  23.1k|    return ::operator delete(data);
  129|  23.1k|}
_ZN6Assimp8ImporterC2Ev:
  150|    624| : pimpl( new ImporterPimpl ) {
  151|    624|    pimpl->mScene = nullptr;
  152|    624|    pimpl->mErrorString = std::string();
  153|       |
  154|       |    // Allocate a default IO handler
  155|    624|    pimpl->mIOHandler = new DefaultIOSystem;
  156|    624|    pimpl->mIsDefaultHandler = true;
  157|    624|    pimpl->bExtraVerbose     = false; // disable extra verbose mode by default
  158|       |
  159|    624|    pimpl->mProgressHandler = new DefaultProgressHandler();
  160|    624|    pimpl->mIsDefaultProgressHandler = true;
  161|       |
  162|    624|    GetImporterInstanceList(pimpl->mImporter);
  163|    624|    GetPostProcessingStepInstanceList(pimpl->mPostProcessingSteps);
  164|       |
  165|       |    // Allocate a SharedPostProcessInfo object and store pointers to it in all post-process steps in the list.
  166|    624|    pimpl->mPPShared = new SharedPostProcessInfo();
  167|    624|    for (std::vector<BaseProcess*>::iterator it =  pimpl->mPostProcessingSteps.begin();
  168|  21.2k|        it != pimpl->mPostProcessingSteps.end();
  ------------------
  |  Branch (168:9): [True: 20.5k, False: 624]
  ------------------
  169|  20.5k|        ++it)   {
  170|       |
  171|  20.5k|        (*it)->SetSharedData(pimpl->mPPShared);
  172|  20.5k|    }
  173|    624|}
_ZN6Assimp8ImporterD2Ev:
  177|    624|Importer::~Importer() {
  178|       |    // Delete all import plugins
  179|    624|	DeleteImporterInstanceList(pimpl->mImporter);
  180|       |
  181|       |    // Delete all post-processing plug-ins
  182|  21.2k|    for( unsigned int a = 0; a < pimpl->mPostProcessingSteps.size(); ++a ) {
  ------------------
  |  Branch (182:30): [True: 20.5k, False: 624]
  ------------------
  183|  20.5k|        delete pimpl->mPostProcessingSteps[a];
  184|  20.5k|    }
  185|       |
  186|       |    // Delete the assigned IO and progress handler
  187|    624|    delete pimpl->mIOHandler;
  188|    624|    delete pimpl->mProgressHandler;
  189|       |
  190|       |    // Kill imported scene. Destructor's should do that recursively
  191|    624|    delete pimpl->mScene;
  192|       |
  193|       |    // Delete shared post-processing data
  194|    624|    delete pimpl->mPPShared;
  195|       |
  196|       |    // and finally the pimpl itself
  197|    624|    delete pimpl;
  198|    624|}
_ZN6Assimp8Importer12SetIOHandlerEPNS_8IOSystemE:
  297|  1.24k|void Importer::SetIOHandler( IOSystem* pIOHandler) {
  298|  1.24k|    ai_assert(nullptr != pimpl);
  299|       |
  300|  1.24k|    ASSIMP_BEGIN_EXCEPTION_REGION();
  301|       |    // If the new handler is zero, allocate a default IO implementation.
  302|  1.24k|    if (!pIOHandler) {
  ------------------
  |  Branch (302:9): [True: 155, False: 1.09k]
  ------------------
  303|       |        // Release pointer in the possession of the caller
  304|    155|        pimpl->mIOHandler = new DefaultIOSystem();
  305|    155|        pimpl->mIsDefaultHandler = true;
  306|  1.09k|    } else if (pimpl->mIOHandler != pIOHandler) { // Otherwise register the custom handler
  ------------------
  |  Branch (306:16): [True: 1.09k, False: 0]
  ------------------
  307|  1.09k|        delete pimpl->mIOHandler;
  308|  1.09k|        pimpl->mIOHandler = pIOHandler;
  309|  1.09k|        pimpl->mIsDefaultHandler = false;
  310|  1.09k|    }
  311|  1.24k|    ASSIMP_END_EXCEPTION_REGION(void);
  312|  1.24k|}
_ZNK6Assimp8Importer18GetProgressHandlerEv:
  352|  4.01k|ProgressHandler* Importer::GetProgressHandler() const {
  353|  4.01k|    ai_assert(nullptr != pimpl);
  354|       |
  355|  4.01k|    return pimpl->mProgressHandler;
  356|  4.01k|}
_Z14_ValidateFlagsj:
  368|    217|bool _ValidateFlags(unsigned int pFlags) {
  369|    217|    if (pFlags & aiProcess_GenSmoothNormals && pFlags & aiProcess_GenNormals)   {
  ------------------
  |  Branch (369:9): [True: 217, False: 0]
  |  Branch (369:48): [True: 0, False: 217]
  ------------------
  370|      0|        ASSIMP_LOG_ERROR("#aiProcess_GenSmoothNormals and #aiProcess_GenNormals are incompatible");
  371|      0|        return false;
  372|      0|    }
  373|    217|    if (pFlags & aiProcess_OptimizeGraph && pFlags & aiProcess_PreTransformVertices)    {
  ------------------
  |  Branch (373:9): [True: 0, False: 217]
  |  Branch (373:45): [True: 0, False: 0]
  ------------------
  374|      0|        ASSIMP_LOG_ERROR("#aiProcess_OptimizeGraph and #aiProcess_PreTransformVertices are incompatible");
  375|      0|        return false;
  376|      0|    }
  377|    217|    return true;
  378|    217|}
_ZN6Assimp8Importer16GetOrphanedSceneEv:
  429|    440|aiScene* Importer::GetOrphanedScene() {
  430|    440|    ai_assert(nullptr != pimpl);
  431|       |
  432|    440|    aiScene* s = pimpl->mScene;
  433|       |
  434|    440|    ASSIMP_BEGIN_EXCEPTION_REGION();
  435|    440|    pimpl->mScene = nullptr;
  436|       |
  437|    440|    pimpl->mErrorString = std::string();
  438|    440|    pimpl->mException = std::exception_ptr();
  439|    440|    ASSIMP_END_EXCEPTION_REGION(aiScene*);
  440|       |
  441|      0|    return s;
  442|    440|}
_ZN6Assimp8Importer18ReadFileFromMemoryEPKvmjPKc:
  485|    469|const aiScene* Importer::ReadFileFromMemory(const void* pBuffer, size_t pLength, unsigned int pFlags, const char* pHint ) {
  486|    469|    ai_assert(nullptr != pimpl);
  487|       |
  488|    469|    IOSystem* io = pimpl->mIOHandler;
  489|    469|    try {
  490|    469|        if (pHint == nullptr) {
  ------------------
  |  Branch (490:13): [True: 469, False: 0]
  ------------------
  491|    469|            pHint = "";
  492|    469|        }
  493|    469|        if (!pBuffer || !pLength || strlen(pHint) > MaxLenHint ) {
  ------------------
  |  Branch (493:13): [True: 0, False: 469]
  |  Branch (493:25): [True: 0, False: 469]
  |  Branch (493:37): [True: 0, False: 469]
  ------------------
  494|      0|            pimpl->mErrorString = "Invalid parameters passed to ReadFileFromMemory()";
  495|      0|            return nullptr;
  496|      0|        }
  497|       |        // prevent deletion of the previous IOHandler
  498|    469|        pimpl->mIOHandler = nullptr;
  499|       |
  500|    469|        SetIOHandler(new MemoryIOSystem((const uint8_t*)pBuffer,pLength,io));
  501|       |
  502|       |        // read the file and recover the previous IOSystem
  503|    469|        static const size_t BufSize(Importer::MaxLenHint + 28);
  504|    469|        char fbuff[BufSize];
  505|    469|        ai_snprintf(fbuff, BufSize, "%s.%s",AI_MEMORYIO_MAGIC_FILENAME,pHint);
  506|       |
  507|    469|        ReadFile(fbuff,pFlags);
  508|    469|        SetIOHandler(io);
  509|    469|    } catch(const DeadlyImportError &e) {
  510|      0|        pimpl->mErrorString = e.what();
  511|      0|        pimpl->mException = std::current_exception();
  512|      0|        SetIOHandler(io);
  513|      0|        return ExceptionSwallower<const aiScene*>()();                                                                                                    \
  514|      0|    } catch(...) {
  515|      0|        pimpl->mErrorString = "Unknown exception";
  516|      0|        pimpl->mException = std::current_exception();
  517|      0|        SetIOHandler(io);
  518|      0|        return ExceptionSwallower<const aiScene*>()();                                                                                                    \
  519|      0|
  520|      0|    }
  521|       |
  522|    469|    return pimpl->mScene;
  523|    469|}
_Z15WriteLogOpeningRKNSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEEE:
  526|    909|void WriteLogOpening(const std::string& file) {
  527|       |
  528|    909|    ASSIMP_LOG_INFO("Load ", file);
  529|       |
  530|       |    // print a full version dump. This is nice because we don't
  531|       |    // need to ask the authors of incoming bug reports for
  532|       |    // the library version they're using - a log dump is
  533|       |    // sufficient.
  534|    909|    const unsigned int flags = aiGetCompileFlags();
  535|    909|    std::stringstream stream;
  536|    909|    stream << "Assimp " << aiGetVersionMajor() << "." << aiGetVersionMinor() << "." << aiGetVersionRevision() << " "
  537|       |#if defined(ASSIMP_BUILD_ARCHITECTURE)
  538|       |           << ASSIMP_BUILD_ARCHITECTURE
  539|       |#elif defined(_M_IX86) || defined(__x86_32__) || defined(__i386__)
  540|       |           << "x86"
  541|       |#elif defined(_M_X64) || defined(__x86_64__)
  542|       |           << "amd64"
  543|       |#elif defined(_M_IA64) || defined(__ia64__)
  544|       |           << "itanium"
  545|       |#elif defined(__ppc__) || defined(__powerpc__)
  546|       |           << "ppc32"
  547|       |#elif defined(__powerpc64__)
  548|       |           << "ppc64"
  549|       |#elif defined(__arm__)
  550|       |           << "arm"
  551|       |#else
  552|       |           << "<unknown architecture>"
  553|       |#endif
  554|    909|           << " "
  555|       |#if defined(ASSIMP_BUILD_COMPILER)
  556|       |           << (ASSIMP_BUILD_COMPILER)
  557|       |#elif defined(_MSC_VER)
  558|       |           << "msvc"
  559|       |#elif defined(__GNUC__)
  560|       |           << "gcc"
  561|       |#elif defined(__clang__)
  562|       |           << "clang"
  563|       |#elif defined(__EMSCRIPTEN__)
  564|       |           << "emscripten"
  565|       |#elif defined(__MINGW32__)
  566|       |           << "MinGW-w64 32bit"
  567|       |#elif defined(__MINGW64__)
  568|       |           << "MinGW-w64 64bit"
  569|       |#else
  570|       |           << "<unknown compiler>"
  571|       |#endif
  572|       |
  573|    909|#ifdef ASSIMP_BUILD_DEBUG
  574|    909|           << " debug"
  575|    909|#endif
  576|       |
  577|    909|           << (flags & ASSIMP_CFLAGS_NOBOOST ? " noboost" : "")
  ------------------
  |  |  105|    909|#define ASSIMP_CFLAGS_NOBOOST           0x8
  ------------------
  |  Branch (577:16): [True: 0, False: 909]
  ------------------
  578|    909|           << (flags & ASSIMP_CFLAGS_SHARED ? " shared" : "")
  ------------------
  |  |   98|    909|#define ASSIMP_CFLAGS_SHARED  0x1
  ------------------
  |  Branch (578:16): [True: 0, False: 909]
  ------------------
  579|    909|           << (flags & ASSIMP_CFLAGS_SINGLETHREADED ? " singlethreaded" : "")
  ------------------
  |  |  107|    909|#define ASSIMP_CFLAGS_SINGLETHREADED    0x10
  ------------------
  |  Branch (579:16): [True: 909, False: 0]
  ------------------
  580|    909|           << (flags & ASSIMP_CFLAGS_DOUBLE_SUPPORT ? " double : " : "single : ");
  ------------------
  |  |  109|    909|#define ASSIMP_CFLAGS_DOUBLE_SUPPORT 0x20
  ------------------
  |  Branch (580:16): [True: 0, False: 909]
  ------------------
  581|       |
  582|       |    ASSIMP_LOG_DEBUG(stream.str());
  583|    909|}
_ZN6Assimp8Importer8ReadFileEPKcj:
  587|    909|const aiScene* Importer::ReadFile( const char* _pFile, unsigned int pFlags) {
  588|    909|    ai_assert(nullptr != pimpl);
  589|       |
  590|    909|    ASSIMP_BEGIN_EXCEPTION_REGION();
  591|    909|    const std::string pFile(_pFile);
  592|       |
  593|       |    // ----------------------------------------------------------------------
  594|       |    // Put a large try block around everything to catch all std::exception's
  595|       |    // that might be thrown by STL containers or by new().
  596|       |    // ImportErrorException's are throw by ourselves and caught elsewhere.
  597|       |    //-----------------------------------------------------------------------
  598|       |
  599|    909|    WriteLogOpening(pFile);
  600|       |
  601|       |#ifdef ASSIMP_CATCH_GLOBAL_EXCEPTIONS
  602|       |    try
  603|       |#endif // ! ASSIMP_CATCH_GLOBAL_EXCEPTIONS
  604|    909|    {
  605|       |        // Check whether this Importer instance has already loaded
  606|       |        // a scene. In this case we need to delete the old one
  607|    909|        if (pimpl->mScene)  {
  ------------------
  |  Branch (607:13): [True: 0, False: 909]
  ------------------
  608|       |
  609|      0|            ASSIMP_LOG_DEBUG("(Deleting previous scene)");
  610|      0|            FreeScene();
  611|      0|        }
  612|       |
  613|       |        // First check if the file is accessible at all
  614|    909|        if( !pimpl->mIOHandler->Exists( pFile)) {
  ------------------
  |  Branch (614:13): [True: 275, False: 634]
  ------------------
  615|       |
  616|    275|            pimpl->mErrorString = "Unable to open file \"" + pFile + "\".";
  617|    275|            ASSIMP_LOG_ERROR(pimpl->mErrorString);
  618|    275|            return nullptr;
  619|    275|        }
  620|       |
  621|    634|        std::unique_ptr<Profiler> profiler(GetPropertyInteger(AI_CONFIG_GLOB_MEASURE_TIME, 0) ? new Profiler() : nullptr);
  ------------------
  |  Branch (621:44): [True: 0, False: 634]
  ------------------
  622|    634|        if (profiler) {
  ------------------
  |  Branch (622:13): [True: 0, False: 634]
  ------------------
  623|      0|            profiler->BeginRegion("total");
  624|      0|        }
  625|       |
  626|       |        // Find an worker class which can handle the file extension.
  627|       |        // Multiple importers may be able to handle the same extension (.xml!); gather them all.
  628|    634|        SetPropertyInteger("importerIndex", -1);
  629|    634|        struct ImporterAndIndex {
  630|    634|            BaseImporter * importer;
  631|    634|            unsigned int   index;
  632|    634|        };
  633|    634|        std::vector<ImporterAndIndex> possibleImporters;
  634|  31.0k|        for (unsigned int a = 0; a < pimpl->mImporter.size(); a++)  {
  ------------------
  |  Branch (634:34): [True: 30.4k, False: 634]
  ------------------
  635|       |
  636|       |            // Every importer has a list of supported extensions.
  637|  30.4k|            std::set<std::string> extensions;
  638|  30.4k|            pimpl->mImporter[a]->GetExtensionList(extensions);
  639|       |
  640|  30.4k|            if (BaseImporter::HasExtension(pFile, extensions)) {
  ------------------
  |  Branch (640:17): [True: 62, False: 30.3k]
  ------------------
  641|     62|                ImporterAndIndex candidate = { pimpl->mImporter[a], a };
  642|     62|                possibleImporters.push_back(candidate);
  643|     62|            }
  644|  30.4k|        }
  645|       |
  646|       |        // If just one importer supports this extension, pick it and close the case.
  647|    634|        BaseImporter* imp = nullptr;
  648|    634|        if (1 == possibleImporters.size()) {
  ------------------
  |  Branch (648:13): [True: 62, False: 572]
  ------------------
  649|     62|            imp = possibleImporters[0].importer;
  650|     62|            SetPropertyInteger("importerIndex", possibleImporters[0].index);
  651|     62|        }
  652|       |        // If multiple importers claim this file extension, ask them to look at the actual file data to decide.
  653|       |        // This can happen e.g. with XML (COLLADA vs. Irrlicht).
  654|    572|        else {
  655|    572|            for (std::vector<ImporterAndIndex>::const_iterator it = possibleImporters.begin(); it < possibleImporters.end(); ++it) {
  ------------------
  |  Branch (655:96): [True: 0, False: 572]
  ------------------
  656|      0|                BaseImporter & importer = *it->importer;
  657|       |
  658|      0|                ASSIMP_LOG_INFO("Found a possible importer: " + std::string(importer.GetInfo()->mName) + "; trying signature-based detection");
  659|      0|                if (importer.CanRead( pFile, pimpl->mIOHandler, true)) {
  ------------------
  |  Branch (659:21): [True: 0, False: 0]
  ------------------
  660|      0|                    imp = &importer;
  661|      0|                    SetPropertyInteger("importerIndex", it->index);
  662|      0|                    break;
  663|      0|                }
  664|       |
  665|      0|            }
  666|       |
  667|    572|        }
  668|       |
  669|    634|        if (!imp)   {
  ------------------
  |  Branch (669:13): [True: 572, False: 62]
  ------------------
  670|       |            // not so bad yet ... try format auto detection.
  671|    572|            ASSIMP_LOG_INFO("File extension not known, trying signature-based detection");
  672|  13.3k|            for( unsigned int a = 0; a < pimpl->mImporter.size(); a++)  {
  ------------------
  |  Branch (672:38): [True: 13.3k, False: 52]
  ------------------
  673|  13.3k|                if( pimpl->mImporter[a]->CanRead( pFile, pimpl->mIOHandler, true)) {
  ------------------
  |  Branch (673:21): [True: 520, False: 12.8k]
  ------------------
  674|    520|                    imp = pimpl->mImporter[a];
  675|    520|                    SetPropertyInteger("importerIndex", a);
  676|    520|                    break;
  677|    520|                }
  678|  13.3k|            }
  679|       |            // Put a proper error message if no suitable importer was found
  680|    572|            if( !imp)   {
  ------------------
  |  Branch (680:17): [True: 42, False: 530]
  ------------------
  681|     42|                pimpl->mErrorString = "No suitable reader found for the file format of file \"" + pFile + "\".";
  682|     42|                ASSIMP_LOG_ERROR(pimpl->mErrorString);
  683|     42|                return nullptr;
  684|     42|            }
  685|    572|        }
  686|       |
  687|       |        // Get file size for progress handler
  688|    592|        IOStream * fileIO = pimpl->mIOHandler->Open( pFile );
  689|    592|        uint32_t fileSize = 0;
  690|    592|        if (fileIO)
  ------------------
  |  Branch (690:13): [True: 582, False: 10]
  ------------------
  691|    582|        {
  692|    582|            fileSize = static_cast<uint32_t>(fileIO->FileSize());
  693|    582|            pimpl->mIOHandler->Close( fileIO );
  694|    582|        }
  695|       |
  696|       |        // Dispatch the reading to the worker class for this format
  697|    592|        const aiImporterDesc *desc( imp->GetInfo() );
  698|    592|        std::string ext( "unknown" );
  699|    592|        if ( nullptr != desc ) {
  ------------------
  |  Branch (699:14): [True: 582, False: 10]
  ------------------
  700|    582|            ext = desc->mName;
  701|    582|        }
  702|    592|        ASSIMP_LOG_INFO("Found a matching importer for this file format: ", ext, "." );
  703|    592|        pimpl->mProgressHandler->UpdateFileRead( 0, fileSize );
  704|       |
  705|    592|        if (profiler) {
  ------------------
  |  Branch (705:13): [True: 0, False: 592]
  ------------------
  706|      0|            profiler->BeginRegion("import");
  707|      0|        }
  708|       |
  709|    592|        pimpl->mScene = imp->ReadFile( this, pFile, pimpl->mIOHandler);
  710|    592|        pimpl->mProgressHandler->UpdateFileRead( fileSize, fileSize );
  711|       |
  712|    592|        if (profiler) {
  ------------------
  |  Branch (712:13): [True: 0, False: 592]
  ------------------
  713|      0|            profiler->EndRegion("import");
  714|      0|        }
  715|       |
  716|    592|        SetPropertyString("sourceFilePath", pFile);
  717|       |
  718|       |        // If successful, apply all active post processing steps to the imported data
  719|    592|        if( pimpl->mScene)  {
  ------------------
  |  Branch (719:13): [True: 290, False: 302]
  ------------------
  720|    290|            if (!pimpl->mScene->mMetaData || !pimpl->mScene->mMetaData->HasKey(AI_METADATA_SOURCE_FORMAT)) {
  ------------------
  |  Branch (720:17): [True: 273, False: 17]
  |  Branch (720:46): [True: 17, False: 0]
  ------------------
  721|    290|                if (!pimpl->mScene->mMetaData) {
  ------------------
  |  Branch (721:21): [True: 273, False: 17]
  ------------------
  722|    273|                    pimpl->mScene->mMetaData = new aiMetadata;
  723|    273|                }
  724|    290|                pimpl->mScene->mMetaData->Add(AI_METADATA_SOURCE_FORMAT, aiString(ext));
  725|    290|            }
  726|       |
  727|    290|#ifndef ASSIMP_BUILD_NO_VALIDATEDS_PROCESS
  728|       |            // The ValidateDS process is an exception. It is executed first, even before ScenePreprocessor is called.
  729|    290|            if (pFlags & aiProcess_ValidateDataStructure) {
  ------------------
  |  Branch (729:17): [True: 266, False: 24]
  ------------------
  730|    266|                ValidateDSProcess ds;
  731|    266|                ds.ExecuteOnScene (this);
  732|    266|                if (!pimpl->mScene) {
  ------------------
  |  Branch (732:21): [True: 49, False: 217]
  ------------------
  733|     49|                    return nullptr;
  734|     49|                }
  735|    266|            }
  736|    241|#endif // ASSIMP_BUILD_NO_VALIDATEDS_PROCESS
  737|       |
  738|       |            // Preprocess the scene and prepare it for post-processing
  739|    241|            if (profiler) {
  ------------------
  |  Branch (739:17): [True: 0, False: 241]
  ------------------
  740|      0|                profiler->BeginRegion("preprocess");
  741|      0|            }
  742|       |
  743|    241|            ScenePreprocessor pre(pimpl->mScene);
  744|    241|            pre.ProcessScene();
  745|       |
  746|    241|            if (profiler) {
  ------------------
  |  Branch (746:17): [True: 0, False: 241]
  ------------------
  747|      0|                profiler->EndRegion("preprocess");
  748|      0|            }
  749|       |
  750|       |            // Ensure that the validation process won't be called twice
  751|    241|            ApplyPostProcessing(pFlags & (~aiProcess_ValidateDataStructure));
  752|    241|        }
  753|       |        // if failed, extract the error string
  754|    302|        else if( !pimpl->mScene) {
  ------------------
  |  Branch (754:18): [True: 292, False: 10]
  ------------------
  755|    292|            pimpl->mErrorString = imp->GetErrorText();
  756|    292|            pimpl->mException = imp->GetException();
  757|    292|        }
  758|       |
  759|       |        // clear any data allocated by post-process steps
  760|    543|        pimpl->mPPShared->Clean();
  761|       |
  762|    543|        if (profiler) {
  ------------------
  |  Branch (762:13): [True: 0, False: 543]
  ------------------
  763|      0|            profiler->EndRegion("total");
  764|      0|        }
  765|    543|    }
  766|       |#ifdef ASSIMP_CATCH_GLOBAL_EXCEPTIONS
  767|       |    catch (std::exception &e) {
  768|       |#if (defined _MSC_VER) &&   (defined _CPPRTTI)
  769|       |        // if we have RTTI get the full name of the exception that occurred
  770|       |        pimpl->mErrorString = std::string(typeid( e ).name()) + ": " + e.what();
  771|       |#else
  772|       |        pimpl->mErrorString = std::string("std::exception: ") + e.what();
  773|       |#endif
  774|       |        pimpl->mException = std::current_exception();
  775|       |
  776|       |        ASSIMP_LOG_ERROR(pimpl->mErrorString);
  777|       |        delete pimpl->mScene; pimpl->mScene = nullptr;
  778|       |    }
  779|       |#endif // ! ASSIMP_CATCH_GLOBAL_EXCEPTIONS
  780|       |
  781|       |    // either successful or failure - the pointer expresses it anyways
  782|    543|    ASSIMP_END_EXCEPTION_REGION_WITH_ERROR_STRING(const aiScene*, pimpl->mErrorString, pimpl->mException);
  783|       |
  784|    533|    return pimpl->mScene;
  785|    909|}
_ZN6Assimp8Importer19ApplyPostProcessingEj:
  790|    241|const aiScene* Importer::ApplyPostProcessing(unsigned int pFlags) {
  791|    241|    ai_assert(nullptr != pimpl);
  792|       |
  793|    241|    ASSIMP_BEGIN_EXCEPTION_REGION();
  794|       |    // Return immediately if no scene is active
  795|    241|    if (!pimpl->mScene) {
  ------------------
  |  Branch (795:9): [True: 0, False: 241]
  ------------------
  796|      0|        return nullptr;
  797|      0|    }
  798|       |
  799|       |    // If no flags are given, return the current scene with no further action
  800|    241|    if (!pFlags) {
  ------------------
  |  Branch (800:9): [True: 24, False: 217]
  ------------------
  801|     24|        return pimpl->mScene;
  802|     24|    }
  803|       |
  804|       |    // In debug builds: run basic flag validation
  805|    241|    ai_assert(_ValidateFlags(pFlags));
  806|    217|    ASSIMP_LOG_INFO("Entering post processing pipeline");
  807|       |
  808|    217|#ifndef ASSIMP_BUILD_NO_VALIDATEDS_PROCESS
  809|       |    // The ValidateDS process plays an exceptional role. It isn't contained in the global
  810|       |    // list of post-processing steps, so we need to call it manually.
  811|    217|    if (pFlags & aiProcess_ValidateDataStructure) {
  ------------------
  |  Branch (811:9): [True: 0, False: 217]
  ------------------
  812|      0|        ValidateDSProcess ds;
  813|      0|        ds.ExecuteOnScene (this);
  814|      0|        if (!pimpl->mScene) {
  ------------------
  |  Branch (814:13): [True: 0, False: 0]
  ------------------
  815|      0|            return nullptr;
  816|      0|        }
  817|      0|    }
  818|    217|#endif // no validation
  819|    217|#ifdef ASSIMP_BUILD_DEBUG
  820|    217|    if (pimpl->bExtraVerbose)
  ------------------
  |  Branch (820:9): [True: 0, False: 217]
  ------------------
  821|      0|    {
  822|       |#ifdef ASSIMP_BUILD_NO_VALIDATEDS_PROCESS
  823|       |        ASSIMP_LOG_ERROR("Verbose Import is not available due to build settings");
  824|       |#endif  // no validation
  825|      0|        pFlags |= aiProcess_ValidateDataStructure;
  826|      0|    }
  827|       |#else
  828|       |    if (pimpl->bExtraVerbose) {
  829|       |        ASSIMP_LOG_WARN("Not a debug build, ignoring extra verbose setting");
  830|       |    }
  831|       |#endif // ! DEBUG
  832|       |
  833|    217|    std::unique_ptr<Profiler> profiler(GetPropertyInteger(AI_CONFIG_GLOB_MEASURE_TIME, 0) ? new Profiler() : nullptr);
  ------------------
  |  Branch (833:40): [True: 0, False: 217]
  ------------------
  834|  7.22k|    for( unsigned int a = 0; a < pimpl->mPostProcessingSteps.size(); a++)   {
  ------------------
  |  Branch (834:30): [True: 7.01k, False: 208]
  ------------------
  835|  7.01k|        BaseProcess* process = pimpl->mPostProcessingSteps[a];
  836|  7.01k|        pimpl->mProgressHandler->UpdatePostProcess(static_cast<int>(a), static_cast<int>(pimpl->mPostProcessingSteps.size()) );
  837|  7.01k|        if( process->IsActive( pFlags)) {
  ------------------
  |  Branch (837:13): [True: 3.17k, False: 3.84k]
  ------------------
  838|  3.17k|            if (profiler) {
  ------------------
  |  Branch (838:17): [True: 0, False: 3.17k]
  ------------------
  839|      0|                profiler->BeginRegion("postprocess");
  840|      0|            }
  841|       |
  842|  3.17k|            process->ExecuteOnScene ( this );
  843|       |
  844|  3.17k|            if (profiler) {
  ------------------
  |  Branch (844:17): [True: 0, False: 3.17k]
  ------------------
  845|      0|                profiler->EndRegion("postprocess");
  846|      0|            }
  847|  3.17k|        }
  848|  7.01k|        if( !pimpl->mScene) {
  ------------------
  |  Branch (848:13): [True: 9, False: 7.00k]
  ------------------
  849|      9|            break;
  850|      9|        }
  851|  7.00k|#ifdef ASSIMP_BUILD_DEBUG
  852|  7.00k|#ifndef ASSIMP_BUILD_NO_VALIDATEDS_PROCESS
  853|       |        // If the extra verbose mode is active, execute the ValidateDataStructureStep again - after each step
  854|  7.00k|        if (pimpl->bExtraVerbose)   {
  ------------------
  |  Branch (854:13): [True: 0, False: 7.00k]
  ------------------
  855|      0|            ASSIMP_LOG_DEBUG("Verbose Import: re-validating data structures");
  856|       |
  857|      0|            ValidateDSProcess ds;
  858|      0|            ds.ExecuteOnScene (this);
  859|      0|            if( !pimpl->mScene) {
  ------------------
  |  Branch (859:17): [True: 0, False: 0]
  ------------------
  860|      0|                ASSIMP_LOG_ERROR("Verbose Import: failed to re-validate data structures");
  861|      0|                break;
  862|      0|            }
  863|      0|        }
  864|  7.00k|#endif  // no validation
  865|  7.00k|#endif // ! DEBUG
  866|  7.00k|    }
  867|    217|    pimpl->mProgressHandler->UpdatePostProcess( static_cast<int>(pimpl->mPostProcessingSteps.size()),
  868|    217|        static_cast<int>(pimpl->mPostProcessingSteps.size()) );
  869|       |
  870|       |    // update private scene flags
  871|    217|    if( pimpl->mScene ) {
  ------------------
  |  Branch (871:9): [True: 208, False: 9]
  ------------------
  872|    208|      ScenePriv(pimpl->mScene)->mPPStepsApplied |= pFlags;
  873|    208|    }
  874|       |
  875|       |    // clear any data allocated by post-process steps
  876|    217|    pimpl->mPPShared->Clean();
  877|    217|    ASSIMP_LOG_INFO("Leaving post processing pipeline");
  878|       |
  879|    217|    ASSIMP_END_EXCEPTION_REGION(const aiScene*);
  880|       |
  881|    217|    return pimpl->mScene;
  882|    241|}
_ZN6Assimp8Importer18SetPropertyIntegerEPKci:
 1063|  1.21k|bool Importer::SetPropertyInteger(const char* szName, int iValue) {
 1064|  1.21k|    ai_assert(nullptr != pimpl);
 1065|       |
 1066|  1.21k|    bool existing;
 1067|  1.21k|    ASSIMP_BEGIN_EXCEPTION_REGION();
 1068|  1.21k|        existing = SetGenericProperty<int>(pimpl->mIntProperties, szName,iValue);
 1069|  1.21k|    ASSIMP_END_EXCEPTION_REGION(bool);
 1070|  1.21k|    return existing;
 1071|  1.21k|}
_ZN6Assimp8Importer16SetPropertyFloatEPKcf:
 1075|    290|bool Importer::SetPropertyFloat(const char* szName, ai_real iValue) {
 1076|    290|    ai_assert(nullptr != pimpl);
 1077|       |
 1078|    290|    bool existing;
 1079|    290|    ASSIMP_BEGIN_EXCEPTION_REGION();
 1080|    290|        existing = SetGenericProperty<ai_real>(pimpl->mFloatProperties, szName,iValue);
 1081|    290|    ASSIMP_END_EXCEPTION_REGION(bool);
 1082|    290|    return existing;
 1083|    290|}
_ZN6Assimp8Importer17SetPropertyStringEPKcRKNSt3__112basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEE:
 1087|    582|bool Importer::SetPropertyString(const char* szName, const std::string& value) {
 1088|    582|    ai_assert(nullptr != pimpl);
 1089|       |
 1090|    582|    bool existing;
 1091|    582|    ASSIMP_BEGIN_EXCEPTION_REGION();
 1092|    582|        existing = SetGenericProperty<std::string>(pimpl->mStringProperties, szName,value);
 1093|    582|    ASSIMP_END_EXCEPTION_REGION(bool);
 1094|    582|    return existing;
 1095|    582|}
_ZNK6Assimp8Importer18GetPropertyIntegerEPKci:
 1123|  4.14k|int Importer::GetPropertyInteger(const char* szName, int iErrorReturn /*= 0xffffffff*/) const {
 1124|  4.14k|    ai_assert(nullptr != pimpl);
 1125|       |
 1126|  4.14k|    return GetGenericProperty<int>(pimpl->mIntProperties,szName,iErrorReturn);
 1127|  4.14k|}
_ZNK6Assimp8Importer16GetPropertyFloatEPKcf:
 1131|    633|ai_real Importer::GetPropertyFloat(const char* szName, ai_real iErrorReturn /*= 10e10*/) const {
 1132|    633|    ai_assert(nullptr != pimpl);
 1133|       |
 1134|    633|    return GetGenericProperty<ai_real>(pimpl->mFloatProperties,szName,iErrorReturn);
 1135|    633|}
_ZNK6Assimp8Importer17GetPropertyStringEPKcRKNSt3__112basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEE:
 1139|    253|std::string Importer::GetPropertyString(const char* szName, const std::string& iErrorReturn /*= ""*/) const {
 1140|    253|    ai_assert(nullptr != pimpl);
 1141|       |
 1142|    253|    return GetGenericProperty<std::string>(pimpl->mStringProperties,szName,iErrorReturn);
 1143|    253|}
_ZNK6Assimp8Importer18GetPropertyPointerEPKcPv:
 1155|      5|void* Importer::GetPropertyPointer(const char* szName, void* iErrorReturn /*= nullptr*/) const {
 1156|      5|    ai_assert(nullptr != pimpl);
 1157|       |
 1158|      5|    return GetGenericProperty<void*>(pimpl->mPointerProperties,szName,iErrorReturn);
 1159|      5|}

_ZN6Assimp13ImporterPimplC2Ev:
  137|    624|        mIOHandler( nullptr ),
  138|    624|        mIsDefaultHandler( false ),
  139|    624|        mProgressHandler( nullptr ),
  140|    624|        mIsDefaultProgressHandler( false ),
  141|    624|        mImporter(),
  142|    624|        mPostProcessingSteps(),
  143|    624|        mScene( nullptr ),
  144|    624|        mErrorString(),
  145|    624|        mException(),
  146|    624|        mIntProperties(),
  147|    624|        mFloatProperties(),
  148|    624|        mStringProperties(),
  149|    624|        mMatrixProperties(),
  150|    624|        mPointerProperties(),
  151|    624|        bExtraVerbose( false ),
  152|    624|        mPPShared( nullptr ) {
  153|       |    // empty
  154|    624|}
_ZN6Assimp13ImporterPimplD2Ev:
  133|    624|    ~ImporterPimpl() = default;
_ZNK6Assimp11BatchLoader11PropertyMapeqERKS1_:
  179|  4.35k|        bool operator == (const PropertyMap& prop) const {
  180|       |            // fixme: really isocpp? gcc complains
  181|  4.35k|            return ints == prop.ints && floats == prop.floats && strings == prop.strings && matrices == prop.matrices;
  ------------------
  |  Branch (181:20): [True: 4.35k, False: 5]
  |  Branch (181:41): [True: 4.35k, False: 0]
  |  Branch (181:66): [True: 4.35k, False: 0]
  |  Branch (181:93): [True: 4.35k, False: 0]
  ------------------
  182|  4.35k|        }
_ZNK6Assimp11BatchLoader11PropertyMap5emptyEv:
  184|  11.8k|        bool empty () const {
  185|  11.8k|            return ints.empty() && floats.empty() && strings.empty() && matrices.empty();
  ------------------
  |  Branch (185:20): [True: 11.8k, False: 0]
  |  Branch (185:36): [True: 11.8k, False: 0]
  |  Branch (185:54): [True: 11.8k, False: 0]
  |  Branch (185:73): [True: 11.8k, False: 0]
  ------------------
  186|  11.8k|        }

_ZN6Assimp23GetImporterInstanceListERNSt3__16vectorIPNS_12BaseImporterENS0_9allocatorIS3_EEEE:
  215|    624|void GetImporterInstanceList(std::vector<BaseImporter *> &out) {
  216|       |
  217|       |    // Some importers may be unimplemented or otherwise unsuitable for general use
  218|       |    // in their current state. Devs can set ASSIMP_ENABLE_DEV_IMPORTERS in their
  219|       |    // local environment to enable them, otherwise they're left out of the registry.
  220|       |#if defined(WINAPI_FAMILY) && WINAPI_FAMILY == WINAPI_FAMILY_DESKTOP_APP
  221|       |    // not supported under uwp
  222|       |    const char *envStr = std::getenv("ASSIMP_ENABLE_DEV_IMPORTERS");
  223|       |#else
  224|    624|    const char *envStr = { "0" };
  225|    624|#endif
  226|    624|    bool devImportersEnabled = envStr && strcmp(envStr, "0");
  ------------------
  |  Branch (226:32): [True: 624, False: 0]
  |  Branch (226:42): [True: 0, False: 624]
  ------------------
  227|       |
  228|       |    // Ensure no unused var warnings if all uses are #ifndef'd away below:
  229|    624|    (void)devImportersEnabled;
  230|       |
  231|       |    // ----------------------------------------------------------------------------
  232|       |    // Add an instance of each worker class here
  233|       |    // (register_new_importers_here)
  234|       |    // ----------------------------------------------------------------------------
  235|    624|    out.reserve(64);
  236|       |#if !defined(ASSIMP_BUILD_NO_USD_IMPORTER)
  237|       |    out.push_back(new USDImporter());
  238|       |#endif
  239|    624|#if (!defined ASSIMP_BUILD_NO_X_IMPORTER)
  240|    624|    out.push_back(new XFileImporter());
  241|    624|#endif
  242|    624|#if (!defined ASSIMP_BUILD_NO_OBJ_IMPORTER)
  243|    624|    out.push_back(new ObjFileImporter());
  244|    624|#endif
  245|    624|#ifndef ASSIMP_BUILD_NO_AMF_IMPORTER
  246|    624|    out.push_back(new AMFImporter());
  247|    624|#endif
  248|    624|#if (!defined ASSIMP_BUILD_NO_3DS_IMPORTER)
  249|    624|    out.push_back(new Discreet3DSImporter());
  250|    624|#endif
  251|       |#if (!defined ASSIMP_BUILD_NO_M3D_IMPORTER)
  252|       |    out.push_back(new M3DImporter());
  253|       |#endif
  254|    624|#if (!defined ASSIMP_BUILD_NO_MD3_IMPORTER)
  255|    624|    out.push_back(new MD3Importer());
  256|    624|#endif
  257|    624|#if (!defined ASSIMP_BUILD_NO_MD2_IMPORTER)
  258|    624|    out.push_back(new MD2Importer());
  259|    624|#endif
  260|    624|#if (!defined ASSIMP_BUILD_NO_PLY_IMPORTER)
  261|    624|    out.push_back(new PLYImporter());
  262|    624|#endif
  263|    624|#if (!defined ASSIMP_BUILD_NO_MDL_IMPORTER)
  264|    624|    out.push_back(new MDLImporter());
  265|    624|#endif
  266|    624|#if (!defined ASSIMP_BUILD_NO_ASE_IMPORTER)
  267|    624|#if (!defined ASSIMP_BUILD_NO_3DS_IMPORTER)
  268|    624|    out.push_back(new ASEImporter());
  269|    624|#endif
  270|    624|#endif
  271|    624|#if (!defined ASSIMP_BUILD_NO_HMP_IMPORTER)
  272|    624|    out.push_back(new HMPImporter());
  273|    624|#endif
  274|    624|#if (!defined ASSIMP_BUILD_NO_SMD_IMPORTER)
  275|    624|    out.push_back(new SMDImporter());
  276|    624|#endif
  277|    624|#if (!defined ASSIMP_BUILD_NO_MDC_IMPORTER)
  278|    624|    out.push_back(new MDCImporter());
  279|    624|#endif
  280|    624|#if (!defined ASSIMP_BUILD_NO_MD5_IMPORTER)
  281|    624|    out.push_back(new MD5Importer());
  282|    624|#endif
  283|    624|#if (!defined ASSIMP_BUILD_NO_STL_IMPORTER)
  284|    624|    out.push_back(new STLImporter());
  285|    624|#endif
  286|    624|#if (!defined ASSIMP_BUILD_NO_LWO_IMPORTER)
  287|    624|    out.push_back(new LWOImporter());
  288|    624|#endif
  289|    624|#if (!defined ASSIMP_BUILD_NO_DXF_IMPORTER)
  290|    624|    out.push_back(new DXFImporter());
  291|    624|#endif
  292|    624|#if (!defined ASSIMP_BUILD_NO_NFF_IMPORTER)
  293|    624|    out.push_back(new NFFImporter());
  294|    624|#endif
  295|    624|#if (!defined ASSIMP_BUILD_NO_RAW_IMPORTER)
  296|    624|    out.push_back(new RAWImporter());
  297|    624|#endif
  298|    624|#if (!defined ASSIMP_BUILD_NO_SIB_IMPORTER)
  299|    624|    out.push_back(new SIBImporter());
  300|    624|#endif
  301|    624|#if (!defined ASSIMP_BUILD_NO_OFF_IMPORTER)
  302|    624|    out.push_back(new OFFImporter());
  303|    624|#endif
  304|    624|#if (!defined ASSIMP_BUILD_NO_AC_IMPORTER)
  305|    624|    out.push_back(new AC3DImporter());
  306|    624|#endif
  307|    624|#if (!defined ASSIMP_BUILD_NO_BVH_IMPORTER)
  308|    624|    out.push_back(new BVHLoader());
  309|    624|#endif
  310|    624|#if (!defined ASSIMP_BUILD_NO_IRRMESH_IMPORTER)
  311|    624|    out.push_back(new IRRMeshImporter());
  312|    624|#endif
  313|    624|#if (!defined ASSIMP_BUILD_NO_IRR_IMPORTER)
  314|    624|    out.push_back(new IRRImporter());
  315|    624|#endif
  316|    624|#if (!defined ASSIMP_BUILD_NO_Q3D_IMPORTER)
  317|    624|    out.push_back(new Q3DImporter());
  318|    624|#endif
  319|    624|#if (!defined ASSIMP_BUILD_NO_B3D_IMPORTER)
  320|    624|    out.push_back(new B3DImporter());
  321|    624|#endif
  322|    624|#if (!defined ASSIMP_BUILD_NO_COLLADA_IMPORTER)
  323|    624|    out.push_back(new ColladaLoader());
  324|    624|#endif
  325|    624|#if (!defined ASSIMP_BUILD_NO_TERRAGEN_IMPORTER)
  326|    624|    out.push_back(new TerragenImporter());
  327|    624|#endif
  328|    624|#if (!defined ASSIMP_BUILD_NO_CSM_IMPORTER)
  329|    624|    out.push_back(new CSMImporter());
  330|    624|#endif
  331|    624|#if (!defined ASSIMP_BUILD_NO_3D_IMPORTER)
  332|    624|    out.push_back(new UnrealImporter());
  333|    624|#endif
  334|    624|#if (!defined ASSIMP_BUILD_NO_LWS_IMPORTER)
  335|    624|    out.push_back(new LWSImporter());
  336|    624|#endif
  337|    624|#if (!defined ASSIMP_BUILD_NO_OGRE_IMPORTER)
  338|    624|    out.push_back(new Ogre::OgreImporter());
  339|    624|#endif
  340|    624|#if (!defined ASSIMP_BUILD_NO_OPENGEX_IMPORTER)
  341|    624|    out.push_back(new OpenGEX::OpenGEXImporter());
  342|    624|#endif
  343|    624|#if (!defined ASSIMP_BUILD_NO_MS3D_IMPORTER)
  344|    624|    out.push_back(new MS3DImporter());
  345|    624|#endif
  346|    624|#if (!defined ASSIMP_BUILD_NO_COB_IMPORTER)
  347|    624|    out.push_back(new COBImporter());
  348|    624|#endif
  349|    624|#if (!defined ASSIMP_BUILD_NO_BLEND_IMPORTER)
  350|    624|    out.push_back(new BlenderImporter());
  351|    624|#endif
  352|    624|#if (!defined ASSIMP_BUILD_NO_Q3BSP_IMPORTER)
  353|    624|    out.push_back(new Q3BSPFileImporter());
  354|    624|#endif
  355|    624|#if (!defined ASSIMP_BUILD_NO_NDO_IMPORTER)
  356|    624|    out.push_back(new NDOImporter());
  357|    624|#endif
  358|    624|#if (!defined ASSIMP_BUILD_NO_IFC_IMPORTER)
  359|    624|    out.push_back(new IFCImporter());
  360|    624|#endif
  361|    624|#if (!defined ASSIMP_BUILD_NO_XGL_IMPORTER)
  362|    624|    out.push_back(new XGLImporter());
  363|    624|#endif
  364|    624|#if (!defined ASSIMP_BUILD_NO_FBX_IMPORTER)
  365|    624|    out.push_back(new FBXImporter());
  366|    624|#endif
  367|    624|#if (!defined ASSIMP_BUILD_NO_ASSBIN_IMPORTER)
  368|    624|    out.push_back(new AssbinImporter());
  369|    624|#endif
  370|    624|#if (!defined ASSIMP_BUILD_NO_GLTF_IMPORTER && !defined ASSIMP_BUILD_NO_GLTF1_IMPORTER)
  371|    624|    out.push_back(new glTFImporter());
  372|    624|#endif
  373|    624|#if (!defined ASSIMP_BUILD_NO_GLTF_IMPORTER && !defined ASSIMP_BUILD_NO_GLTF2_IMPORTER)
  374|    624|    out.push_back(new glTF2Importer());
  375|    624|#endif
  376|       |#if (!defined ASSIMP_BUILD_NO_C4D_IMPORTER)
  377|       |    out.push_back(new C4DImporter());
  378|       |#endif
  379|    624|#if (!defined ASSIMP_BUILD_NO_3MF_IMPORTER)
  380|    624|    out.push_back(new D3MFImporter());
  381|    624|#endif
  382|    624|#ifndef ASSIMP_BUILD_NO_X3D_IMPORTER
  383|    624|    out.push_back(new X3DImporter());
  384|    624|#endif
  385|    624|#ifndef ASSIMP_BUILD_NO_MMD_IMPORTER
  386|    624|    out.push_back(new MMDImporter());
  387|    624|#endif
  388|    624|#ifndef ASSIMP_BUILD_NO_IQM_IMPORTER
  389|    624|    out.push_back(new IQMImporter());
  390|    624|#endif
  391|    624|}
_ZN6Assimp26DeleteImporterInstanceListERNSt3__16vectorIPNS_12BaseImporterENS0_9allocatorIS3_EEEE:
  394|    624|void DeleteImporterInstanceList(std::vector<BaseImporter *> &deleteList) {
  395|  30.5k|    for (size_t i = 0; i < deleteList.size(); ++i) {
  ------------------
  |  Branch (395:24): [True: 29.9k, False: 624]
  ------------------
  396|  29.9k|        delete deleteList[i];
  397|  29.9k|        deleteList[i] = nullptr;
  398|  29.9k|    } //for
  399|    624|}

_ZNK6Assimp5MaybeIfEcvbEv:
   63|  1.49k|    operator bool() const {
   64|  1.49k|        return _valid;
   65|  1.49k|    }
_ZNK6Assimp5MaybeI9aiColor3DEcvbEv:
   63|    374|    operator bool() const {
   64|    374|        return _valid;
   65|    374|    }
_ZNK6Assimp5MaybeI9aiColor3DE3GetEv:
   79|      2|    const T &Get() const {
   80|      2|        ai_assert(_valid);
  ------------------
  |  |   67|      2|#   define ai_assert(expression) (void)((!!(expression)) || (Assimp::aiAssertViolation(#expression, __FILE__, __LINE__), 0))
  |  |  ------------------
  |  |  |  Branch (67:41): [True: 2, False: 0]
  |  |  |  Branch (67:61): [True: 0, False: 0]
  |  |  ------------------
  ------------------
   81|      2|        return _val;
   82|      2|    }
_ZN6Assimp5MaybeIfEC2Ev:
   53|  7.43k|    Maybe() = default;
_ZN6Assimp5MaybeI9aiColor3DEC2Ev:
   53|    519|    Maybe() = default;
_ZN6Assimp5MaybeI9aiColor3DEaSERKS2_:
   86|     70|    Maybe &operator=(const Maybe &) = default;
_ZN6Assimp5MaybeI9aiColor3DEC2IRS1_EEOT_:
   59|     70|            _val(std::forward<U>(val)), _valid(true) {}
_ZN6Assimp5MaybeIfEC2IfEEOT_:
   59|  1.39k|            _val(std::forward<U>(val)), _valid(true) {}

_ZN6Assimp12NewellNormalILi3ELi3ELi3EfEEvR10aiVector3tIT2_EiPS2_S5_S5_:
  178|    817|inline void NewellNormal (aiVector3t<TReal>& out, int num, TReal* x, TReal* y, TReal* z) {
  179|       |    // Duplicate the first two vertices at the end
  180|    817|    x[(num+0)*ofs_x] = x[0];
  181|    817|    x[(num+1)*ofs_x] = x[ofs_x];
  182|       |
  183|    817|    y[(num+0)*ofs_y] = y[0];
  184|    817|    y[(num+1)*ofs_y] = y[ofs_y];
  185|       |
  186|    817|    z[(num+0)*ofs_z] = z[0];
  187|    817|    z[(num+1)*ofs_z] = z[ofs_z];
  188|       |
  189|    817|    TReal sum_xy = 0.0, sum_yz = 0.0, sum_zx = 0.0;
  190|       |
  191|    817|    TReal *xptr = x +ofs_x, *xlow = x, *xhigh = x + ofs_x*2;
  192|    817|    TReal *yptr = y +ofs_y, *ylow = y, *yhigh = y + ofs_y*2;
  193|    817|    TReal *zptr = z +ofs_z, *zlow = z, *zhigh = z + ofs_z*2;
  194|       |
  195|  8.79k|    for (int tmp=0; tmp < num; tmp++) {
  ------------------
  |  Branch (195:21): [True: 7.97k, False: 817]
  ------------------
  196|  7.97k|        sum_xy += (*xptr) * ( (*yhigh) - (*ylow) );
  197|  7.97k|        sum_yz += (*yptr) * ( (*zhigh) - (*zlow) );
  198|  7.97k|        sum_zx += (*zptr) * ( (*xhigh) - (*xlow) );
  199|       |
  200|  7.97k|        xptr  += ofs_x;
  201|  7.97k|        xlow  += ofs_x;
  202|  7.97k|        xhigh += ofs_x;
  203|       |
  204|  7.97k|        yptr  += ofs_y;
  205|  7.97k|        ylow  += ofs_y;
  206|  7.97k|        yhigh += ofs_y;
  207|       |
  208|  7.97k|        zptr  += ofs_z;
  209|  7.97k|        zlow  += ofs_z;
  210|  7.97k|        zhigh += ofs_z;
  211|  7.97k|    }
  212|    817|    out = aiVector3t<TReal>(sum_yz,sum_zx,sum_xy);
  213|    817|}

_ZN6Assimp33GetPostProcessingStepInstanceListERNSt3__16vectorIPNS_11BaseProcessENS0_9allocatorIS3_EEEE:
  147|    832|{
  148|       |    // ----------------------------------------------------------------------------
  149|       |    // Add an instance of each post processing step here in the order
  150|       |    // of sequence it is executed. Steps that are added here are not
  151|       |    // validated - as RegisterPPStep() does - all dependencies must be given.
  152|       |    // ----------------------------------------------------------------------------
  153|    832|    out.reserve(31);
  154|    832|#if (!defined ASSIMP_BUILD_NO_MAKELEFTHANDED_PROCESS)
  155|    832|    out.push_back( new MakeLeftHandedProcess());
  156|    832|#endif
  157|    832|#if (!defined ASSIMP_BUILD_NO_FLIPUVS_PROCESS)
  158|    832|    out.push_back( new FlipUVsProcess());
  159|    832|#endif
  160|    832|#if (!defined ASSIMP_BUILD_NO_FLIPWINDINGORDER_PROCESS)
  161|    832|    out.push_back( new FlipWindingOrderProcess());
  162|    832|#endif
  163|    832|#if (!defined ASSIMP_BUILD_NO_REMOVEVC_PROCESS)
  164|    832|    out.push_back( new RemoveVCProcess());
  165|    832|#endif
  166|    832|#if (!defined ASSIMP_BUILD_NO_REMOVE_REDUNDANTMATERIALS_PROCESS)
  167|    832|    out.push_back( new RemoveRedundantMatsProcess());
  168|    832|#endif
  169|    832|#if (!defined ASSIMP_BUILD_NO_EMBEDTEXTURES_PROCESS)
  170|    832|    out.push_back( new EmbedTexturesProcess());
  171|    832|#endif
  172|    832|#if (!defined ASSIMP_BUILD_NO_FINDINSTANCES_PROCESS)
  173|    832|    out.push_back( new FindInstancesProcess());
  174|    832|#endif
  175|    832|#if (!defined ASSIMP_BUILD_NO_OPTIMIZEGRAPH_PROCESS)
  176|    832|    out.push_back( new OptimizeGraphProcess());
  177|    832|#endif
  178|    832|#ifndef ASSIMP_BUILD_NO_GENUVCOORDS_PROCESS
  179|    832|    out.push_back( new ComputeUVMappingProcess());
  180|    832|#endif
  181|    832|#ifndef ASSIMP_BUILD_NO_TRANSFORMTEXCOORDS_PROCESS
  182|    832|    out.push_back( new TextureTransformStep());
  183|    832|#endif
  184|    832|#if (!defined ASSIMP_BUILD_NO_GLOBALSCALE_PROCESS)
  185|    832|    out.push_back( new ScaleProcess());
  186|    832|#endif
  187|    832|#if (!defined ASSIMP_BUILD_NO_ARMATUREPOPULATE_PROCESS)
  188|    832|    out.push_back( new ArmaturePopulate());
  189|    832|#endif
  190|    832|#if (!defined ASSIMP_BUILD_NO_PRETRANSFORMVERTICES_PROCESS)
  191|    832|    out.push_back( new PretransformVertices());
  192|    832|#endif
  193|    832|#if (!defined ASSIMP_BUILD_NO_TRIANGULATE_PROCESS)
  194|    832|    out.push_back( new TriangulateProcess());
  195|    832|#endif
  196|    832|#if (!defined ASSIMP_BUILD_NO_FINDDEGENERATES_PROCESS)
  197|       |    //find degenerates should run after triangulation (to sort out small
  198|       |    //generated triangles) but before sort by p types (in case there are lines
  199|       |    //and points generated and inserted into a mesh)
  200|    832|    out.push_back( new FindDegeneratesProcess());
  201|    832|#endif
  202|    832|#if (!defined ASSIMP_BUILD_NO_SORTBYPTYPE_PROCESS)
  203|    832|    out.push_back( new SortByPTypeProcess());
  204|    832|#endif
  205|    832|#if (!defined ASSIMP_BUILD_NO_FINDINVALIDDATA_PROCESS)
  206|    832|    out.push_back( new FindInvalidDataProcess());
  207|    832|#endif
  208|    832|#if (!defined ASSIMP_BUILD_NO_OPTIMIZEMESHES_PROCESS)
  209|    832|    out.push_back( new OptimizeMeshesProcess());
  210|    832|#endif
  211|    832|#if (!defined ASSIMP_BUILD_NO_FIXINFACINGNORMALS_PROCESS)
  212|    832|    out.push_back( new FixInfacingNormalsProcess());
  213|    832|#endif
  214|    832|#if (!defined ASSIMP_BUILD_NO_SPLITBYBONECOUNT_PROCESS)
  215|    832|    out.push_back( new SplitByBoneCountProcess());
  216|    832|#endif
  217|    832|#if (!defined ASSIMP_BUILD_NO_SPLITLARGEMESHES_PROCESS)
  218|    832|    out.push_back( new SplitLargeMeshesProcess_Triangle());
  219|    832|#endif
  220|    832|#if (!defined ASSIMP_BUILD_NO_GENFACENORMALS_PROCESS)
  221|    832|    out.push_back( new DropFaceNormalsProcess());
  222|    832|#endif
  223|    832|#if (!defined ASSIMP_BUILD_NO_GENFACENORMALS_PROCESS)
  224|    832|    out.push_back( new GenFaceNormalsProcess());
  225|    832|#endif
  226|       |    // .........................................................................
  227|       |    // DON'T change the order of these five ..
  228|       |    // XXX this is actually a design weakness that dates back to the time
  229|       |    // when Importer would maintain the postprocessing step list exclusively.
  230|       |    // Now that others access it too, we need a better solution.
  231|    832|    out.push_back( new ComputeSpatialSortProcess());
  232|       |    // .........................................................................
  233|       |
  234|    832|#if (!defined ASSIMP_BUILD_NO_GENVERTEXNORMALS_PROCESS)
  235|    832|    out.push_back( new GenVertexNormalsProcess());
  236|    832|#endif
  237|    832|#if (!defined ASSIMP_BUILD_NO_CALCTANGENTS_PROCESS)
  238|    832|    out.push_back( new CalcTangentsProcess());
  239|    832|#endif
  240|    832|#if (!defined ASSIMP_BUILD_NO_JOINVERTICES_PROCESS)
  241|    832|    out.push_back( new JoinVerticesProcess());
  242|    832|#endif
  243|       |
  244|       |    // .........................................................................
  245|    832|    out.push_back( new DestroySpatialSortProcess());
  246|       |    // .........................................................................
  247|       |
  248|    832|#if (!defined ASSIMP_BUILD_NO_SPLITLARGEMESHES_PROCESS)
  249|    832|    out.push_back( new SplitLargeMeshesProcess_Vertex());
  250|    832|#endif
  251|    832|#if (!defined ASSIMP_BUILD_NO_DEBONE_PROCESS)
  252|    832|    out.push_back( new DeboneProcess());
  253|    832|#endif
  254|    832|#if (!defined ASSIMP_BUILD_NO_LIMITBONEWEIGHTS_PROCESS)
  255|    832|    out.push_back( new LimitBoneWeightsProcess());
  256|    832|#endif
  257|    832|#if (!defined ASSIMP_BUILD_NO_IMPROVECACHELOCALITY_PROCESS)
  258|    832|    out.push_back( new ImproveCacheLocalityProcess());
  259|    832|#endif
  260|    832|#if (!defined ASSIMP_BUILD_NO_GENBOUNDINGBOXES_PROCESS)
  261|    832|    out.push_back(new GenBoundingBoxesProcess);
  262|    832|#endif
  263|    832|}

_ZN6Assimp14CommentRemover18RemoveLineCommentsEPKcPcc:
   54|     12|void CommentRemover::RemoveLineComments(const char* szComment, char* szBuffer, char chReplacement /* = ' ' */) {
   55|       |    // validate parameters
   56|     12|    ai_assert(nullptr != szComment);
   57|     12|    ai_assert(nullptr != szBuffer);
   58|     12|    ai_assert(*szComment);
   59|       |
   60|     12|    size_t len = strlen(szComment);
   61|     12|    const size_t lenBuffer = strlen(szBuffer);
   62|     12|    if (len > lenBuffer) {
  ------------------
  |  Branch (62:9): [True: 0, False: 12]
  ------------------
   63|      0|        len = lenBuffer;
   64|      0|    }
   65|       |
   66|    940|    for(size_t i = 0; i < lenBuffer; i++) {
  ------------------
  |  Branch (66:23): [True: 940, False: 0]
  ------------------
   67|       |        // skip over quotes
   68|    940|        if (szBuffer[i] == '\"' || szBuffer[i] == '\'')
  ------------------
  |  Branch (68:13): [True: 4, False: 936]
  |  Branch (68:36): [True: 4, False: 932]
  ------------------
   69|    240|            while (++i < lenBuffer && szBuffer[i] != '\"' && szBuffer[i] != '\'');
  ------------------
  |  Branch (69:20): [True: 236, False: 4]
  |  Branch (69:39): [True: 236, False: 0]
  |  Branch (69:62): [True: 232, False: 4]
  ------------------
   70|       |
   71|    940|        if(lenBuffer - i < len) {
  ------------------
  |  Branch (71:12): [True: 12, False: 928]
  ------------------
   72|     12|            break;
   73|     12|        }
   74|       |
   75|    928|        if (!strncmp(szBuffer + i,szComment,len)) {
  ------------------
  |  Branch (75:13): [True: 0, False: 928]
  ------------------
   76|      0|            while (i < lenBuffer && !IsLineEnd(szBuffer[i])) {
  ------------------
  |  Branch (76:20): [True: 0, False: 0]
  |  Branch (76:37): [True: 0, False: 0]
  ------------------
   77|      0|                szBuffer[i++] = chReplacement;
   78|      0|            }
   79|      0|        }
   80|    928|    }
   81|     12|}

_ZN6Assimp13SGSpatialSortC2Ev:
   51|     35|SGSpatialSort::SGSpatialSort() {
   52|       |    // define the reference plane. We choose some arbitrary vector away from all basic axes
   53|       |    // in the hope that no model spreads all its vertices along this plane.
   54|     35|    mPlaneNormal.Set( 0.8523f, 0.34321f, 0.5736f);
   55|     35|    mPlaneNormal.Normalize();
   56|     35|}
_ZN6Assimp13SGSpatialSort3AddERK10aiVector3tIfEjj:
   61|  11.8k|{
   62|       |    // store position by index and distance
   63|  11.8k|    float distance = vPosition * mPlaneNormal;
   64|  11.8k|    mPositions.emplace_back( index, vPosition,
   65|  11.8k|        distance, smoothingGroup);
   66|  11.8k|}
_ZN6Assimp13SGSpatialSort7PrepareEv:
   69|     35|{
   70|       |    // now sort the array ascending by distance.
   71|     35|    std::sort( this->mPositions.begin(), this->mPositions.end());
   72|     35|}
_ZNK6Assimp13SGSpatialSort13FindPositionsERK10aiVector3tIfEjfRNSt3__16vectorIjNS5_9allocatorIjEEEEb:
   80|  4.07k|{
   81|  4.07k|    float dist = pPosition * mPlaneNormal;
   82|  4.07k|    float minDist = dist - pRadius, maxDist = dist + pRadius;
   83|       |
   84|       |    // clear the array
   85|  4.07k|    poResults.clear();
   86|       |
   87|       |    // quick check for positions outside the range
   88|  4.07k|    if( mPositions.empty() )
  ------------------
  |  Branch (88:9): [True: 0, False: 4.07k]
  ------------------
   89|      0|        return;
   90|  4.07k|    if( maxDist < mPositions.front().mDistance)
  ------------------
  |  Branch (90:9): [True: 0, False: 4.07k]
  ------------------
   91|      0|        return;
   92|  4.07k|    if( minDist > mPositions.back().mDistance)
  ------------------
  |  Branch (92:9): [True: 0, False: 4.07k]
  ------------------
   93|      0|        return;
   94|       |
   95|       |    // do a binary search for the minimal distance to start the iteration there
   96|  4.07k|    unsigned int index = (unsigned int)mPositions.size() / 2;
   97|  4.07k|    unsigned int binaryStepSize = (unsigned int)mPositions.size() / 4;
   98|  36.9k|    while( binaryStepSize > 1)
  ------------------
  |  Branch (98:12): [True: 32.9k, False: 4.07k]
  ------------------
   99|  32.9k|    {
  100|  32.9k|        if( mPositions[index].mDistance < minDist)
  ------------------
  |  Branch (100:13): [True: 16.2k, False: 16.6k]
  ------------------
  101|  16.2k|            index += binaryStepSize;
  102|  16.6k|        else
  103|  16.6k|            index -= binaryStepSize;
  104|       |
  105|  32.9k|        binaryStepSize /= 2;
  106|  32.9k|    }
  107|       |
  108|       |    // depending on the direction of the last step we need to single step a bit back or forth
  109|       |    // to find the actual beginning element of the range
  110|  7.25k|    while( index > 0 && mPositions[index].mDistance > minDist)
  ------------------
  |  Branch (110:12): [True: 7.20k, False: 51]
  |  Branch (110:25): [True: 3.18k, False: 4.02k]
  ------------------
  111|  3.18k|        index--;
  112|  9.56k|    while( index < (mPositions.size() - 1) && mPositions[index].mDistance < minDist)
  ------------------
  |  Branch (112:12): [True: 9.56k, False: 0]
  |  Branch (112:47): [True: 5.48k, False: 4.07k]
  ------------------
  113|  5.48k|        index++;
  114|       |
  115|       |    // Mow start iterating from there until the first position lays outside of the distance range.
  116|       |    // Add all positions inside the distance range within the given radius to the result array
  117|       |
  118|  4.07k|    float squareEpsilon = pRadius * pRadius;
  119|  4.07k|    std::vector<Entry>::const_iterator it  = mPositions.begin() + index;
  120|  4.07k|    std::vector<Entry>::const_iterator end = mPositions.end();
  121|       |
  122|  4.07k|    if (exactMatch)
  ------------------
  |  Branch (122:9): [True: 2.39k, False: 1.67k]
  ------------------
  123|  2.39k|    {
  124|  13.8k|        while( it->mDistance < maxDist)
  ------------------
  |  Branch (124:16): [True: 11.5k, False: 2.36k]
  ------------------
  125|  11.5k|        {
  126|  11.5k|            if((it->mPosition - pPosition).SquareLength() < squareEpsilon && it->mSmoothGroups == pSG)
  ------------------
  |  Branch (126:16): [True: 11.2k, False: 256]
  |  Branch (126:16): [True: 11.2k, False: 256]
  |  Branch (126:78): [True: 11.2k, False: 0]
  ------------------
  127|  11.2k|            {
  128|  11.2k|                poResults.push_back( it->mIndex);
  129|  11.2k|            }
  130|  11.5k|            ++it;
  131|  11.5k|            if( end == it )break;
  ------------------
  |  Branch (131:17): [True: 32, False: 11.4k]
  ------------------
  132|  11.5k|        }
  133|  2.39k|    }
  134|  1.67k|    else
  135|  1.67k|    {
  136|       |        // if the given smoothing group is 0, we'll return all surrounding vertices
  137|  1.67k|        if (!pSG)
  ------------------
  |  Branch (137:13): [True: 773, False: 901]
  ------------------
  138|    773|        {
  139|  5.38k|            while( it->mDistance < maxDist)
  ------------------
  |  Branch (139:20): [True: 4.61k, False: 771]
  ------------------
  140|  4.61k|            {
  141|  4.61k|                if((it->mPosition - pPosition).SquareLength() < squareEpsilon)
  ------------------
  |  Branch (141:20): [True: 4.61k, False: 0]
  ------------------
  142|  4.61k|                    poResults.push_back( it->mIndex);
  143|  4.61k|                ++it;
  144|  4.61k|                if( end == it)break;
  ------------------
  |  Branch (144:21): [True: 2, False: 4.60k]
  ------------------
  145|  4.61k|            }
  146|    773|        }
  147|  6.03k|        else while( it->mDistance < maxDist)
  ------------------
  |  Branch (147:21): [True: 5.15k, False: 884]
  ------------------
  148|  5.15k|        {
  149|  5.15k|            if((it->mPosition - pPosition).SquareLength() < squareEpsilon &&
  ------------------
  |  Branch (149:16): [True: 4.88k, False: 263]
  |  Branch (149:16): [True: 4.79k, False: 355]
  ------------------
  150|  4.88k|                (it->mSmoothGroups & pSG || !it->mSmoothGroups))
  ------------------
  |  Branch (150:18): [True: 4.79k, False: 94]
  |  Branch (150:45): [True: 2, False: 92]
  ------------------
  151|  4.79k|            {
  152|  4.79k|                poResults.push_back( it->mIndex);
  153|  4.79k|            }
  154|  5.15k|            ++it;
  155|  5.15k|            if( end == it)break;
  ------------------
  |  Branch (155:17): [True: 17, False: 5.13k]
  ------------------
  156|  5.15k|        }
  157|  1.67k|    }
  158|  4.07k|}

_ZN6Assimp13SceneCombiner13AddNodeHashesEP6aiNodeRNSt3__13setIjNS3_4lessIjEENS3_9allocatorIjEEEE:
   98|  12.2k|void SceneCombiner::AddNodeHashes(aiNode *node, std::set<unsigned int> &hashes) {
   99|  12.2k|    if (node == nullptr) {
  ------------------
  |  Branch (99:9): [True: 0, False: 12.2k]
  ------------------
  100|      0|        ASSIMP_LOG_ERROR("Pointer to aiNode is nullptr.");
  101|      0|        return;
  102|      0|    }
  103|       |
  104|       |    // Add node name to hashing set if it is non-empty - empty nodes are allowed
  105|       |    // and they can't have any anims assigned so its absolutely safe to duplicate them.
  106|  12.2k|    if (node->mName.length) {
  ------------------
  |  Branch (106:9): [True: 12.2k, False: 1]
  ------------------
  107|  12.2k|        hashes.insert(SuperFastHash(node->mName.data, static_cast<uint32_t>(node->mName.length)));
  108|  12.2k|    }
  109|       |
  110|       |    // Process all children recursively
  111|  23.8k|    for (unsigned int i = 0; i < node->mNumChildren; ++i) {
  ------------------
  |  Branch (111:30): [True: 11.6k, False: 12.2k]
  ------------------
  112|  11.6k|        AddNodeHashes(node->mChildren[i], hashes);
  113|  11.6k|    }
  114|  12.2k|}
_ZN6Assimp13SceneCombiner13FindNameMatchERK8aiStringRNSt3__16vectorINS_11SceneHelperENS4_9allocatorIS6_EEEEj:
  131|    719|bool SceneCombiner::FindNameMatch(const aiString &name, std::vector<SceneHelper> &input, unsigned int cur) {
  132|    719|    const unsigned int hash = SuperFastHash(name.data, static_cast<uint32_t>(name.length));
  133|       |
  134|       |    // Check whether we find a positive match in one of the given sets
  135|  1.56k|    for (unsigned int i = 0; i < input.size(); ++i) {
  ------------------
  |  Branch (135:30): [True: 1.54k, False: 19]
  ------------------
  136|  1.54k|        if (cur != i && input[i].hashes.find(hash) != input[i].hashes.end()) {
  ------------------
  |  Branch (136:13): [True: 1.45k, False: 90]
  |  Branch (136:13): [True: 700, False: 844]
  |  Branch (136:25): [True: 700, False: 754]
  ------------------
  137|    700|            return true;
  138|    700|        }
  139|  1.54k|    }
  140|     19|    return false;
  141|    719|}
_ZN6Assimp13SceneCombiner22AddNodePrefixesCheckedEP6aiNodePKcjRNSt3__16vectorINS_11SceneHelperENS5_9allocatorIS7_EEEEj:
  146|  13.7k|        std::vector<SceneHelper> &input, unsigned int cur) {
  147|  13.7k|    ai_assert(nullptr != prefix);
  ------------------
  |  |   67|  13.7k|#   define ai_assert(expression) (void)((!!(expression)) || (Assimp::aiAssertViolation(#expression, __FILE__, __LINE__), 0))
  |  |  ------------------
  |  |  |  Branch (67:41): [True: 13.7k, False: 0]
  |  |  |  Branch (67:61): [True: 0, False: 0]
  |  |  ------------------
  ------------------
  148|       |
  149|  13.7k|    const unsigned int hash = SuperFastHash(node->mName.data, static_cast<uint32_t>(node->mName.length));
  150|       |
  151|       |    // Check whether we find a positive match in one of the given sets
  152|   397k|    for (unsigned int i = 0; i < input.size(); ++i) {
  ------------------
  |  Branch (152:30): [True: 396k, False: 1.58k]
  ------------------
  153|   396k|        if (cur != i && input[i].hashes.find(hash) != input[i].hashes.end()) {
  ------------------
  |  Branch (153:13): [True: 394k, False: 2.12k]
  |  Branch (153:13): [True: 12.2k, False: 384k]
  |  Branch (153:25): [True: 12.2k, False: 381k]
  ------------------
  154|  12.2k|            PrefixString(node->mName, prefix, len);
  155|  12.2k|            break;
  156|  12.2k|        }
  157|   396k|    }
  158|       |
  159|       |    // Process all children recursively
  160|  27.0k|    for (unsigned int i = 0; i < node->mNumChildren; ++i) {
  ------------------
  |  Branch (160:30): [True: 13.2k, False: 13.7k]
  ------------------
  161|  13.2k|        AddNodePrefixesChecked(node->mChildren[i], prefix, len, input, cur);
  162|  13.2k|    }
  163|  13.7k|}
_ZN6Assimp13SceneCombiner21OffsetNodeMeshIndicesEP6aiNodej:
  167|  13.7k|void SceneCombiner::OffsetNodeMeshIndices(aiNode *node, unsigned int offset) {
  168|  26.7k|    for (unsigned int i = 0; i < node->mNumMeshes; ++i)
  ------------------
  |  Branch (168:30): [True: 12.9k, False: 13.7k]
  ------------------
  169|  12.9k|        node->mMeshes[i] += offset;
  170|       |
  171|  27.0k|    for (unsigned int i = 0; i < node->mNumChildren; ++i) {
  ------------------
  |  Branch (171:30): [True: 13.2k, False: 13.7k]
  ------------------
  172|  13.2k|        OffsetNodeMeshIndices(node->mChildren[i], offset);
  173|  13.2k|    }
  174|  13.7k|}
_ZN6Assimp13SceneCombiner13AttachToGraphEP6aiNodeRNSt3__16vectorINS_18NodeAttachmentInfoENS3_9allocatorIS5_EEEE:
  213|  1.56k|void SceneCombiner::AttachToGraph(aiNode *attach, std::vector<NodeAttachmentInfo> &srcList) {
  214|  1.56k|    unsigned int cnt;
  215|  3.12k|    for (cnt = 0; cnt < attach->mNumChildren; ++cnt) {
  ------------------
  |  Branch (215:19): [True: 1.55k, False: 1.56k]
  ------------------
  216|  1.55k|        AttachToGraph(attach->mChildren[cnt], srcList);
  217|  1.55k|    }
  218|       |
  219|  1.56k|    cnt = 0;
  220|  1.56k|    for (std::vector<NodeAttachmentInfo>::iterator it = srcList.begin();
  221|   371k|            it != srcList.end(); ++it) {
  ------------------
  |  Branch (221:13): [True: 369k, False: 1.56k]
  ------------------
  222|   369k|        if ((*it).attachToNode == attach && !(*it).resolved)
  ------------------
  |  Branch (222:13): [True: 555, False: 369k]
  |  Branch (222:45): [True: 555, False: 0]
  ------------------
  223|    555|            ++cnt;
  224|   369k|    }
  225|       |
  226|  1.56k|    if (cnt) {
  ------------------
  |  Branch (226:9): [True: 555, False: 1.01k]
  ------------------
  227|    555|        aiNode **n = new aiNode *[cnt + attach->mNumChildren];
  228|    555|        if (attach->mNumChildren) {
  ------------------
  |  Branch (228:13): [True: 0, False: 555]
  ------------------
  229|      0|            ::memcpy(n, attach->mChildren, sizeof(void *) * attach->mNumChildren);
  230|      0|            delete[] attach->mChildren;
  231|      0|        }
  232|    555|        attach->mChildren = n;
  233|       |
  234|    555|        n += attach->mNumChildren;
  235|    555|        attach->mNumChildren += cnt;
  236|       |
  237|   179k|        for (unsigned int i = 0; i < srcList.size(); ++i) {
  ------------------
  |  Branch (237:34): [True: 179k, False: 555]
  ------------------
  238|   179k|            NodeAttachmentInfo &att = srcList[i];
  239|   179k|            if (att.attachToNode == attach && !att.resolved) {
  ------------------
  |  Branch (239:17): [True: 555, False: 178k]
  |  Branch (239:47): [True: 555, False: 0]
  ------------------
  240|    555|                *n = att.node;
  241|    555|                (**n).mParent = attach;
  242|    555|                ++n;
  243|       |
  244|       |                // mark this attachment as resolved
  245|    555|                att.resolved = true;
  246|    555|            }
  247|   179k|        }
  248|    555|    }
  249|  1.56k|}
_ZN6Assimp13SceneCombiner13AttachToGraphEP7aiSceneRNSt3__16vectorINS_18NodeAttachmentInfoENS3_9allocatorIS5_EEEE:
  252|      9|void SceneCombiner::AttachToGraph(aiScene *master, std::vector<NodeAttachmentInfo> &src) {
  253|      9|    ai_assert(nullptr != master);
  ------------------
  |  |   67|      9|#   define ai_assert(expression) (void)((!!(expression)) || (Assimp::aiAssertViolation(#expression, __FILE__, __LINE__), 0))
  |  |  ------------------
  |  |  |  Branch (67:41): [True: 9, False: 0]
  |  |  |  Branch (67:61): [True: 0, False: 0]
  |  |  ------------------
  ------------------
  254|       |
  255|      9|    AttachToGraph(master->mRootNode, src);
  256|      9|}
_ZN6Assimp13SceneCombiner11MergeScenesEPP7aiSceneS2_RNSt3__16vectorINS_14AttachmentInfoENS4_9allocatorIS6_EEEEj:
  259|     50|void SceneCombiner::MergeScenes(aiScene **_dest, aiScene *master, std::vector<AttachmentInfo> &srcList, unsigned int flags) {
  260|     50|    if (nullptr == _dest) {
  ------------------
  |  Branch (260:9): [True: 0, False: 50]
  ------------------
  261|      0|        std::unordered_set<aiScene *> uniqueScenes;
  262|      0|        uniqueScenes.insert(master);
  263|      0|        for (const auto &item : srcList) {
  ------------------
  |  Branch (263:31): [True: 0, False: 0]
  ------------------
  264|      0|            uniqueScenes.insert(item.scene);
  265|      0|        }
  266|      0|        for (const auto &item : uniqueScenes) {
  ------------------
  |  Branch (266:31): [True: 0, False: 0]
  ------------------
  267|      0|            delete item;
  268|      0|        }
  269|      0|        return;
  270|      0|    }
  271|       |
  272|       |    // if _dest points to nullptr allocate a new scene. Otherwise clear the old and reuse it
  273|     50|    if (srcList.empty()) {
  ------------------
  |  Branch (273:9): [True: 41, False: 9]
  ------------------
  274|     41|        if (*_dest) {
  ------------------
  |  Branch (274:13): [True: 41, False: 0]
  ------------------
  275|     41|            SceneCombiner::CopySceneFlat(_dest, master);
  276|     41|            delete master;
  277|     41|        } else
  278|      0|            *_dest = master;
  279|     41|        return;
  280|     41|    }
  281|      9|    if (*_dest) {
  ------------------
  |  Branch (281:9): [True: 9, False: 0]
  ------------------
  282|      9|        (*_dest)->~aiScene();
  283|      9|        new (*_dest) aiScene();
  284|      9|    } else
  285|      0|        *_dest = new aiScene();
  286|       |
  287|      9|    aiScene *dest = *_dest;
  288|       |
  289|      9|    std::vector<SceneHelper> src(srcList.size() + 1);
  290|      9|    src[0].scene = master;
  291|    564|    for (unsigned int i = 0; i < srcList.size(); ++i) {
  ------------------
  |  Branch (291:30): [True: 555, False: 9]
  ------------------
  292|    555|        src[i + 1] = SceneHelper(srcList[i].scene);
  293|    555|    }
  294|       |
  295|       |    // this helper array specifies which scenes are duplicates of others
  296|      9|    std::vector<unsigned int> duplicates(src.size(), UINT_MAX);
  297|       |
  298|       |    // this helper array is used as lookup table several times
  299|      9|    std::vector<unsigned int> offset(src.size());
  300|       |
  301|       |    // Find duplicate scenes
  302|    573|    for (unsigned int i = 0; i < src.size(); ++i) {
  ------------------
  |  Branch (302:30): [True: 564, False: 9]
  ------------------
  303|    564|        if (duplicates[i] != i && duplicates[i] != UINT_MAX) {
  ------------------
  |  Branch (303:13): [True: 564, False: 0]
  |  Branch (303:35): [True: 531, False: 33]
  ------------------
  304|    531|            continue;
  305|    531|        }
  306|       |
  307|     33|        duplicates[i] = i;
  308|  1.68k|        for (unsigned int a = i + 1; a < src.size(); ++a) {
  ------------------
  |  Branch (308:38): [True: 1.64k, False: 33]
  ------------------
  309|  1.64k|            if (src[i].scene == src[a].scene) {
  ------------------
  |  Branch (309:17): [True: 531, False: 1.11k]
  ------------------
  310|    531|                duplicates[a] = i;
  311|    531|            }
  312|  1.64k|        }
  313|     33|    }
  314|       |
  315|       |    // Generate unique names for all named stuff?
  316|      9|    if (flags & AI_INT_MERGE_SCENE_GEN_UNIQUE_NAMES) {
  ------------------
  |  Branch (316:9): [True: 9, False: 0]
  ------------------
  317|       |#if 0
  318|       |        // Construct a proper random number generator
  319|       |        boost::mt19937 rng(  );
  320|       |        boost::uniform_int<> dist(1u,1 << 24u);
  321|       |        boost::variate_generator<boost::mt19937&, boost::uniform_int<> > rndGen(rng, dist);
  322|       |#endif
  323|    564|        for (unsigned int i = 1; i < src.size(); ++i) {
  ------------------
  |  Branch (323:34): [True: 555, False: 9]
  ------------------
  324|    555|            src[i].idlen = ai_snprintf(src[i].id, 32, "$%.6X$_", i);
  325|       |
  326|    555|            if (flags & AI_INT_MERGE_SCENE_GEN_UNIQUE_NAMES_IF_NECESSARY) {
  ------------------
  |  Branch (326:17): [True: 555, False: 0]
  ------------------
  327|       |
  328|       |                // Compute hashes for all identifiers in this scene and store them
  329|       |                // in a sorted table (for convenience I'm using std::set). We hash
  330|       |                // just the node and animation channel names, all identifiers except
  331|       |                // the material names should be caught by doing this.
  332|    555|                AddNodeHashes(src[i]->mRootNode, src[i].hashes);
  333|       |
  334|  1.12k|                for (unsigned int a = 0; a < src[i]->mNumAnimations; ++a) {
  ------------------
  |  Branch (334:42): [True: 572, False: 555]
  ------------------
  335|    572|                    aiAnimation *anim = src[i]->mAnimations[a];
  336|    572|                    src[i].hashes.insert(SuperFastHash(anim->mName.data, static_cast<uint32_t>(anim->mName.length)));
  337|    572|                }
  338|    555|            }
  339|    555|        }
  340|      9|    }
  341|       |
  342|      9|    unsigned int cnt;
  343|       |
  344|       |    // First find out how large the respective output arrays must be
  345|    573|    for (unsigned int n = 0; n < src.size(); ++n) {
  ------------------
  |  Branch (345:30): [True: 564, False: 9]
  ------------------
  346|    564|        SceneHelper *cur = &src[n];
  347|       |
  348|    564|        if (n == duplicates[n] || flags & AI_INT_MERGE_SCENE_DUPLICATES_DEEP_CPY) {
  ------------------
  |  Branch (348:13): [True: 33, False: 531]
  |  Branch (348:35): [True: 0, False: 531]
  ------------------
  349|     33|            dest->mNumTextures += (*cur)->mNumTextures;
  350|     33|            dest->mNumMaterials += (*cur)->mNumMaterials;
  351|     33|            dest->mNumMeshes += (*cur)->mNumMeshes;
  352|     33|        }
  353|       |
  354|    564|        dest->mNumLights += (*cur)->mNumLights;
  355|    564|        dest->mNumCameras += (*cur)->mNumCameras;
  356|    564|        dest->mNumAnimations += (*cur)->mNumAnimations;
  357|       |
  358|       |        // Combine the flags of all scenes
  359|       |        // We need to process them flag-by-flag here to get correct results
  360|       |        // dest->mFlags ; //|= (*cur)->mFlags;
  361|    564|        if ((*cur)->mFlags & AI_SCENE_FLAGS_NON_VERBOSE_FORMAT) {
  ------------------
  |  Branch (361:13): [True: 0, False: 564]
  ------------------
  362|      0|            dest->mFlags |= AI_SCENE_FLAGS_NON_VERBOSE_FORMAT;
  363|      0|        }
  364|    564|    }
  365|       |
  366|       |    // generate the output texture list + an offset table for all texture indices
  367|      9|    if (dest->mNumTextures) {
  ------------------
  |  Branch (367:9): [True: 0, False: 9]
  ------------------
  368|      0|        aiTexture **pip = dest->mTextures = new aiTexture *[dest->mNumTextures];
  369|      0|        cnt = 0;
  370|      0|        for (unsigned int n = 0; n < src.size(); ++n) {
  ------------------
  |  Branch (370:34): [True: 0, False: 0]
  ------------------
  371|      0|            SceneHelper *cur = &src[n];
  372|      0|            for (unsigned int i = 0; i < (*cur)->mNumTextures; ++i) {
  ------------------
  |  Branch (372:38): [True: 0, False: 0]
  ------------------
  373|      0|                if (n != duplicates[n]) {
  ------------------
  |  Branch (373:21): [True: 0, False: 0]
  ------------------
  374|      0|                    if (flags & AI_INT_MERGE_SCENE_DUPLICATES_DEEP_CPY)
  ------------------
  |  Branch (374:25): [True: 0, False: 0]
  ------------------
  375|      0|                        Copy(pip, (*cur)->mTextures[i]);
  376|       |
  377|      0|                    else
  378|      0|                        continue;
  379|      0|                } else
  380|      0|                    *pip = (*cur)->mTextures[i];
  381|      0|                ++pip;
  382|      0|            }
  383|       |
  384|      0|            offset[n] = cnt;
  385|      0|            cnt = (unsigned int)(pip - dest->mTextures);
  386|      0|        }
  387|      0|    }
  388|       |
  389|       |    // generate the output material list + an offset table for all material indices
  390|      9|    if (dest->mNumMaterials) {
  ------------------
  |  Branch (390:9): [True: 5, False: 4]
  ------------------
  391|      5|        aiMaterial **pip = dest->mMaterials = new aiMaterial *[dest->mNumMaterials];
  392|      5|        cnt = 0;
  393|    457|        for (unsigned int n = 0; n < src.size(); ++n) {
  ------------------
  |  Branch (393:34): [True: 452, False: 5]
  ------------------
  394|    452|            SceneHelper *cur = &src[n];
  395|  13.3k|            for (unsigned int i = 0; i < (*cur)->mNumMaterials; ++i) {
  ------------------
  |  Branch (395:38): [True: 12.9k, False: 452]
  ------------------
  396|  12.9k|                if (n != duplicates[n]) {
  ------------------
  |  Branch (396:21): [True: 11.3k, False: 1.60k]
  ------------------
  397|  11.3k|                    if (flags & AI_INT_MERGE_SCENE_DUPLICATES_DEEP_CPY)
  ------------------
  |  Branch (397:25): [True: 0, False: 11.3k]
  ------------------
  398|      0|                        Copy(pip, (*cur)->mMaterials[i]);
  399|       |
  400|  11.3k|                    else
  401|  11.3k|                        continue;
  402|  11.3k|                } else
  403|  1.60k|                    *pip = (*cur)->mMaterials[i];
  404|       |
  405|  1.60k|                if ((*cur)->mNumTextures != dest->mNumTextures) {
  ------------------
  |  Branch (405:21): [True: 0, False: 1.60k]
  ------------------
  406|       |                    // We need to update all texture indices of the mesh. So we need to search for
  407|       |                    // a material property called '$tex.file'
  408|       |
  409|      0|                    for (unsigned int a = 0; a < (*pip)->mNumProperties; ++a) {
  ------------------
  |  Branch (409:46): [True: 0, False: 0]
  ------------------
  410|      0|                        aiMaterialProperty *prop = (*pip)->mProperties[a];
  411|      0|                        if (!strncmp(prop->mKey.data, "$tex.file", 9)) {
  ------------------
  |  Branch (411:29): [True: 0, False: 0]
  ------------------
  412|       |                            // Check whether this texture is an embedded texture.
  413|       |                            // In this case the property looks like this: *<n>,
  414|       |                            // where n is the index of the texture.
  415|       |                            // Copy here because we overwrite the string data in-place and the buffer inside of aiString
  416|       |                            // will be a lie if we just reinterpret from prop->mData. The size of mData is not guaranteed to be
  417|       |                            // AI_MAXLEN in size.
  418|      0|                            aiString s(*(aiString *)prop->mData);
  419|      0|                            if ('*' == s.data[0]) {
  ------------------
  |  Branch (419:33): [True: 0, False: 0]
  ------------------
  420|       |                                // Offset the index and write it back ..
  421|      0|                                const unsigned int idx = strtoul10(&s.data[1]) + offset[n];
  422|      0|                                const unsigned int oldLen = s.length;
  423|       |
  424|      0|                                s.length = 1 + ASSIMP_itoa10(&s.data[1], sizeof(s.data) - 1, idx);
  425|       |
  426|       |                                // The string changed in size so we need to reallocate the buffer for the property.
  427|      0|                                if (oldLen < s.length) {
  ------------------
  |  Branch (427:37): [True: 0, False: 0]
  ------------------
  428|      0|                                    prop->mDataLength += s.length - oldLen;
  429|      0|                                    delete[] prop->mData;
  430|      0|                                    prop->mData = new char[prop->mDataLength];
  431|      0|                                }
  432|       |
  433|      0|                                memcpy(prop->mData, static_cast<void*>(&s), prop->mDataLength);
  434|      0|                            }
  435|      0|                        }
  436|       |
  437|       |                        // Need to generate new, unique material names?
  438|      0|                        else if (!::strcmp(prop->mKey.data, "$mat.name") && flags & AI_INT_MERGE_SCENE_GEN_UNIQUE_MATNAMES) {
  ------------------
  |  Branch (438:34): [True: 0, False: 0]
  |  Branch (438:77): [True: 0, False: 0]
  ------------------
  439|      0|                            aiString *pcSrc = (aiString *)prop->mData;
  440|      0|                            PrefixString(*pcSrc, (*cur).id, (*cur).idlen);
  441|      0|                        }
  442|      0|                    }
  443|      0|                }
  444|  1.60k|                ++pip;
  445|  1.60k|            }
  446|       |
  447|    452|            offset[n] = cnt;
  448|    452|            cnt = (unsigned int)(pip - dest->mMaterials);
  449|    452|        }
  450|      5|    }
  451|       |
  452|       |    // generate the output mesh list + again an offset table for all mesh indices
  453|      9|    if (dest->mNumMeshes) {
  ------------------
  |  Branch (453:9): [True: 5, False: 4]
  ------------------
  454|      5|        aiMesh **pip = dest->mMeshes = new aiMesh *[dest->mNumMeshes];
  455|      5|        cnt = 0;
  456|    457|        for (unsigned int n = 0; n < src.size(); ++n) {
  ------------------
  |  Branch (456:34): [True: 452, False: 5]
  ------------------
  457|    452|            SceneHelper *cur = &src[n];
  458|  13.3k|            for (unsigned int i = 0; i < (*cur)->mNumMeshes; ++i) {
  ------------------
  |  Branch (458:38): [True: 12.9k, False: 452]
  ------------------
  459|  12.9k|                if (n != duplicates[n]) {
  ------------------
  |  Branch (459:21): [True: 11.3k, False: 1.60k]
  ------------------
  460|  11.3k|                    if (flags & AI_INT_MERGE_SCENE_DUPLICATES_DEEP_CPY)
  ------------------
  |  Branch (460:25): [True: 0, False: 11.3k]
  ------------------
  461|      0|                        Copy(pip, (*cur)->mMeshes[i]);
  462|       |
  463|  11.3k|                    else
  464|  11.3k|                        continue;
  465|  11.3k|                } else
  466|  1.60k|                    *pip = (*cur)->mMeshes[i];
  467|       |
  468|       |                // update the material index of the mesh
  469|  1.60k|                (*pip)->mMaterialIndex += offset[n];
  470|  1.60k|                ++pip;
  471|  1.60k|            }
  472|       |
  473|       |            // reuse the offset array - store now the mesh offset in it
  474|    452|            offset[n] = cnt;
  475|    452|            cnt = (unsigned int)(pip - dest->mMeshes);
  476|    452|        }
  477|      5|    }
  478|       |
  479|      9|    std::vector<NodeAttachmentInfo> nodes;
  480|      9|    nodes.reserve(srcList.size());
  481|       |
  482|       |    // ----------------------------------------------------------------------------
  483|       |    // Now generate the output node graph. We need to make those
  484|       |    // names in the graph that are referenced by anims or lights
  485|       |    // or cameras unique. So we add a prefix to them ... $<rand>_
  486|       |    // We could also use a counter, but using a random value allows us to
  487|       |    // use just one prefix if we are joining multiple scene hierarchies recursively.
  488|       |    // Chances are quite good we don't collide, so we try that ...
  489|       |    // ----------------------------------------------------------------------------
  490|       |
  491|       |    // Allocate space for light sources, cameras and animations
  492|      9|    aiLight **ppLights = dest->mLights = (dest->mNumLights ? new aiLight *[dest->mNumLights] : nullptr);
  ------------------
  |  Branch (492:43): [True: 1, False: 8]
  ------------------
  493|       |
  494|      9|    aiCamera **ppCameras = dest->mCameras = (dest->mNumCameras ? new aiCamera *[dest->mNumCameras] : nullptr);
  ------------------
  |  Branch (494:46): [True: 0, False: 9]
  ------------------
  495|       |
  496|      9|    aiAnimation **ppAnims = dest->mAnimations = (dest->mNumAnimations ? new aiAnimation *[dest->mNumAnimations] : nullptr);
  ------------------
  |  Branch (496:50): [True: 3, False: 6]
  ------------------
  497|       |
  498|    573|    for (int n = static_cast<int>(src.size() - 1); n >= 0; --n) /* !!! important !!! */
  ------------------
  |  Branch (498:52): [True: 564, False: 9]
  ------------------
  499|    564|    {
  500|    564|        SceneHelper *cur = &src[n];
  501|    564|        aiNode *node;
  502|       |
  503|       |        // To offset or not to offset, this is the question
  504|    564|        if (n != (int)duplicates[n]) {
  ------------------
  |  Branch (504:13): [True: 531, False: 33]
  ------------------
  505|       |            // Get full scene-graph copy
  506|    531|            Copy(&node, (*cur)->mRootNode);
  507|    531|            OffsetNodeMeshIndices(node, offset[duplicates[n]]);
  508|       |
  509|    531|            if (flags & AI_INT_MERGE_SCENE_DUPLICATES_DEEP_CPY) {
  ------------------
  |  Branch (509:17): [True: 0, False: 531]
  ------------------
  510|       |                // (note:) they are already 'offseted' by offset[duplicates[n]]
  511|      0|                OffsetNodeMeshIndices(node, offset[n] - offset[duplicates[n]]);
  512|      0|            }
  513|    531|        } else // if (n == duplicates[n])
  514|     33|        {
  515|     33|            node = (*cur)->mRootNode;
  516|     33|            OffsetNodeMeshIndices(node, offset[n]);
  517|     33|        }
  518|    564|        if (n) // src[0] is the master node
  ------------------
  |  Branch (518:13): [True: 555, False: 9]
  ------------------
  519|    555|            nodes.emplace_back(node, srcList[n - 1].attachToNode, n);
  520|       |
  521|       |        // add name prefixes?
  522|    564|        if (flags & AI_INT_MERGE_SCENE_GEN_UNIQUE_NAMES) {
  ------------------
  |  Branch (522:13): [True: 564, False: 0]
  ------------------
  523|       |
  524|       |            // or the whole scenegraph
  525|    564|            if (flags & AI_INT_MERGE_SCENE_GEN_UNIQUE_NAMES_IF_NECESSARY) {
  ------------------
  |  Branch (525:17): [True: 564, False: 0]
  ------------------
  526|    564|                AddNodePrefixesChecked(node, (*cur).id, (*cur).idlen, src, n);
  527|    564|            } else
  528|      0|                AddNodePrefixes(node, (*cur).id, (*cur).idlen);
  529|       |
  530|       |            // meshes
  531|  13.4k|            for (unsigned int i = 0; i < (*cur)->mNumMeshes; ++i) {
  ------------------
  |  Branch (531:38): [True: 12.9k, False: 564]
  ------------------
  532|  12.9k|                aiMesh *mesh = (*cur)->mMeshes[i];
  533|       |
  534|       |                // rename all bones
  535|  12.9k|                for (unsigned int a = 0; a < mesh->mNumBones; ++a) {
  ------------------
  |  Branch (535:42): [True: 5, False: 12.9k]
  ------------------
  536|      5|                    if (flags & AI_INT_MERGE_SCENE_GEN_UNIQUE_NAMES_IF_NECESSARY) {
  ------------------
  |  Branch (536:25): [True: 5, False: 0]
  ------------------
  537|      5|                        if (!FindNameMatch(mesh->mBones[a]->mName, src, n))
  ------------------
  |  Branch (537:29): [True: 4, False: 1]
  ------------------
  538|      4|                            continue;
  539|      5|                    }
  540|      1|                    PrefixString(mesh->mBones[a]->mName, (*cur).id, (*cur).idlen);
  541|      1|                }
  542|  12.9k|            }
  543|    564|        }
  544|       |
  545|       |        // --------------------------------------------------------------------
  546|       |        // Copy light sources
  547|    566|        for (unsigned int i = 0; i < (*cur)->mNumLights; ++i, ++ppLights) {
  ------------------
  |  Branch (547:34): [True: 2, False: 564]
  ------------------
  548|      2|            if (n != (int)duplicates[n]) // duplicate scene?
  ------------------
  |  Branch (548:17): [True: 0, False: 2]
  ------------------
  549|      0|            {
  550|      0|                Copy(ppLights, (*cur)->mLights[i]);
  551|      0|            } else
  552|      2|                *ppLights = (*cur)->mLights[i];
  553|       |
  554|       |            // Add name prefixes?
  555|      2|            if (flags & AI_INT_MERGE_SCENE_GEN_UNIQUE_NAMES) {
  ------------------
  |  Branch (555:17): [True: 2, False: 0]
  ------------------
  556|      2|                if (flags & AI_INT_MERGE_SCENE_GEN_UNIQUE_NAMES_IF_NECESSARY) {
  ------------------
  |  Branch (556:21): [True: 2, False: 0]
  ------------------
  557|      2|                    if (!FindNameMatch((*ppLights)->mName, src, n))
  ------------------
  |  Branch (557:25): [True: 2, False: 0]
  ------------------
  558|      2|                        continue;
  559|      2|                }
  560|       |
  561|      0|                PrefixString((*ppLights)->mName, (*cur).id, (*cur).idlen);
  562|      0|            }
  563|      2|        }
  564|       |
  565|       |        // --------------------------------------------------------------------
  566|       |        // Copy cameras
  567|    564|        for (unsigned int i = 0; i < (*cur)->mNumCameras; ++i, ++ppCameras) {
  ------------------
  |  Branch (567:34): [True: 0, False: 564]
  ------------------
  568|      0|            if (n != (int)duplicates[n]) // duplicate scene?
  ------------------
  |  Branch (568:17): [True: 0, False: 0]
  ------------------
  569|      0|            {
  570|      0|                Copy(ppCameras, (*cur)->mCameras[i]);
  571|      0|            } else
  572|      0|                *ppCameras = (*cur)->mCameras[i];
  573|       |
  574|       |            // Add name prefixes?
  575|      0|            if (flags & AI_INT_MERGE_SCENE_GEN_UNIQUE_NAMES) {
  ------------------
  |  Branch (575:17): [True: 0, False: 0]
  ------------------
  576|      0|                if (flags & AI_INT_MERGE_SCENE_GEN_UNIQUE_NAMES_IF_NECESSARY) {
  ------------------
  |  Branch (576:21): [True: 0, False: 0]
  ------------------
  577|      0|                    if (!FindNameMatch((*ppCameras)->mName, src, n))
  ------------------
  |  Branch (577:25): [True: 0, False: 0]
  ------------------
  578|      0|                        continue;
  579|      0|                }
  580|       |
  581|      0|                PrefixString((*ppCameras)->mName, (*cur).id, (*cur).idlen);
  582|      0|            }
  583|      0|        }
  584|       |
  585|       |        // --------------------------------------------------------------------
  586|       |        // Copy animations
  587|  1.13k|        for (unsigned int i = 0; i < (*cur)->mNumAnimations; ++i, ++ppAnims) {
  ------------------
  |  Branch (587:34): [True: 572, False: 564]
  ------------------
  588|    572|            if (n != (int)duplicates[n]) // duplicate scene?
  ------------------
  |  Branch (588:17): [True: 520, False: 52]
  ------------------
  589|    520|            {
  590|    520|                Copy(ppAnims, (*cur)->mAnimations[i]);
  591|    520|            } else
  592|     52|                *ppAnims = (*cur)->mAnimations[i];
  593|       |
  594|       |            // Add name prefixes?
  595|    572|            if (flags & AI_INT_MERGE_SCENE_GEN_UNIQUE_NAMES) {
  ------------------
  |  Branch (595:17): [True: 572, False: 0]
  ------------------
  596|    572|                if (flags & AI_INT_MERGE_SCENE_GEN_UNIQUE_NAMES_IF_NECESSARY) {
  ------------------
  |  Branch (596:21): [True: 572, False: 0]
  ------------------
  597|    572|                    if (!FindNameMatch((*ppAnims)->mName, src, n))
  ------------------
  |  Branch (597:25): [True: 13, False: 559]
  ------------------
  598|     13|                        continue;
  599|    572|                }
  600|       |
  601|    559|                PrefixString((*ppAnims)->mName, (*cur).id, (*cur).idlen);
  602|       |
  603|       |                // don't forget to update all node animation channels
  604|    699|                for (unsigned int a = 0; a < (*ppAnims)->mNumChannels; ++a) {
  ------------------
  |  Branch (604:42): [True: 140, False: 559]
  ------------------
  605|    140|                    if (flags & AI_INT_MERGE_SCENE_GEN_UNIQUE_NAMES_IF_NECESSARY) {
  ------------------
  |  Branch (605:25): [True: 140, False: 0]
  ------------------
  606|    140|                        if (!FindNameMatch((*ppAnims)->mChannels[a]->mNodeName, src, n))
  ------------------
  |  Branch (606:29): [True: 0, False: 140]
  ------------------
  607|      0|                            continue;
  608|    140|                    }
  609|       |
  610|    140|                    PrefixString((*ppAnims)->mChannels[a]->mNodeName, (*cur).id, (*cur).idlen);
  611|    140|                }
  612|    559|            }
  613|    572|        }
  614|    564|    }
  615|       |
  616|       |    // Now build the output graph
  617|      9|    AttachToGraph(master, nodes);
  618|      9|    dest->mRootNode = master->mRootNode;
  619|       |
  620|       |    // Check whether we succeeded at building the output graph
  621|      9|    for (std::vector<NodeAttachmentInfo>::iterator it = nodes.begin();
  622|    564|            it != nodes.end(); ++it) {
  ------------------
  |  Branch (622:13): [True: 555, False: 9]
  ------------------
  623|    555|        if (!(*it).resolved) {
  ------------------
  |  Branch (623:13): [True: 0, False: 555]
  ------------------
  624|      0|            if (flags & AI_INT_MERGE_SCENE_RESOLVE_CROSS_ATTACHMENTS) {
  ------------------
  |  Branch (624:17): [True: 0, False: 0]
  ------------------
  625|       |                // search for this attachment point in all other imported scenes, too.
  626|      0|                for (unsigned int n = 0; n < src.size(); ++n) {
  ------------------
  |  Branch (626:42): [True: 0, False: 0]
  ------------------
  627|      0|                    if (n != (*it).src_idx) {
  ------------------
  |  Branch (627:25): [True: 0, False: 0]
  ------------------
  628|      0|                        AttachToGraph(src[n].scene, nodes);
  629|      0|                        if ((*it).resolved)
  ------------------
  |  Branch (629:29): [True: 0, False: 0]
  ------------------
  630|      0|                            break;
  631|      0|                    }
  632|      0|                }
  633|      0|            }
  634|      0|            if (!(*it).resolved) {
  ------------------
  |  Branch (634:17): [True: 0, False: 0]
  ------------------
  635|      0|                ASSIMP_LOG_ERROR("SceneCombiner: Failed to resolve attachment ", (*it).node->mName.data,
  636|      0|                        " ", (*it).attachToNode->mName.data);
  637|      0|            }
  638|      0|        }
  639|    555|    }
  640|       |
  641|       |    // now delete all input scenes. Make sure duplicate scenes aren't
  642|       |    // deleted more than one time
  643|    573|    for (unsigned int n = 0; n < src.size(); ++n) {
  ------------------
  |  Branch (643:30): [True: 564, False: 9]
  ------------------
  644|    564|        if (n != duplicates[n]) // duplicate scene?
  ------------------
  |  Branch (644:13): [True: 531, False: 33]
  ------------------
  645|    531|            continue;
  646|       |
  647|     33|        aiScene *deleteMe = src[n].scene;
  648|       |
  649|       |        // We need to delete the arrays before the destructor is called -
  650|       |        // we are reusing the array members
  651|     33|        delete[] deleteMe->mMeshes;
  652|     33|        deleteMe->mMeshes = nullptr;
  653|     33|        delete[] deleteMe->mCameras;
  654|     33|        deleteMe->mCameras = nullptr;
  655|     33|        delete[] deleteMe->mLights;
  656|     33|        deleteMe->mLights = nullptr;
  657|     33|        delete[] deleteMe->mMaterials;
  658|     33|        deleteMe->mMaterials = nullptr;
  659|     33|        delete[] deleteMe->mAnimations;
  660|     33|        deleteMe->mAnimations = nullptr;
  661|     33|        delete[] deleteMe->mTextures;
  662|     33|        deleteMe->mTextures = nullptr;
  663|       |
  664|     33|        deleteMe->mRootNode = nullptr;
  665|       |
  666|       |        // Now we can safely delete the scene
  667|     33|        delete deleteMe;
  668|     33|    }
  669|       |
  670|       |    // Check flags
  671|      9|    if (!dest->mNumMeshes || !dest->mNumMaterials) {
  ------------------
  |  Branch (671:9): [True: 4, False: 5]
  |  Branch (671:30): [True: 0, False: 5]
  ------------------
  672|      4|        dest->mFlags |= AI_SCENE_FLAGS_INCOMPLETE;
  673|      4|    }
  674|       |
  675|       |    // We're finished
  676|      9|}
_ZN6Assimp13SceneCombiner13CopySceneFlatEPP7aiScenePKS1_:
  997|     41|void SceneCombiner::CopySceneFlat(aiScene **_dest, const aiScene *src) {
  998|     41|    if (nullptr == _dest || nullptr == src) {
  ------------------
  |  Branch (998:9): [True: 0, False: 41]
  |  Branch (998:29): [True: 0, False: 41]
  ------------------
  999|      0|        return;
 1000|      0|    }
 1001|       |
 1002|       |    // reuse the old scene or allocate a new?
 1003|     41|    if (*_dest) {
  ------------------
  |  Branch (1003:9): [True: 41, False: 0]
  ------------------
 1004|     41|        (*_dest)->~aiScene();
 1005|     41|        new (*_dest) aiScene();
 1006|     41|    } else {
 1007|      0|        *_dest = new aiScene();
 1008|      0|    }
 1009|     41|    CopyScene(_dest, src, false);
 1010|     41|}
_ZN6Assimp13SceneCombiner9CopySceneEPP7aiScenePKS1_b:
 1013|    249|void SceneCombiner::CopyScene(aiScene **_dest, const aiScene *src, bool allocate) {
 1014|    249|    if (nullptr == _dest || nullptr == src) {
  ------------------
  |  Branch (1014:9): [True: 0, False: 249]
  |  Branch (1014:29): [True: 0, False: 249]
  ------------------
 1015|      0|        return;
 1016|      0|    }
 1017|       |
 1018|    249|    if (allocate) {
  ------------------
  |  Branch (1018:9): [True: 208, False: 41]
  ------------------
 1019|    208|        *_dest = new aiScene();
 1020|    208|    }
 1021|    249|    aiScene *dest = *_dest;
 1022|    249|    ai_assert(nullptr != dest);
  ------------------
  |  |   67|    249|#   define ai_assert(expression) (void)((!!(expression)) || (Assimp::aiAssertViolation(#expression, __FILE__, __LINE__), 0))
  |  |  ------------------
  |  |  |  Branch (67:41): [True: 249, False: 0]
  |  |  |  Branch (67:61): [True: 0, False: 0]
  |  |  ------------------
  ------------------
 1023|       |
 1024|       |    // copy metadata
 1025|    249|    if (nullptr != src->mMetaData) {
  ------------------
  |  Branch (1025:9): [True: 208, False: 41]
  ------------------
 1026|    208|        dest->mMetaData = new aiMetadata(*src->mMetaData);
 1027|    208|    }
 1028|       |
 1029|       |    // copy animations
 1030|    249|    dest->mNumAnimations = src->mNumAnimations;
 1031|    249|    CopyPtrArray(dest->mAnimations, src->mAnimations,
 1032|    249|            dest->mNumAnimations);
 1033|       |
 1034|       |    // copy textures
 1035|    249|    dest->mNumTextures = src->mNumTextures;
 1036|    249|    CopyPtrArray(dest->mTextures, src->mTextures,
 1037|    249|            dest->mNumTextures);
 1038|       |
 1039|       |    // copy materials
 1040|    249|    dest->mNumMaterials = src->mNumMaterials;
 1041|    249|    CopyPtrArray(dest->mMaterials, src->mMaterials,
 1042|    249|            dest->mNumMaterials);
 1043|       |
 1044|       |    // copy lights
 1045|    249|    dest->mNumLights = src->mNumLights;
 1046|    249|    CopyPtrArray(dest->mLights, src->mLights,
 1047|    249|            dest->mNumLights);
 1048|       |
 1049|       |    // copy cameras
 1050|    249|    dest->mNumCameras = src->mNumCameras;
 1051|    249|    CopyPtrArray(dest->mCameras, src->mCameras,
 1052|    249|            dest->mNumCameras);
 1053|       |
 1054|       |    // copy meshes
 1055|    249|    dest->mNumMeshes = src->mNumMeshes;
 1056|    249|    CopyPtrArray(dest->mMeshes, src->mMeshes,
 1057|    249|            dest->mNumMeshes);
 1058|       |
 1059|       |    // now - copy the root node of the scene (deep copy, too)
 1060|    249|    Copy(&dest->mRootNode, src->mRootNode);
 1061|       |
 1062|       |    // and keep the flags ...
 1063|    249|    dest->mFlags = src->mFlags;
 1064|       |
 1065|       |    // source private data might be nullptr if the scene is user-allocated (i.e. for use with the export API)
 1066|    249|    if (src->mPrivate != nullptr) {
  ------------------
  |  Branch (1066:9): [True: 249, False: 0]
  ------------------
 1067|    249|        ScenePriv(dest)->mPPStepsApplied = ScenePriv(src) ? ScenePriv(src)->mPPStepsApplied : 0;
  ------------------
  |  Branch (1067:44): [True: 249, False: 0]
  ------------------
 1068|    249|    }
 1069|    249|}
_ZN6Assimp13SceneCombiner4CopyEPP6aiMeshPKS1_:
 1072|  3.58k|void SceneCombiner::Copy(aiMesh **_dest, const aiMesh *src) {
 1073|  3.58k|    if (nullptr == _dest || nullptr == src) {
  ------------------
  |  Branch (1073:9): [True: 0, False: 3.58k]
  |  Branch (1073:29): [True: 0, False: 3.58k]
  ------------------
 1074|      0|        return;
 1075|      0|    }
 1076|       |
 1077|  3.58k|    aiMesh *dest = *_dest = new aiMesh();
 1078|       |
 1079|       |    // get a flat copy
 1080|  3.58k|    *dest = *src;
 1081|       |
 1082|       |    // and reallocate all arrays
 1083|  3.58k|    GetArrayCopy(dest->mVertices, dest->mNumVertices);
 1084|  3.58k|    GetArrayCopy(dest->mNormals, dest->mNumVertices);
 1085|  3.58k|    GetArrayCopy(dest->mTangents, dest->mNumVertices);
 1086|  3.58k|    GetArrayCopy(dest->mBitangents, dest->mNumVertices);
 1087|       |
 1088|  3.58k|    unsigned int n = 0;
 1089|  3.86k|    while (dest->HasTextureCoords(n)) {
  ------------------
  |  Branch (1089:12): [True: 277, False: 3.58k]
  ------------------
 1090|    277|        GetArrayCopy(dest->mTextureCoords[n++], dest->mNumVertices);
 1091|    277|    }
 1092|       |
 1093|  3.58k|    n = 0;
 1094|  3.80k|    while (dest->HasVertexColors(n)) {
  ------------------
  |  Branch (1094:12): [True: 216, False: 3.58k]
  ------------------
 1095|    216|        GetArrayCopy(dest->mColors[n++], dest->mNumVertices);
 1096|    216|    }
 1097|       |
 1098|       |    // make a deep copy of all bones
 1099|  3.58k|    CopyPtrArray(dest->mBones, dest->mBones, dest->mNumBones);
 1100|       |
 1101|       |    // make a deep copy of all faces
 1102|  3.58k|    GetArrayCopy(dest->mFaces, dest->mNumFaces);
 1103|       |
 1104|       |    // make a deep copy of all blend shapes
 1105|  3.58k|    CopyPtrArray(dest->mAnimMeshes, dest->mAnimMeshes, dest->mNumAnimMeshes);
 1106|       |
 1107|       |    // make a deep copy of all texture coordinate names
 1108|  3.58k|    if (src->mTextureCoordsNames != nullptr) {
  ------------------
  |  Branch (1108:9): [True: 0, False: 3.58k]
  ------------------
 1109|      0|        dest->mTextureCoordsNames = new aiString *[AI_MAX_NUMBER_OF_TEXTURECOORDS] {};
 1110|      0|        for (unsigned int i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++i) {
  ------------------
  |  Branch (1110:34): [True: 0, False: 0]
  ------------------
 1111|      0|            Copy(&dest->mTextureCoordsNames[i], src->mTextureCoordsNames[i]);
 1112|      0|        }
 1113|      0|    }
 1114|  3.58k|}
_ZN6Assimp13SceneCombiner4CopyEPP10aiMaterialPKS1_:
 1143|    259|void SceneCombiner::Copy(aiMaterial **_dest, const aiMaterial *src) {
 1144|    259|    if (nullptr == _dest || nullptr == src) {
  ------------------
  |  Branch (1144:9): [True: 0, False: 259]
  |  Branch (1144:29): [True: 0, False: 259]
  ------------------
 1145|      0|        return;
 1146|      0|    }
 1147|       |
 1148|    259|    aiMaterial *dest = (aiMaterial *)(*_dest = new aiMaterial());
 1149|       |
 1150|    259|    dest->Clear();
 1151|    259|    delete[] dest->mProperties;
 1152|       |
 1153|    259|    dest->mNumAllocated = src->mNumAllocated;
 1154|    259|    dest->mNumProperties = src->mNumProperties;
 1155|    259|    dest->mProperties = new aiMaterialProperty *[dest->mNumAllocated];
 1156|       |
 1157|  3.61k|    for (unsigned int i = 0; i < dest->mNumProperties; ++i) {
  ------------------
  |  Branch (1157:30): [True: 3.35k, False: 259]
  ------------------
 1158|  3.35k|        aiMaterialProperty *prop = dest->mProperties[i] = new aiMaterialProperty();
 1159|  3.35k|        aiMaterialProperty *sprop = src->mProperties[i];
 1160|       |
 1161|  3.35k|        prop->mDataLength = sprop->mDataLength;
 1162|  3.35k|        prop->mData = new char[prop->mDataLength];
 1163|  3.35k|        ::memcpy(prop->mData, sprop->mData, prop->mDataLength);
 1164|       |
 1165|  3.35k|        prop->mIndex = sprop->mIndex;
 1166|  3.35k|        prop->mSemantic = sprop->mSemantic;
 1167|  3.35k|        prop->mKey = sprop->mKey;
 1168|  3.35k|        prop->mType = sprop->mType;
 1169|  3.35k|    }
 1170|    259|}
_ZN6Assimp13SceneCombiner4CopyEPP9aiTexturePKS1_:
 1173|      7|void SceneCombiner::Copy(aiTexture **_dest, const aiTexture *src) {
 1174|      7|    if (nullptr == _dest || nullptr == src) {
  ------------------
  |  Branch (1174:9): [True: 0, False: 7]
  |  Branch (1174:29): [True: 0, False: 7]
  ------------------
 1175|      0|        return;
 1176|      0|    }
 1177|       |
 1178|      7|    aiTexture *dest = *_dest = new aiTexture();
 1179|       |
 1180|       |    // get a flat copy
 1181|      7|    *dest = *src;
 1182|       |
 1183|       |    // and reallocate all arrays. We must do it manually here
 1184|      7|    const char *old = (const char *)dest->pcData;
 1185|      7|    if (old) {
  ------------------
  |  Branch (1185:9): [True: 7, False: 0]
  ------------------
 1186|      7|        unsigned int cpy;
 1187|      7|        if (!dest->mHeight)
  ------------------
  |  Branch (1187:13): [True: 4, False: 3]
  ------------------
 1188|      4|            cpy = dest->mWidth;
 1189|      3|        else
 1190|      3|            cpy = dest->mHeight * dest->mWidth * sizeof(aiTexel);
 1191|       |
 1192|      7|        if (!cpy) {
  ------------------
  |  Branch (1192:13): [True: 0, False: 7]
  ------------------
 1193|      0|            dest->pcData = nullptr;
 1194|      0|            return;
 1195|      0|        }
 1196|       |        // the cast is legal, the aiTexel c'tor does nothing important
 1197|      7|        dest->pcData = (aiTexel *)new char[cpy];
 1198|      7|        ::memcpy(dest->pcData, old, cpy);
 1199|      7|    }
 1200|      7|}
_ZN6Assimp13SceneCombiner4CopyEPP11aiAnimationPKS1_:
 1203|    559|void SceneCombiner::Copy(aiAnimation **_dest, const aiAnimation *src) {
 1204|    559|    if (nullptr == _dest || nullptr == src) {
  ------------------
  |  Branch (1204:9): [True: 0, False: 559]
  |  Branch (1204:29): [True: 0, False: 559]
  ------------------
 1205|      0|        return;
 1206|      0|    }
 1207|       |
 1208|    559|    aiAnimation *dest = *_dest = new aiAnimation();
 1209|       |
 1210|       |    // get a flat copy
 1211|    559|    *dest = *src;
 1212|       |
 1213|       |    // and reallocate all arrays
 1214|    559|    CopyPtrArray(dest->mChannels, src->mChannels, dest->mNumChannels);
 1215|    559|    CopyPtrArray(dest->mMorphMeshChannels, src->mMorphMeshChannels, dest->mNumMorphMeshChannels);
 1216|    559|}
_ZN6Assimp13SceneCombiner4CopyEPP10aiNodeAnimPKS1_:
 1219|  1.00k|void SceneCombiner::Copy(aiNodeAnim **_dest, const aiNodeAnim *src) {
 1220|  1.00k|    if (nullptr == _dest || nullptr == src) {
  ------------------
  |  Branch (1220:9): [True: 0, False: 1.00k]
  |  Branch (1220:29): [True: 0, False: 1.00k]
  ------------------
 1221|      0|        return;
 1222|      0|    }
 1223|       |
 1224|  1.00k|    aiNodeAnim *dest = *_dest = new aiNodeAnim();
 1225|       |
 1226|       |    // get a flat copy
 1227|  1.00k|    *dest = *src;
 1228|       |
 1229|       |    // and reallocate all arrays
 1230|  1.00k|    GetArrayCopy(dest->mPositionKeys, dest->mNumPositionKeys);
 1231|  1.00k|    GetArrayCopy(dest->mScalingKeys, dest->mNumScalingKeys);
 1232|  1.00k|    GetArrayCopy(dest->mRotationKeys, dest->mNumRotationKeys);
 1233|  1.00k|}
_ZN6Assimp13SceneCombiner4CopyEPP8aiCameraPKS1_:
 1256|     57|void SceneCombiner::Copy(aiCamera **_dest, const aiCamera *src) {
 1257|     57|    if (nullptr == _dest || nullptr == src) {
  ------------------
  |  Branch (1257:9): [True: 0, False: 57]
  |  Branch (1257:29): [True: 0, False: 57]
  ------------------
 1258|      0|        return;
 1259|      0|    }
 1260|       |
 1261|     57|    aiCamera *dest = *_dest = new aiCamera();
 1262|       |
 1263|       |    // get a flat copy, that's already OK
 1264|     57|    *dest = *src;
 1265|     57|}
_ZN6Assimp13SceneCombiner4CopyEPP7aiLightPKS1_:
 1268|     67|void SceneCombiner::Copy(aiLight **_dest, const aiLight *src) {
 1269|     67|    if (nullptr == _dest || nullptr == src) {
  ------------------
  |  Branch (1269:9): [True: 0, False: 67]
  |  Branch (1269:29): [True: 0, False: 67]
  ------------------
 1270|      0|        return;
 1271|      0|    }
 1272|       |
 1273|     67|    aiLight *dest = *_dest = new aiLight();
 1274|       |
 1275|       |    // get a flat copy, that's already OK
 1276|     67|    *dest = *src;
 1277|     67|}
_ZN6Assimp13SceneCombiner4CopyEPP6aiBonePKS1_:
 1280|  3.08k|void SceneCombiner::Copy(aiBone **_dest, const aiBone *src) {
 1281|  3.08k|    if (nullptr == _dest || nullptr == src) {
  ------------------
  |  Branch (1281:9): [True: 0, False: 3.08k]
  |  Branch (1281:29): [True: 0, False: 3.08k]
  ------------------
 1282|      0|        return;
 1283|      0|    }
 1284|       |
 1285|  3.08k|    aiBone *dest = *_dest = new aiBone();
 1286|       |
 1287|       |    // get a flat copy
 1288|  3.08k|    *dest = *src;
 1289|  3.08k|}
_ZN6Assimp13SceneCombiner4CopyEPP6aiNodePKS1_:
 1292|  68.5k|void SceneCombiner::Copy(aiNode **_dest, const aiNode *src) {
 1293|  68.5k|    ai_assert(nullptr != _dest);
  ------------------
  |  |   67|  68.5k|#   define ai_assert(expression) (void)((!!(expression)) || (Assimp::aiAssertViolation(#expression, __FILE__, __LINE__), 0))
  |  |  ------------------
  |  |  |  Branch (67:41): [True: 68.5k, False: 0]
  |  |  |  Branch (67:61): [True: 0, False: 0]
  |  |  ------------------
  ------------------
 1294|  68.5k|    ai_assert(nullptr != src);
  ------------------
  |  |   67|  68.5k|#   define ai_assert(expression) (void)((!!(expression)) || (Assimp::aiAssertViolation(#expression, __FILE__, __LINE__), 0))
  |  |  ------------------
  |  |  |  Branch (67:41): [True: 68.5k, False: 0]
  |  |  |  Branch (67:61): [True: 0, False: 0]
  |  |  ------------------
  ------------------
 1295|       |
 1296|  68.5k|    aiNode *dest = *_dest = new aiNode();
 1297|       |
 1298|       |    // get a flat copy
 1299|  68.5k|    *dest = *src;
 1300|       |
 1301|  68.5k|    if (src->mMetaData) {
  ------------------
  |  Branch (1301:9): [True: 14, False: 68.5k]
  ------------------
 1302|     14|        Copy(&dest->mMetaData, src->mMetaData);
 1303|     14|    }
 1304|       |
 1305|       |    // and reallocate all arrays
 1306|  68.5k|    GetArrayCopy(dest->mMeshes, dest->mNumMeshes);
 1307|  68.5k|    CopyPtrArray(dest->mChildren, src->mChildren, dest->mNumChildren);
 1308|       |
 1309|       |    // need to set the mParent fields to the created aiNode.
 1310|   136k|    for (unsigned int i = 0; i < dest->mNumChildren; i++) {
  ------------------
  |  Branch (1310:30): [True: 67.7k, False: 68.5k]
  ------------------
 1311|  67.7k|        dest->mChildren[i]->mParent = dest;
 1312|  67.7k|    }
 1313|  68.5k|}
_ZN6Assimp13SceneCombiner4CopyEPP10aiMetadataPKS1_:
 1316|     14|void SceneCombiner::Copy(aiMetadata **_dest, const aiMetadata *src) {
 1317|     14|    if (nullptr == _dest || nullptr == src) {
  ------------------
  |  Branch (1317:9): [True: 0, False: 14]
  |  Branch (1317:29): [True: 0, False: 14]
  ------------------
 1318|      0|        return;
 1319|      0|    }
 1320|       |
 1321|     14|    if (0 == src->mNumProperties) {
  ------------------
  |  Branch (1321:9): [True: 0, False: 14]
  ------------------
 1322|      0|        return;
 1323|      0|    }
 1324|       |
 1325|     14|    aiMetadata *dest = *_dest = aiMetadata::Alloc(src->mNumProperties);
 1326|     14|    std::copy(src->mKeys, src->mKeys + src->mNumProperties, dest->mKeys);
 1327|       |
 1328|    124|    for (unsigned int i = 0; i < src->mNumProperties; ++i) {
  ------------------
  |  Branch (1328:30): [True: 110, False: 14]
  ------------------
 1329|    110|        aiMetadataEntry &in = src->mValues[i];
 1330|    110|        aiMetadataEntry &out = dest->mValues[i];
 1331|    110|        out.mType = in.mType;
 1332|    110|        switch (dest->mValues[i].mType) {
 1333|      0|        case AI_BOOL:
  ------------------
  |  Branch (1333:9): [True: 0, False: 110]
  ------------------
 1334|      0|            out.mData = new bool(*static_cast<bool *>(in.mData));
 1335|      0|            break;
 1336|     68|        case AI_INT32:
  ------------------
  |  Branch (1336:9): [True: 68, False: 42]
  ------------------
 1337|     68|            out.mData = new int32_t(*static_cast<int32_t *>(in.mData));
 1338|     68|            break;
 1339|      0|        case AI_UINT64:
  ------------------
  |  Branch (1339:9): [True: 0, False: 110]
  ------------------
 1340|      0|            out.mData = new uint64_t(*static_cast<uint64_t *>(in.mData));
 1341|      0|            break;
 1342|      3|        case AI_FLOAT:
  ------------------
  |  Branch (1342:9): [True: 3, False: 107]
  ------------------
 1343|      3|            out.mData = new float(*static_cast<float *>(in.mData));
 1344|      3|            break;
 1345|      0|        case AI_DOUBLE:
  ------------------
  |  Branch (1345:9): [True: 0, False: 110]
  ------------------
 1346|      0|            out.mData = new double(*static_cast<double *>(in.mData));
 1347|      0|            break;
 1348|     11|        case AI_AISTRING:
  ------------------
  |  Branch (1348:9): [True: 11, False: 99]
  ------------------
 1349|     11|            out.mData = new aiString(*static_cast<aiString *>(in.mData));
 1350|     11|            break;
 1351|     28|        case AI_AIVECTOR3D:
  ------------------
  |  Branch (1351:9): [True: 28, False: 82]
  ------------------
 1352|     28|            out.mData = new aiVector3D(*static_cast<aiVector3D *>(in.mData));
 1353|     28|            break;
 1354|      0|        case AI_AIMETADATA:
  ------------------
  |  Branch (1354:9): [True: 0, False: 110]
  ------------------
 1355|      0|            out.mData = new aiMetadata(*static_cast<aiMetadata *>(in.mData));
 1356|      0|            break;
 1357|      0|        default:
  ------------------
  |  Branch (1357:9): [True: 0, False: 110]
  ------------------
 1358|      0|            ai_assert(false);
  ------------------
  |  |   67|      0|#   define ai_assert(expression) (void)((!!(expression)) || (Assimp::aiAssertViolation(#expression, __FILE__, __LINE__), 0))
  |  |  ------------------
  |  |  |  Branch (67:41): [Folded, False: 0]
  |  |  |  Branch (67:61): [True: 0, False: 0]
  |  |  ------------------
  ------------------
 1359|      0|            break;
 1360|    110|        }
 1361|    110|    }
 1362|     14|}
_ZN6Assimp12PrefixStringER8aiStringPKcj:
   77|  12.9k|inline void PrefixString(aiString &string, const char *prefix, unsigned int len) {
   78|       |    // If the string is already prefixed, we won't prefix it a second time
   79|  12.9k|    if (string.length >= 1 && string.data[0] == '$')
  ------------------
  |  Branch (79:9): [True: 12.4k, False: 427]
  |  Branch (79:31): [True: 12, False: 12.4k]
  ------------------
   80|     12|        return;
   81|       |
   82|  12.8k|    if (len + string.length >= AI_MAXLEN - 1) {
  ------------------
  |  Branch (82:9): [True: 0, False: 12.8k]
  ------------------
   83|      0|        ASSIMP_LOG_VERBOSE_DEBUG("Can't add an unique prefix because the string is too long");
   84|      0|        ai_assert(false);
  ------------------
  |  |   67|      0|#   define ai_assert(expression) (void)((!!(expression)) || (Assimp::aiAssertViolation(#expression, __FILE__, __LINE__), 0))
  |  |  ------------------
  |  |  |  Branch (67:41): [Folded, False: 0]
  |  |  |  Branch (67:61): [True: 0, False: 0]
  |  |  ------------------
  ------------------
   85|      0|        return;
   86|      0|    }
   87|       |
   88|       |    // Add the prefix
   89|  12.8k|    ::memmove(string.data + len, string.data, string.length + 1);
   90|  12.8k|    ::memcpy(string.data, prefix, len);
   91|       |
   92|       |    // And update the string's length
   93|  12.8k|    string.length += len;
   94|  12.8k|}
_ZN6Assimp12CopyPtrArrayI11aiAnimationEEvRPPT_PKPKS2_j:
  973|    249|inline void CopyPtrArray(Type **&dest, const Type *const *src, ai_uint num) {
  974|    249|    if (!num) {
  ------------------
  |  Branch (974:9): [True: 213, False: 36]
  ------------------
  975|    213|        dest = nullptr;
  976|    213|        return;
  977|    213|    }
  978|     36|    dest = new Type *[num];
  979|     75|    for (ai_uint i = 0; i < num; ++i) {
  ------------------
  |  Branch (979:25): [True: 39, False: 36]
  ------------------
  980|     39|        SceneCombiner::Copy(&dest[i], src[i]);
  981|     39|    }
  982|     36|}
_ZN6Assimp12CopyPtrArrayI9aiTextureEEvRPPT_PKPKS2_j:
  973|    249|inline void CopyPtrArray(Type **&dest, const Type *const *src, ai_uint num) {
  974|    249|    if (!num) {
  ------------------
  |  Branch (974:9): [True: 242, False: 7]
  ------------------
  975|    242|        dest = nullptr;
  976|    242|        return;
  977|    242|    }
  978|      7|    dest = new Type *[num];
  979|     14|    for (ai_uint i = 0; i < num; ++i) {
  ------------------
  |  Branch (979:25): [True: 7, False: 7]
  ------------------
  980|      7|        SceneCombiner::Copy(&dest[i], src[i]);
  981|      7|    }
  982|      7|}
_ZN6Assimp12CopyPtrArrayI10aiMaterialEEvRPPT_PKPKS2_j:
  973|    249|inline void CopyPtrArray(Type **&dest, const Type *const *src, ai_uint num) {
  974|    249|    if (!num) {
  ------------------
  |  Branch (974:9): [True: 71, False: 178]
  ------------------
  975|     71|        dest = nullptr;
  976|     71|        return;
  977|     71|    }
  978|    178|    dest = new Type *[num];
  979|    437|    for (ai_uint i = 0; i < num; ++i) {
  ------------------
  |  Branch (979:25): [True: 259, False: 178]
  ------------------
  980|    259|        SceneCombiner::Copy(&dest[i], src[i]);
  981|    259|    }
  982|    178|}
_ZN6Assimp12CopyPtrArrayI7aiLightEEvRPPT_PKPKS2_j:
  973|    249|inline void CopyPtrArray(Type **&dest, const Type *const *src, ai_uint num) {
  974|    249|    if (!num) {
  ------------------
  |  Branch (974:9): [True: 204, False: 45]
  ------------------
  975|    204|        dest = nullptr;
  976|    204|        return;
  977|    204|    }
  978|     45|    dest = new Type *[num];
  979|    112|    for (ai_uint i = 0; i < num; ++i) {
  ------------------
  |  Branch (979:25): [True: 67, False: 45]
  ------------------
  980|     67|        SceneCombiner::Copy(&dest[i], src[i]);
  981|     67|    }
  982|     45|}
_ZN6Assimp12CopyPtrArrayI8aiCameraEEvRPPT_PKPKS2_j:
  973|    249|inline void CopyPtrArray(Type **&dest, const Type *const *src, ai_uint num) {
  974|    249|    if (!num) {
  ------------------
  |  Branch (974:9): [True: 204, False: 45]
  ------------------
  975|    204|        dest = nullptr;
  976|    204|        return;
  977|    204|    }
  978|     45|    dest = new Type *[num];
  979|    102|    for (ai_uint i = 0; i < num; ++i) {
  ------------------
  |  Branch (979:25): [True: 57, False: 45]
  ------------------
  980|     57|        SceneCombiner::Copy(&dest[i], src[i]);
  981|     57|    }
  982|     45|}
_ZN6Assimp12CopyPtrArrayI6aiMeshEEvRPPT_PKPKS2_j:
  973|    249|inline void CopyPtrArray(Type **&dest, const Type *const *src, ai_uint num) {
  974|    249|    if (!num) {
  ------------------
  |  Branch (974:9): [True: 71, False: 178]
  ------------------
  975|     71|        dest = nullptr;
  976|     71|        return;
  977|     71|    }
  978|    178|    dest = new Type *[num];
  979|  3.76k|    for (ai_uint i = 0; i < num; ++i) {
  ------------------
  |  Branch (979:25): [True: 3.58k, False: 178]
  ------------------
  980|  3.58k|        SceneCombiner::Copy(&dest[i], src[i]);
  981|  3.58k|    }
  982|    178|}
_ZN6Assimp12GetArrayCopyI10aiVector3tIfEEEvRPT_j:
  986|  14.6k|inline void GetArrayCopy(Type *&dest, ai_uint num) {
  987|  14.6k|    if (!dest) {
  ------------------
  |  Branch (987:9): [True: 7.68k, False: 6.93k]
  ------------------
  988|  7.68k|        return;
  989|  7.68k|    }
  990|  6.93k|    Type *old = dest;
  991|       |
  992|  6.93k|    dest = new Type[num];
  993|  6.93k|    std::copy(old, old+num, dest);
  994|  6.93k|}
_ZN6Assimp12GetArrayCopyI9aiColor4tIfEEEvRPT_j:
  986|    216|inline void GetArrayCopy(Type *&dest, ai_uint num) {
  987|    216|    if (!dest) {
  ------------------
  |  Branch (987:9): [True: 0, False: 216]
  ------------------
  988|      0|        return;
  989|      0|    }
  990|    216|    Type *old = dest;
  991|       |
  992|    216|    dest = new Type[num];
  993|    216|    std::copy(old, old+num, dest);
  994|    216|}
_ZN6Assimp12CopyPtrArrayI6aiBoneEEvRPPT_PKPKS2_j:
  973|  3.58k|inline void CopyPtrArray(Type **&dest, const Type *const *src, ai_uint num) {
  974|  3.58k|    if (!num) {
  ------------------
  |  Branch (974:9): [True: 3.56k, False: 27]
  ------------------
  975|  3.56k|        dest = nullptr;
  976|  3.56k|        return;
  977|  3.56k|    }
  978|     27|    dest = new Type *[num];
  979|  3.11k|    for (ai_uint i = 0; i < num; ++i) {
  ------------------
  |  Branch (979:25): [True: 3.08k, False: 27]
  ------------------
  980|  3.08k|        SceneCombiner::Copy(&dest[i], src[i]);
  981|  3.08k|    }
  982|     27|}
_ZN6Assimp12GetArrayCopyI6aiFaceEEvRPT_j:
  986|  3.58k|inline void GetArrayCopy(Type *&dest, ai_uint num) {
  987|  3.58k|    if (!dest) {
  ------------------
  |  Branch (987:9): [True: 0, False: 3.58k]
  ------------------
  988|      0|        return;
  989|      0|    }
  990|  3.58k|    Type *old = dest;
  991|       |
  992|  3.58k|    dest = new Type[num];
  993|  3.58k|    std::copy(old, old+num, dest);
  994|  3.58k|}
_ZN6Assimp12CopyPtrArrayI10aiAnimMeshEEvRPPT_PKPKS2_j:
  973|  3.58k|inline void CopyPtrArray(Type **&dest, const Type *const *src, ai_uint num) {
  974|  3.58k|    if (!num) {
  ------------------
  |  Branch (974:9): [True: 3.58k, False: 0]
  ------------------
  975|  3.58k|        dest = nullptr;
  976|  3.58k|        return;
  977|  3.58k|    }
  978|      0|    dest = new Type *[num];
  979|      0|    for (ai_uint i = 0; i < num; ++i) {
  ------------------
  |  Branch (979:25): [True: 0, False: 0]
  ------------------
  980|      0|        SceneCombiner::Copy(&dest[i], src[i]);
  981|      0|    }
  982|      0|}
_ZN6Assimp12CopyPtrArrayI10aiNodeAnimEEvRPPT_PKPKS2_j:
  973|    559|inline void CopyPtrArray(Type **&dest, const Type *const *src, ai_uint num) {
  974|    559|    if (!num) {
  ------------------
  |  Branch (974:9): [True: 415, False: 144]
  ------------------
  975|    415|        dest = nullptr;
  976|    415|        return;
  977|    415|    }
  978|    144|    dest = new Type *[num];
  979|  1.15k|    for (ai_uint i = 0; i < num; ++i) {
  ------------------
  |  Branch (979:25): [True: 1.00k, False: 144]
  ------------------
  980|  1.00k|        SceneCombiner::Copy(&dest[i], src[i]);
  981|  1.00k|    }
  982|    144|}
_ZN6Assimp12CopyPtrArrayI15aiMeshMorphAnimEEvRPPT_PKPKS2_j:
  973|    559|inline void CopyPtrArray(Type **&dest, const Type *const *src, ai_uint num) {
  974|    559|    if (!num) {
  ------------------
  |  Branch (974:9): [True: 559, False: 0]
  ------------------
  975|    559|        dest = nullptr;
  976|    559|        return;
  977|    559|    }
  978|      0|    dest = new Type *[num];
  979|      0|    for (ai_uint i = 0; i < num; ++i) {
  ------------------
  |  Branch (979:25): [True: 0, False: 0]
  ------------------
  980|      0|        SceneCombiner::Copy(&dest[i], src[i]);
  981|      0|    }
  982|      0|}
_ZN6Assimp12GetArrayCopyI11aiVectorKeyEEvRPT_j:
  986|  2.01k|inline void GetArrayCopy(Type *&dest, ai_uint num) {
  987|  2.01k|    if (!dest) {
  ------------------
  |  Branch (987:9): [True: 507, False: 1.51k]
  ------------------
  988|    507|        return;
  989|    507|    }
  990|  1.51k|    Type *old = dest;
  991|       |
  992|  1.51k|    dest = new Type[num];
  993|  1.51k|    std::copy(old, old+num, dest);
  994|  1.51k|}
_ZN6Assimp12GetArrayCopyI9aiQuatKeyEEvRPT_j:
  986|  1.00k|inline void GetArrayCopy(Type *&dest, ai_uint num) {
  987|  1.00k|    if (!dest) {
  ------------------
  |  Branch (987:9): [True: 381, False: 628]
  ------------------
  988|    381|        return;
  989|    381|    }
  990|    628|    Type *old = dest;
  991|       |
  992|    628|    dest = new Type[num];
  993|    628|    std::copy(old, old+num, dest);
  994|    628|}
_ZN6Assimp12GetArrayCopyIjEEvRPT_j:
  986|  68.5k|inline void GetArrayCopy(Type *&dest, ai_uint num) {
  987|  68.5k|    if (!dest) {
  ------------------
  |  Branch (987:9): [True: 20.7k, False: 47.7k]
  ------------------
  988|  20.7k|        return;
  989|  20.7k|    }
  990|  47.7k|    Type *old = dest;
  991|       |
  992|  47.7k|    dest = new Type[num];
  993|  47.7k|    std::copy(old, old+num, dest);
  994|  47.7k|}
_ZN6Assimp12CopyPtrArrayI6aiNodeEEvRPPT_PKPKS2_j:
  973|  68.5k|inline void CopyPtrArray(Type **&dest, const Type *const *src, ai_uint num) {
  974|  68.5k|    if (!num) {
  ------------------
  |  Branch (974:9): [True: 47.0k, False: 21.4k]
  ------------------
  975|  47.0k|        dest = nullptr;
  976|  47.0k|        return;
  977|  47.0k|    }
  978|  21.4k|    dest = new Type *[num];
  979|  89.2k|    for (ai_uint i = 0; i < num; ++i) {
  ------------------
  |  Branch (979:25): [True: 67.7k, False: 21.4k]
  ------------------
  980|  67.7k|        SceneCombiner::Copy(&dest[i], src[i]);
  981|  67.7k|    }
  982|  21.4k|}

_ZN6Assimp17ScenePreprocessor12ProcessSceneEv:
   50|    241|void ScenePreprocessor::ProcessScene() {
   51|    241|    ai_assert(scene != nullptr);
  ------------------
  |  |   67|    241|#   define ai_assert(expression) (void)((!!(expression)) || (Assimp::aiAssertViolation(#expression, __FILE__, __LINE__), 0))
  |  |  ------------------
  |  |  |  Branch (67:41): [True: 241, False: 0]
  |  |  |  Branch (67:61): [True: 0, False: 0]
  |  |  ------------------
  ------------------
   52|       |
   53|       |    // Process all meshes
   54|  5.09k|    for (unsigned int i = 0; i < scene->mNumMeshes; ++i) {
  ------------------
  |  Branch (54:30): [True: 4.85k, False: 241]
  ------------------
   55|  4.85k|        if (nullptr == scene->mMeshes[i]) {
  ------------------
  |  Branch (55:13): [True: 0, False: 4.85k]
  ------------------
   56|      0|            continue;
   57|      0|        }
   58|  4.85k|        ProcessMesh(scene->mMeshes[i]);
   59|  4.85k|    }
   60|       |
   61|       |    // - nothing to do for nodes for the moment
   62|       |    // - nothing to do for textures for the moment
   63|       |    // - nothing to do for lights for the moment
   64|       |    // - nothing to do for cameras for the moment
   65|       |
   66|       |    // Process all animations
   67|    335|    for (unsigned int i = 0; i < scene->mNumAnimations; ++i) {
  ------------------
  |  Branch (67:30): [True: 94, False: 241]
  ------------------
   68|     94|        if (nullptr == scene->mAnimations[i]) {
  ------------------
  |  Branch (68:13): [True: 0, False: 94]
  ------------------
   69|      0|            continue;
   70|      0|        }
   71|     94|        ProcessAnimation(scene->mAnimations[i]);
   72|     94|    }
   73|       |
   74|       |    // Generate a default material if none was specified
   75|    241|    if (!scene->mNumMaterials && scene->mNumMeshes) {
  ------------------
  |  Branch (75:9): [True: 55, False: 186]
  |  Branch (75:34): [True: 7, False: 48]
  ------------------
   76|      7|        scene->mMaterials = new aiMaterial *[2];
   77|      7|        aiMaterial *helper;
   78|       |
   79|      7|        aiString name;
   80|       |
   81|      7|        scene->mMaterials[scene->mNumMaterials] = helper = new aiMaterial();
   82|      7|        aiColor3D clr(0.6f, 0.6f, 0.6f);
   83|      7|        helper->AddProperty(&clr, 1, AI_MATKEY_COLOR_DIFFUSE);
   84|       |
   85|       |        // setup the default name to make this material identifiable
   86|      7|        name.Set(AI_DEFAULT_MATERIAL_NAME);
   87|      7|        helper->AddProperty(&name, AI_MATKEY_NAME);
   88|       |
   89|      7|        ASSIMP_LOG_DEBUG("ScenePreprocessor: Adding default material \'" AI_DEFAULT_MATERIAL_NAME "\'");
   90|       |
   91|     80|        for (unsigned int i = 0; i < scene->mNumMeshes; ++i) {
  ------------------
  |  Branch (91:34): [True: 73, False: 7]
  ------------------
   92|     73|            if (nullptr == scene->mMeshes[i]) {
  ------------------
  |  Branch (92:17): [True: 0, False: 73]
  ------------------
   93|      0|                continue;
   94|      0|            }
   95|     73|            scene->mMeshes[i]->mMaterialIndex = scene->mNumMaterials;
   96|     73|        }
   97|       |
   98|      7|        scene->mNumMaterials++;
   99|      7|    }
  100|    241|}
_ZN6Assimp17ScenePreprocessor11ProcessMeshEP6aiMesh:
  103|  4.85k|void ScenePreprocessor::ProcessMesh(aiMesh *mesh) {
  104|       |    // If aiMesh::mNumUVComponents is *not* set assign the default value of 2
  105|  43.6k|    for (unsigned int i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++i) {
  ------------------
  |  Branch (105:30): [True: 38.8k, False: 4.85k]
  ------------------
  106|  38.8k|        if (!mesh->mTextureCoords[i]) {
  ------------------
  |  Branch (106:13): [True: 38.5k, False: 293]
  ------------------
  107|  38.5k|            mesh->mNumUVComponents[i] = 0;
  108|  38.5k|            continue;
  109|  38.5k|        }
  110|       |
  111|    293|        if (!mesh->mNumUVComponents[i]) {
  ------------------
  |  Branch (111:13): [True: 59, False: 234]
  ------------------
  112|     59|            mesh->mNumUVComponents[i] = 2;
  113|     59|        }
  114|       |
  115|    293|        aiVector3D *p = mesh->mTextureCoords[i], *end = p + mesh->mNumVertices;
  116|       |
  117|       |        // Ensure unused components are zeroed. This will make 1D texture channels work
  118|       |        // as if they were 2D channels .. just in case an application doesn't handle
  119|       |        // this case
  120|    293|        if (2 == mesh->mNumUVComponents[i]) {
  ------------------
  |  Branch (120:13): [True: 257, False: 36]
  ------------------
  121|   375k|            for (; p != end; ++p) {
  ------------------
  |  Branch (121:20): [True: 375k, False: 257]
  ------------------
  122|   375k|                p->z = 0.f;
  123|   375k|            }
  124|    257|        } else if (1 == mesh->mNumUVComponents[i]) {
  ------------------
  |  Branch (124:20): [True: 0, False: 36]
  ------------------
  125|      0|            for (; p != end; ++p) {
  ------------------
  |  Branch (125:20): [True: 0, False: 0]
  ------------------
  126|      0|                p->z = p->y = 0.f;
  127|      0|            }
  128|     36|        } else if (3 == mesh->mNumUVComponents[i]) {
  ------------------
  |  Branch (128:20): [True: 36, False: 0]
  ------------------
  129|       |            // Really 3D coordinates? Check whether the third coordinate is != 0 for at least one element
  130|  2.27k|            for (; p != end; ++p) {
  ------------------
  |  Branch (130:20): [True: 2.23k, False: 35]
  ------------------
  131|  2.23k|                if (p->z != 0) {
  ------------------
  |  Branch (131:21): [True: 1, False: 2.23k]
  ------------------
  132|      1|                    break;
  133|      1|                }
  134|  2.23k|            }
  135|     36|            if (p == end) {
  ------------------
  |  Branch (135:17): [True: 35, False: 1]
  ------------------
  136|     35|                ASSIMP_LOG_WARN("ScenePreprocessor: UVs are declared to be 3D but they're obviously not. Reverting to 2D.");
  137|     35|                mesh->mNumUVComponents[i] = 2;
  138|     35|            }
  139|     36|        }
  140|    293|    }
  141|       |
  142|       |    // If the information which primitive types are there in the
  143|       |    // mesh is currently not available, compute it.
  144|  4.85k|    if (!mesh->mPrimitiveTypes) {
  ------------------
  |  Branch (144:9): [True: 1.76k, False: 3.08k]
  ------------------
  145|  1.76k|        ai_assert(mesh->mFaces != nullptr);
  ------------------
  |  |   67|  1.76k|#   define ai_assert(expression) (void)((!!(expression)) || (Assimp::aiAssertViolation(#expression, __FILE__, __LINE__), 0))
  |  |  ------------------
  |  |  |  Branch (67:41): [True: 1.76k, False: 0]
  |  |  |  Branch (67:61): [True: 0, False: 0]
  |  |  ------------------
  ------------------
  146|   522k|        for (unsigned int a = 0; a < mesh->mNumFaces; ++a) {
  ------------------
  |  Branch (146:34): [True: 520k, False: 1.76k]
  ------------------
  147|   520k|            aiFace &face = mesh->mFaces[a];
  148|   520k|            switch (face.mNumIndices) {
  149|   182k|            case 3u:
  ------------------
  |  Branch (149:13): [True: 182k, False: 337k]
  ------------------
  150|   182k|                mesh->mPrimitiveTypes |= aiPrimitiveType_TRIANGLE;
  151|   182k|                break;
  152|       |
  153|      0|            case 2u:
  ------------------
  |  Branch (153:13): [True: 0, False: 520k]
  ------------------
  154|      0|                mesh->mPrimitiveTypes |= aiPrimitiveType_LINE;
  155|      0|                break;
  156|       |
  157|      0|            case 1u:
  ------------------
  |  Branch (157:13): [True: 0, False: 520k]
  ------------------
  158|      0|                mesh->mPrimitiveTypes |= aiPrimitiveType_POINT;
  159|      0|                break;
  160|       |
  161|   337k|            default:
  ------------------
  |  Branch (161:13): [True: 337k, False: 182k]
  ------------------
  162|   337k|                mesh->mPrimitiveTypes |= aiPrimitiveType_POLYGON;
  163|   337k|                break;
  164|   520k|            }
  165|   520k|        }
  166|  1.76k|    }
  167|       |
  168|       |    // If tangents and normals are given but no bitangents compute them
  169|  4.85k|    if (mesh->mTangents && mesh->mNormals && !mesh->mBitangents) {
  ------------------
  |  Branch (169:9): [True: 0, False: 4.85k]
  |  Branch (169:28): [True: 0, False: 0]
  |  Branch (169:46): [True: 0, False: 0]
  ------------------
  170|      0|        mesh->mBitangents = new aiVector3D[mesh->mNumVertices];
  171|      0|        for (unsigned int i = 0; i < mesh->mNumVertices; ++i) {
  ------------------
  |  Branch (171:34): [True: 0, False: 0]
  ------------------
  172|      0|            mesh->mBitangents[i] = mesh->mNormals[i] ^ mesh->mTangents[i];
  173|      0|        }
  174|      0|    }
  175|  4.85k|}
_ZN6Assimp17ScenePreprocessor16ProcessAnimationEP11aiAnimation:
  178|     94|void ScenePreprocessor::ProcessAnimation(aiAnimation *anim) {
  179|     94|    double first = 10e10, last = -10e10;
  180|    768|    for (unsigned int i = 0; i < anim->mNumChannels; ++i) {
  ------------------
  |  Branch (180:30): [True: 674, False: 94]
  ------------------
  181|    674|        aiNodeAnim *channel = anim->mChannels[i];
  182|       |
  183|       |        //  If the exact duration of the animation is not given
  184|       |        //  compute it now.
  185|    674|        if (anim->mDuration == -1.) {
  ------------------
  |  Branch (185:13): [True: 18, False: 656]
  ------------------
  186|       |            // Position keys
  187|  2.36k|            for (unsigned int j = 0; j < channel->mNumPositionKeys; ++j) {
  ------------------
  |  Branch (187:38): [True: 2.34k, False: 18]
  ------------------
  188|  2.34k|                aiVectorKey &key = channel->mPositionKeys[j];
  189|  2.34k|                first = std::min(first, key.mTime);
  190|  2.34k|                last = std::max(last, key.mTime);
  191|  2.34k|            }
  192|       |
  193|       |            // Scaling keys
  194|     63|            for (unsigned int j = 0; j < channel->mNumScalingKeys; ++j) {
  ------------------
  |  Branch (194:38): [True: 45, False: 18]
  ------------------
  195|     45|                aiVectorKey &key = channel->mScalingKeys[j];
  196|     45|                first = std::min(first, key.mTime);
  197|     45|                last = std::max(last, key.mTime);
  198|     45|            }
  199|       |
  200|       |            // Rotation keys
  201|  1.01k|            for (unsigned int j = 0; j < channel->mNumRotationKeys; ++j) {
  ------------------
  |  Branch (201:38): [True: 992, False: 18]
  ------------------
  202|    992|                aiQuatKey &key = channel->mRotationKeys[j];
  203|    992|                first = std::min(first, key.mTime);
  204|    992|                last = std::max(last, key.mTime);
  205|    992|            }
  206|     18|        }
  207|       |
  208|       |        // Check whether the animation channel has no rotation
  209|       |        // or position tracks. In this case we generate a dummy
  210|       |        // track from the information we have in the transformation
  211|       |        // matrix of the corresponding node.
  212|    674|        if (!channel->mNumRotationKeys || !channel->mNumPositionKeys || !channel->mNumScalingKeys) {
  ------------------
  |  Branch (212:13): [True: 318, False: 356]
  |  Branch (212:43): [True: 3, False: 353]
  |  Branch (212:73): [True: 85, False: 268]
  ------------------
  213|       |            // Find the node that belongs to this animation
  214|    406|            aiNode *node = scene->mRootNode->FindNode(channel->mNodeName);
  215|    406|            if (node) // ValidateDS will complain later if 'node' is nullptr
  ------------------
  |  Branch (215:17): [True: 371, False: 35]
  ------------------
  216|    371|            {
  217|       |                // Decompose the transformation matrix of the node
  218|    371|                aiVector3D scaling, position;
  219|    371|                aiQuaternion rotation;
  220|       |
  221|    371|                node->mTransformation.Decompose(scaling, rotation, position);
  222|       |
  223|       |                // No rotation keys? Generate a dummy track
  224|    371|                if (!channel->mNumRotationKeys) {
  ------------------
  |  Branch (224:21): [True: 283, False: 88]
  ------------------
  225|    283|                    if (channel->mRotationKeys) {
  ------------------
  |  Branch (225:25): [True: 0, False: 283]
  ------------------
  226|      0|                        delete[] channel->mRotationKeys;
  227|      0|                        channel->mRotationKeys = nullptr;
  228|      0|                    }
  229|    283|                    ai_assert(!channel->mRotationKeys);
  ------------------
  |  |   67|    283|#   define ai_assert(expression) (void)((!!(expression)) || (Assimp::aiAssertViolation(#expression, __FILE__, __LINE__), 0))
  |  |  ------------------
  |  |  |  Branch (67:41): [True: 283, False: 0]
  |  |  |  Branch (67:61): [True: 0, False: 0]
  |  |  ------------------
  ------------------
  230|    283|                    channel->mNumRotationKeys = 1;
  231|    283|                    channel->mRotationKeys = new aiQuatKey[1];
  232|    283|                    aiQuatKey &q = channel->mRotationKeys[0];
  233|       |
  234|    283|                    q.mTime = 0.;
  235|    283|                    q.mValue = rotation;
  236|       |
  237|    283|                    ASSIMP_LOG_VERBOSE_DEBUG("ScenePreprocessor: Dummy rotation track has been generated");
  238|    283|                } else {
  239|     88|                    ai_assert(channel->mRotationKeys);
  ------------------
  |  |   67|     88|#   define ai_assert(expression) (void)((!!(expression)) || (Assimp::aiAssertViolation(#expression, __FILE__, __LINE__), 0))
  |  |  ------------------
  |  |  |  Branch (67:41): [True: 88, False: 0]
  |  |  |  Branch (67:61): [True: 0, False: 0]
  |  |  ------------------
  ------------------
  240|     88|                }
  241|       |
  242|       |                // No scaling keys? Generate a dummy track
  243|    371|                if (!channel->mNumScalingKeys) {
  ------------------
  |  Branch (243:21): [True: 371, False: 0]
  ------------------
  244|    371|                    if (channel->mScalingKeys) {
  ------------------
  |  Branch (244:25): [True: 0, False: 371]
  ------------------
  245|      0|                        delete[] channel->mScalingKeys;
  246|      0|                        channel->mScalingKeys = nullptr;
  247|      0|                    }
  248|    371|                    ai_assert(!channel->mScalingKeys);
  ------------------
  |  |   67|    371|#   define ai_assert(expression) (void)((!!(expression)) || (Assimp::aiAssertViolation(#expression, __FILE__, __LINE__), 0))
  |  |  ------------------
  |  |  |  Branch (67:41): [True: 371, False: 0]
  |  |  |  Branch (67:61): [True: 0, False: 0]
  |  |  ------------------
  ------------------
  249|    371|                    channel->mNumScalingKeys = 1;
  250|    371|                    channel->mScalingKeys = new aiVectorKey[1];
  251|    371|                    aiVectorKey &q = channel->mScalingKeys[0];
  252|       |
  253|    371|                    q.mTime = 0.;
  254|    371|                    q.mValue = scaling;
  255|       |
  256|    371|                    ASSIMP_LOG_VERBOSE_DEBUG("ScenePreprocessor: Dummy scaling track has been generated");
  257|    371|                } else {
  258|      0|                    ai_assert(channel->mScalingKeys);
  ------------------
  |  |   67|      0|#   define ai_assert(expression) (void)((!!(expression)) || (Assimp::aiAssertViolation(#expression, __FILE__, __LINE__), 0))
  |  |  ------------------
  |  |  |  Branch (67:41): [True: 0, False: 0]
  |  |  |  Branch (67:61): [True: 0, False: 0]
  |  |  ------------------
  ------------------
  259|      0|                }
  260|       |
  261|       |                // No position keys? Generate a dummy track
  262|    371|                if (!channel->mNumPositionKeys) {
  ------------------
  |  Branch (262:21): [True: 16, False: 355]
  ------------------
  263|     16|                    if (channel->mPositionKeys) {
  ------------------
  |  Branch (263:25): [True: 0, False: 16]
  ------------------
  264|      0|                        delete[] channel->mPositionKeys;
  265|      0|                        channel->mPositionKeys = nullptr;
  266|      0|                    }
  267|     16|                    ai_assert(!channel->mPositionKeys);
  ------------------
  |  |   67|     16|#   define ai_assert(expression) (void)((!!(expression)) || (Assimp::aiAssertViolation(#expression, __FILE__, __LINE__), 0))
  |  |  ------------------
  |  |  |  Branch (67:41): [True: 16, False: 0]
  |  |  |  Branch (67:61): [True: 0, False: 0]
  |  |  ------------------
  ------------------
  268|     16|                    channel->mNumPositionKeys = 1;
  269|     16|                    channel->mPositionKeys = new aiVectorKey[1];
  270|     16|                    aiVectorKey &q = channel->mPositionKeys[0];
  271|       |
  272|     16|                    q.mTime = 0.;
  273|     16|                    q.mValue = position;
  274|       |
  275|     16|                    ASSIMP_LOG_VERBOSE_DEBUG("ScenePreprocessor: Dummy position track has been generated");
  276|    355|                } else {
  277|    355|                    ai_assert(channel->mPositionKeys);
  ------------------
  |  |   67|    355|#   define ai_assert(expression) (void)((!!(expression)) || (Assimp::aiAssertViolation(#expression, __FILE__, __LINE__), 0))
  |  |  ------------------
  |  |  |  Branch (67:41): [True: 355, False: 0]
  |  |  |  Branch (67:61): [True: 0, False: 0]
  |  |  ------------------
  ------------------
  278|    355|                }
  279|    371|            }
  280|    406|        }
  281|    674|    }
  282|       |
  283|     94|    if (anim->mDuration == -1.) {
  ------------------
  |  Branch (283:9): [True: 12, False: 82]
  ------------------
  284|       |        ASSIMP_LOG_VERBOSE_DEBUG("ScenePreprocessor: Setting animation duration");
  285|     12|        anim->mDuration = last - std::min(first, 0.);
  286|     12|    }
  287|     94|}

_ZN6Assimp17ScenePreprocessorC2EP7aiScene:
   79|    241|            scene(_scene) {}

_ZN6Assimp9ScenePrivEP7aiScene:
   85|    457|ScenePrivateData* ScenePriv(aiScene* in) {
   86|    457|    ai_assert( nullptr != in );
   87|    457|    if ( nullptr == in ) {
  ------------------
  |  Branch (87:10): [True: 0, False: 457]
  ------------------
   88|      0|        return nullptr;
   89|      0|    }
   90|    457|    return static_cast<ScenePrivateData*>(in->mPrivate);
   91|    457|}
_ZN6Assimp9ScenePrivEPK7aiScene:
   94|    706|const ScenePrivateData* ScenePriv(const aiScene* in) {
   95|    706|    ai_assert( nullptr != in );
   96|    706|    if ( nullptr == in ) {
  ------------------
  |  Branch (96:10): [True: 0, False: 706]
  ------------------
   97|      0|        return nullptr;
   98|      0|    }
   99|    706|    return static_cast<const ScenePrivateData*>(in->mPrivate);
  100|    706|}
_ZN6Assimp16ScenePrivateDataC2Ev:
   77|    890|: mOrigImporter( nullptr )
   78|    890|, mPPStepsApplied( 0 )
   79|    890|, mIsCopy( false ) {
   80|       |    // empty
   81|    890|}

_ZN6Assimp19SkeletonMeshBuilderC2EP7aiSceneP6aiNodeb:
   53|     18|SkeletonMeshBuilder::SkeletonMeshBuilder(aiScene *pScene, aiNode *root, bool bKnobsOnly) {
   54|       |    // nothing to do if there's mesh data already present at the scene
   55|     18|    if (pScene->mNumMeshes > 0 || pScene->mRootNode == nullptr) {
  ------------------
  |  Branch (55:9): [True: 0, False: 18]
  |  Branch (55:35): [True: 0, False: 18]
  ------------------
   56|      0|        return;
   57|      0|    }
   58|       |
   59|     18|    if (!root) {
  ------------------
  |  Branch (59:9): [True: 18, False: 0]
  ------------------
   60|     18|        root = pScene->mRootNode;
   61|     18|    }
   62|       |
   63|     18|    mKnobsOnly = bKnobsOnly;
   64|       |
   65|       |    // build some faces around each node
   66|     18|    CreateGeometry(root);
   67|       |
   68|       |    // create a mesh to hold all the generated faces
   69|     18|    pScene->mNumMeshes = 1;
   70|     18|    pScene->mMeshes = new aiMesh *[1];
   71|     18|    pScene->mMeshes[0] = CreateMesh();
   72|       |    // and install it at the root node
   73|     18|    root->mNumMeshes = 1;
   74|     18|    root->mMeshes = new unsigned int[1];
   75|     18|    root->mMeshes[0] = 0;
   76|       |
   77|       |    // create a dummy material for the mesh
   78|     18|    if (pScene->mNumMaterials == 0) {
  ------------------
  |  Branch (78:9): [True: 12, False: 6]
  ------------------
   79|     12|        pScene->mNumMaterials = 1;
   80|     12|        pScene->mMaterials = new aiMaterial *[1];
   81|     12|        pScene->mMaterials[0] = CreateMaterial();
   82|     12|    }
   83|     18|}
_ZN6Assimp19SkeletonMeshBuilder14CreateGeometryEPK6aiNode:
   87|  5.88k|void SkeletonMeshBuilder::CreateGeometry(const aiNode *pNode) {
   88|       |    // add a joint entry for the node.
   89|  5.88k|    const unsigned int vertexStartIndex = static_cast<unsigned int>(mVertices.size());
   90|       |
   91|       |    // now build the geometry.
   92|  5.88k|    if (pNode->mNumChildren > 0 && !mKnobsOnly) {
  ------------------
  |  Branch (92:9): [True: 2.93k, False: 2.94k]
  |  Branch (92:36): [True: 2.93k, False: 0]
  ------------------
   93|       |        // If the node has children, we build little pointers to each of them
   94|  8.80k|        for (unsigned int a = 0; a < pNode->mNumChildren; a++) {
  ------------------
  |  Branch (94:34): [True: 5.86k, False: 2.93k]
  ------------------
   95|       |            // find a suitable coordinate system
   96|  5.86k|            const aiMatrix4x4 &childTransform = pNode->mChildren[a]->mTransformation;
   97|  5.86k|            aiVector3D childpos(childTransform.a4, childTransform.b4, childTransform.c4);
   98|  5.86k|            ai_real distanceToChild = childpos.Length();
   99|  5.86k|            if (distanceToChild < ai_epsilon) {
  ------------------
  |  Branch (99:17): [True: 5.58k, False: 285]
  ------------------
  100|  5.58k|                continue;
  101|  5.58k|            }
  102|    285|            aiVector3D up = aiVector3D(childpos).Normalize();
  103|    285|            aiVector3D orth(1.0, 0.0, 0.0);
  104|    285|            if (std::fabs(orth * up) > 0.99) {
  ------------------
  |  Branch (104:17): [True: 6, False: 279]
  ------------------
  105|      6|                orth.Set(0.0, 1.0, 0.0);
  106|      6|            }
  107|       |
  108|    285|            aiVector3D front = (up ^ orth).Normalize();
  109|    285|            aiVector3D side = (front ^ up).Normalize();
  110|       |
  111|    285|            unsigned int localVertexStart = static_cast<unsigned int>(mVertices.size());
  112|    285|            mVertices.push_back(-front * distanceToChild * (ai_real)0.1);
  113|    285|            mVertices.push_back(childpos);
  114|    285|            mVertices.push_back(-side * distanceToChild * (ai_real)0.1);
  115|    285|            mVertices.push_back(-side * distanceToChild * (ai_real)0.1);
  116|    285|            mVertices.push_back(childpos);
  117|    285|            mVertices.push_back(front * distanceToChild * (ai_real)0.1);
  118|    285|            mVertices.push_back(front * distanceToChild * (ai_real)0.1);
  119|    285|            mVertices.push_back(childpos);
  120|    285|            mVertices.push_back(side * distanceToChild * (ai_real)0.1);
  121|    285|            mVertices.push_back(side * distanceToChild * (ai_real)0.1);
  122|    285|            mVertices.push_back(childpos);
  123|    285|            mVertices.push_back(-front * distanceToChild * (ai_real)0.1);
  124|       |
  125|    285|            mFaces.emplace_back(localVertexStart + 0, localVertexStart + 1, localVertexStart + 2);
  126|    285|            mFaces.emplace_back(localVertexStart + 3, localVertexStart + 4, localVertexStart + 5);
  127|    285|            mFaces.emplace_back(localVertexStart + 6, localVertexStart + 7, localVertexStart + 8);
  128|    285|            mFaces.emplace_back(localVertexStart + 9, localVertexStart + 10, localVertexStart + 11);
  129|    285|        }
  130|  2.94k|    } else {
  131|       |        // if the node has no children, it's an end node. Put a little knob there instead
  132|  2.94k|        aiVector3D ownpos(pNode->mTransformation.a4, pNode->mTransformation.b4, pNode->mTransformation.c4);
  133|  2.94k|        ai_real sizeEstimate = ownpos.Length() * ai_real(0.18);
  134|  2.94k|        const ai_real zero(0.0);
  135|       |
  136|  2.94k|        mVertices.emplace_back(-sizeEstimate, zero, zero);
  137|  2.94k|        mVertices.emplace_back(zero, sizeEstimate, zero);
  138|  2.94k|        mVertices.emplace_back(zero, zero, -sizeEstimate);
  139|  2.94k|        mVertices.emplace_back(zero, sizeEstimate, zero);
  140|  2.94k|        mVertices.emplace_back(sizeEstimate, zero, zero);
  141|  2.94k|        mVertices.emplace_back(zero, zero, -sizeEstimate);
  142|  2.94k|        mVertices.emplace_back(sizeEstimate, zero, zero);
  143|  2.94k|        mVertices.emplace_back(zero, -sizeEstimate, zero);
  144|  2.94k|        mVertices.emplace_back(zero, zero, -sizeEstimate);
  145|  2.94k|        mVertices.emplace_back(zero, -sizeEstimate, zero);
  146|  2.94k|        mVertices.emplace_back(-sizeEstimate, zero, zero);
  147|  2.94k|        mVertices.emplace_back(zero, zero, -sizeEstimate);
  148|       |
  149|  2.94k|        mVertices.emplace_back(-sizeEstimate, zero, zero);
  150|  2.94k|        mVertices.emplace_back(zero, zero, sizeEstimate);
  151|  2.94k|        mVertices.emplace_back(zero, sizeEstimate, zero);
  152|  2.94k|        mVertices.emplace_back(zero, sizeEstimate, zero);
  153|  2.94k|        mVertices.emplace_back(zero, zero, sizeEstimate);
  154|  2.94k|        mVertices.emplace_back(sizeEstimate, zero, zero);
  155|  2.94k|        mVertices.emplace_back(sizeEstimate, zero, zero);
  156|  2.94k|        mVertices.emplace_back(zero, zero, sizeEstimate);
  157|  2.94k|        mVertices.emplace_back(zero, -sizeEstimate, zero);
  158|  2.94k|        mVertices.emplace_back(zero, -sizeEstimate, zero);
  159|  2.94k|        mVertices.emplace_back(zero, zero, sizeEstimate);
  160|  2.94k|        mVertices.emplace_back(-sizeEstimate, zero, zero);
  161|       |
  162|  2.94k|        mFaces.emplace_back(vertexStartIndex + 0, vertexStartIndex + 1, vertexStartIndex + 2);
  163|  2.94k|        mFaces.emplace_back(vertexStartIndex + 3, vertexStartIndex + 4, vertexStartIndex + 5);
  164|  2.94k|        mFaces.emplace_back(vertexStartIndex + 6, vertexStartIndex + 7, vertexStartIndex + 8);
  165|  2.94k|        mFaces.emplace_back(vertexStartIndex + 9, vertexStartIndex + 10, vertexStartIndex + 11);
  166|  2.94k|        mFaces.emplace_back(vertexStartIndex + 12, vertexStartIndex + 13, vertexStartIndex + 14);
  167|  2.94k|        mFaces.emplace_back(vertexStartIndex + 15, vertexStartIndex + 16, vertexStartIndex + 17);
  168|  2.94k|        mFaces.emplace_back(vertexStartIndex + 18, vertexStartIndex + 19, vertexStartIndex + 20);
  169|  2.94k|        mFaces.emplace_back(vertexStartIndex + 21, vertexStartIndex + 22, vertexStartIndex + 23);
  170|  2.94k|    }
  171|       |
  172|  5.88k|    unsigned int numVertices = static_cast<unsigned int>(mVertices.size() - vertexStartIndex);
  173|  5.88k|    if (numVertices > 0) {
  ------------------
  |  Branch (173:9): [True: 2.95k, False: 2.92k]
  ------------------
  174|       |        // create a bone affecting all the newly created vertices
  175|  2.95k|        aiBone *bone = new aiBone;
  176|  2.95k|        mBones.push_back(bone);
  177|  2.95k|        bone->mName = pNode->mName;
  178|       |
  179|       |        // calculate the bone offset matrix by concatenating the inverse transformations of all parents
  180|  2.95k|        bone->mOffsetMatrix = aiMatrix4x4(pNode->mTransformation).Inverse();
  181|  8.82k|        for (aiNode *parent = pNode->mParent; parent != nullptr; parent = parent->mParent)
  ------------------
  |  Branch (181:47): [True: 5.87k, False: 2.95k]
  ------------------
  182|  5.87k|            bone->mOffsetMatrix = aiMatrix4x4(parent->mTransformation).Inverse() * bone->mOffsetMatrix;
  183|       |
  184|       |        // add all the vertices to the bone's influences
  185|  2.95k|        bone->mNumWeights = numVertices;
  186|  2.95k|        bone->mWeights = new aiVertexWeight[numVertices];
  187|  77.0k|        for (unsigned int a = 0; a < numVertices; ++a) {
  ------------------
  |  Branch (187:34): [True: 74.0k, False: 2.95k]
  ------------------
  188|  74.0k|            bone->mWeights[a] = aiVertexWeight(vertexStartIndex + a, 1.0);
  189|  74.0k|        }
  190|       |
  191|       |        // HACK: (thom) transform all vertices to the bone's local space. Should be done before adding
  192|       |        // them to the array, but I'm tired now and I'm annoyed.
  193|  2.95k|        aiMatrix4x4 boneToMeshTransform = aiMatrix4x4(bone->mOffsetMatrix).Inverse();
  194|  77.0k|        for (unsigned int a = vertexStartIndex; a < mVertices.size(); a++)
  ------------------
  |  Branch (194:49): [True: 74.0k, False: 2.95k]
  ------------------
  195|  74.0k|            mVertices[a] = boneToMeshTransform * mVertices[a];
  196|  2.95k|    }
  197|       |
  198|       |    // and finally recurse into the children list
  199|  11.7k|    for (unsigned int a = 0; a < pNode->mNumChildren; ++a) {
  ------------------
  |  Branch (199:30): [True: 5.86k, False: 5.88k]
  ------------------
  200|  5.86k|        CreateGeometry(pNode->mChildren[a]);
  201|  5.86k|    }
  202|  5.88k|}
_ZN6Assimp19SkeletonMeshBuilder10CreateMeshEv:
  206|     18|aiMesh *SkeletonMeshBuilder::CreateMesh() {
  207|     18|    aiMesh *mesh = new aiMesh();
  208|       |
  209|       |    // add points
  210|     18|    mesh->mNumVertices = static_cast<unsigned int>(mVertices.size());
  211|     18|    mesh->mVertices = new aiVector3D[mesh->mNumVertices];
  212|     18|    std::copy(mVertices.begin(), mVertices.end(), mesh->mVertices);
  213|       |
  214|     18|    mesh->mNormals = new aiVector3D[mesh->mNumVertices];
  215|       |
  216|       |    // add faces
  217|     18|    mesh->mNumFaces = static_cast<unsigned int>(mFaces.size());
  218|     18|    mesh->mFaces = new aiFace[mesh->mNumFaces];
  219|  24.7k|    for (unsigned int a = 0; a < mesh->mNumFaces; a++) {
  ------------------
  |  Branch (219:30): [True: 24.6k, False: 18]
  ------------------
  220|  24.6k|        const Face &inface = mFaces[a];
  221|  24.6k|        aiFace &outface = mesh->mFaces[a];
  222|  24.6k|        outface.mNumIndices = 3;
  223|  24.6k|        outface.mIndices = new unsigned int[3];
  224|  24.6k|        outface.mIndices[0] = inface.mIndices[0];
  225|  24.6k|        outface.mIndices[1] = inface.mIndices[1];
  226|  24.6k|        outface.mIndices[2] = inface.mIndices[2];
  227|       |
  228|       |        // Compute per-face normals ... we don't want the bones to be smoothed ... they're built to visualize
  229|       |        // the skeleton, so it's good if there's a visual difference to the rest of the geometry
  230|  24.6k|        aiVector3D nor = ((mVertices[inface.mIndices[2]] - mVertices[inface.mIndices[0]]) ^
  231|  24.6k|                          (mVertices[inface.mIndices[1]] - mVertices[inface.mIndices[0]]));
  232|       |
  233|  24.6k|        if (nor.Length() < 1e-5) /* ensure that FindInvalidData won't remove us ...*/
  ------------------
  |  Branch (233:13): [True: 23.4k, False: 1.22k]
  ------------------
  234|  23.4k|            nor = aiVector3D(1.0, 0.0, 0.0);
  235|       |
  236|  98.7k|        for (unsigned int n = 0; n < 3; ++n)
  ------------------
  |  Branch (236:34): [True: 74.0k, False: 24.6k]
  ------------------
  237|  74.0k|            mesh->mNormals[inface.mIndices[n]] = nor;
  238|  24.6k|    }
  239|       |
  240|       |    // add the bones
  241|     18|    mesh->mNumBones = static_cast<unsigned int>(mBones.size());
  242|     18|    mesh->mBones = new aiBone *[mesh->mNumBones];
  243|     18|    std::copy(mBones.begin(), mBones.end(), mesh->mBones);
  244|       |
  245|       |    // default
  246|     18|    mesh->mMaterialIndex = 0;
  247|       |
  248|     18|    return mesh;
  249|     18|}
_ZN6Assimp19SkeletonMeshBuilder14CreateMaterialEv:
  253|     12|aiMaterial *SkeletonMeshBuilder::CreateMaterial() {
  254|     12|    aiMaterial *matHelper = new aiMaterial;
  255|       |
  256|       |    // Name
  257|     12|    aiString matName(std::string("SkeletonMaterial"));
  258|     12|    matHelper->AddProperty(&matName, AI_MATKEY_NAME);
  259|       |
  260|       |    // Prevent backface culling
  261|     12|    const int no_cull = 1;
  262|     12|    matHelper->AddProperty(&no_cull, 1, AI_MATKEY_TWOSIDED);
  263|       |
  264|     12|    return matHelper;
  265|     12|}

_ZN6Assimp11SpatialSortC2Ev:
   69|  6.06k|        mPlaneNormal(PlaneInit),
   70|  6.06k|        mFinalized(false) {
   71|  6.06k|    mPlaneNormal.Normalize();
   72|  6.06k|}
_ZN6Assimp11SpatialSort4FillEPK10aiVector3tIfEjjb:
   77|  3.57k|        bool pFinalize /*= true */) {
   78|  3.57k|    mPositions.clear();
   79|  3.57k|    mFinalized = false;
   80|  3.57k|    Append(pPositions, pNumPositions, pElementOffset, pFinalize);
   81|  3.57k|    mFinalized = pFinalize;
   82|  3.57k|}
_ZNK6Assimp11SpatialSort17CalculateDistanceERK10aiVector3tIfE:
   85|  3.85M|ai_real SpatialSort::CalculateDistance(const aiVector3D &pPosition) const {
   86|  3.85M|    return (pPosition - mCentroid) * mPlaneNormal;
   87|  3.85M|}
_ZN6Assimp11SpatialSort8FinalizeEv:
   90|  3.59k|void SpatialSort::Finalize() {
   91|  3.59k|    const ai_real scale = 1.0f / mPositions.size();
   92|  3.32M|    for (unsigned int i = 0; i < mPositions.size(); i++) {
  ------------------
  |  Branch (92:30): [True: 3.32M, False: 3.59k]
  ------------------
   93|  3.32M|        mCentroid += scale * mPositions[i].mPosition;
   94|  3.32M|    }
   95|  3.32M|    for (unsigned int i = 0; i < mPositions.size(); i++) {
  ------------------
  |  Branch (95:30): [True: 3.32M, False: 3.59k]
  ------------------
   96|  3.32M|        mPositions[i].mDistance = CalculateDistance(mPositions[i].mPosition);
   97|  3.32M|    }
   98|  3.59k|    std::sort(mPositions.begin(), mPositions.end());
   99|  3.59k|    mFinalized = true;
  100|  3.59k|}
_ZN6Assimp11SpatialSort6AppendEPK10aiVector3tIfEjjb:
  105|  3.59k|        bool pFinalize /*= true */) {
  106|  3.59k|    ai_assert(!mFinalized && "You cannot add positions to the SpatialSort object after it has been finalized.");
  ------------------
  |  |   67|  7.19k|#   define ai_assert(expression) (void)((!!(expression)) || (Assimp::aiAssertViolation(#expression, __FILE__, __LINE__), 0))
  |  |  ------------------
  |  |  |  Branch (67:45): [True: 3.59k, False: 0]
  |  |  |  Branch (67:45): [True: 0, Folded]
  |  |  |  Branch (67:61): [True: 0, False: 0]
  |  |  ------------------
  ------------------
  107|       |    // store references to all given positions along with their distance to the reference plane
  108|  3.59k|    const size_t initial = mPositions.size();
  109|  3.59k|    mPositions.reserve(initial + pNumPositions);
  110|  3.32M|    for (unsigned int a = 0; a < pNumPositions; a++) {
  ------------------
  |  Branch (110:30): [True: 3.32M, False: 3.59k]
  ------------------
  111|  3.32M|        const char *tempPointer = reinterpret_cast<const char *>(pPositions);
  112|  3.32M|        const aiVector3D *vec = reinterpret_cast<const aiVector3D *>(tempPointer + a * pElementOffset);
  113|  3.32M|        mPositions.emplace_back(static_cast<unsigned int>(a + initial), *vec);
  114|  3.32M|    }
  115|       |
  116|  3.59k|    if (pFinalize) {
  ------------------
  |  Branch (116:9): [True: 3.57k, False: 23]
  ------------------
  117|       |        // now sort the array ascending by distance.
  118|  3.57k|        Finalize();
  119|  3.57k|    }
  120|  3.59k|}
_ZNK6Assimp11SpatialSort13FindPositionsERK10aiVector3tIfEfRNSt3__16vectorIjNS5_9allocatorIjEEEE:
  125|   528k|        ai_real pRadius, std::vector<unsigned int> &poResults) const {
  126|   528k|    ai_assert(mFinalized && "The SpatialSort object must be finalized before FindPositions can be called.");
  ------------------
  |  |   67|  1.05M|#   define ai_assert(expression) (void)((!!(expression)) || (Assimp::aiAssertViolation(#expression, __FILE__, __LINE__), 0))
  |  |  ------------------
  |  |  |  Branch (67:45): [True: 528k, False: 0]
  |  |  |  Branch (67:45): [True: 0, Folded]
  |  |  |  Branch (67:61): [True: 0, False: 0]
  |  |  ------------------
  ------------------
  127|   528k|    const ai_real dist = CalculateDistance(pPosition);
  128|   528k|    const ai_real minDist = dist - pRadius, maxDist = dist + pRadius;
  129|       |
  130|       |    // clear the array
  131|   528k|    poResults.clear();
  132|       |
  133|       |    // quick check for positions outside the range
  134|   528k|    if (mPositions.size() == 0)
  ------------------
  |  Branch (134:9): [True: 0, False: 528k]
  ------------------
  135|      0|        return;
  136|   528k|    if (maxDist < mPositions.front().mDistance)
  ------------------
  |  Branch (136:9): [True: 0, False: 528k]
  ------------------
  137|      0|        return;
  138|   528k|    if (minDist > mPositions.back().mDistance)
  ------------------
  |  Branch (138:9): [True: 0, False: 528k]
  ------------------
  139|      0|        return;
  140|       |
  141|       |    // do a binary search for the minimal distance to start the iteration there
  142|   528k|    unsigned int index = (unsigned int)mPositions.size() / 2;
  143|   528k|    unsigned int binaryStepSize = (unsigned int)mPositions.size() / 4;
  144|  8.48M|    while (binaryStepSize > 1) {
  ------------------
  |  Branch (144:12): [True: 7.95M, False: 528k]
  ------------------
  145|  7.95M|        if (mPositions[index].mDistance < minDist)
  ------------------
  |  Branch (145:13): [True: 3.97M, False: 3.98M]
  ------------------
  146|  3.97M|            index += binaryStepSize;
  147|  3.98M|        else
  148|  3.98M|            index -= binaryStepSize;
  149|       |
  150|  7.95M|        binaryStepSize /= 2;
  151|  7.95M|    }
  152|       |
  153|       |    // depending on the direction of the last step we need to single step a bit back or forth
  154|       |    // to find the actual beginning element of the range
  155|   941k|    while (index > 0 && mPositions[index].mDistance > minDist)
  ------------------
  |  Branch (155:12): [True: 938k, False: 3.21k]
  |  Branch (155:25): [True: 413k, False: 525k]
  ------------------
  156|   413k|        index--;
  157|  1.24M|    while (index < (mPositions.size() - 1) && mPositions[index].mDistance < minDist)
  ------------------
  |  Branch (157:12): [True: 1.24M, False: 340]
  |  Branch (157:47): [True: 718k, False: 528k]
  ------------------
  158|   718k|        index++;
  159|       |
  160|       |    // Mow start iterating from there until the first position lays outside of the distance range.
  161|       |    // Add all positions inside the distance range within the given radius to the result array
  162|   528k|    std::vector<Entry>::const_iterator it = mPositions.begin() + index;
  163|   528k|    const ai_real pSquared = pRadius * pRadius;
  164|   101M|    while (it->mDistance < maxDist) {
  ------------------
  |  Branch (164:12): [True: 100M, False: 525k]
  ------------------
  165|   100M|        if ((it->mPosition - pPosition).SquareLength() < pSquared)
  ------------------
  |  Branch (165:13): [True: 2.33M, False: 98.5M]
  ------------------
  166|  2.33M|            poResults.push_back(it->mIndex);
  167|   100M|        ++it;
  168|   100M|        if (it == mPositions.end())
  ------------------
  |  Branch (168:13): [True: 2.86k, False: 100M]
  ------------------
  169|  2.86k|            break;
  170|   100M|    }
  171|       |
  172|       |    // that's it
  173|   528k|}
_ZNK6Assimp11SpatialSort20GenerateMappingTableERNSt3__16vectorIjNS1_9allocatorIjEEEEf:
  310|     18|unsigned int SpatialSort::GenerateMappingTable(std::vector<unsigned int> &fill, ai_real pRadius) const {
  311|     18|    ai_assert(mFinalized && "The SpatialSort object must be finalized before GenerateMappingTable can be called.");
  ------------------
  |  |   67|     36|#   define ai_assert(expression) (void)((!!(expression)) || (Assimp::aiAssertViolation(#expression, __FILE__, __LINE__), 0))
  |  |  ------------------
  |  |  |  Branch (67:45): [True: 18, False: 0]
  |  |  |  Branch (67:45): [True: 0, Folded]
  |  |  |  Branch (67:61): [True: 0, False: 0]
  |  |  ------------------
  ------------------
  312|     18|    fill.resize(mPositions.size(), UINT_MAX);
  313|     18|    ai_real dist, maxDist;
  314|       |
  315|     18|    unsigned int t = 0;
  316|     18|    const ai_real pSquared = pRadius * pRadius;
  317|  77.1k|    for (size_t i = 0; i < mPositions.size();) {
  ------------------
  |  Branch (317:24): [True: 77.1k, False: 18]
  ------------------
  318|  77.1k|        dist = (mPositions[i].mPosition - mCentroid) * mPlaneNormal;
  319|  77.1k|        maxDist = dist + pRadius;
  320|       |
  321|  77.1k|        fill[mPositions[i].mIndex] = t;
  322|  77.1k|        const aiVector3D &oldpos = mPositions[i].mPosition;
  323|   307k|        for (++i; i < fill.size() && mPositions[i].mDistance < maxDist && (mPositions[i].mPosition - oldpos).SquareLength() < pSquared; ++i) {
  ------------------
  |  Branch (323:19): [True: 307k, False: 18]
  |  Branch (323:19): [True: 230k, False: 77.1k]
  |  Branch (323:38): [True: 293k, False: 13.9k]
  |  Branch (323:75): [True: 230k, False: 63.2k]
  ------------------
  324|   230k|            fill[mPositions[i].mIndex] = t;
  325|   230k|        }
  326|  77.1k|        ++t;
  327|  77.1k|    }
  328|       |
  329|     18|#ifdef ASSIMP_BUILD_DEBUG
  330|       |
  331|       |    // debug invariant: mPositions[i].mIndex values must range from 0 to mPositions.size()-1
  332|   307k|    for (size_t i = 0; i < fill.size(); ++i) {
  ------------------
  |  Branch (332:24): [True: 307k, False: 18]
  ------------------
  333|   307k|        ai_assert(fill[i] < mPositions.size());
  ------------------
  |  |   67|   307k|#   define ai_assert(expression) (void)((!!(expression)) || (Assimp::aiAssertViolation(#expression, __FILE__, __LINE__), 0))
  |  |  ------------------
  |  |  |  Branch (67:41): [True: 307k, False: 0]
  |  |  |  Branch (67:61): [True: 0, False: 0]
  |  |  ------------------
  ------------------
  334|   307k|    }
  335|       |
  336|     18|#endif
  337|     18|    return t;
  338|     18|}

_ZN6Assimp9SubdivideERNSt3__16vectorI10aiVector3tIfENS0_9allocatorIS3_EEEE:
   86|     30|void Subdivide(std::vector<aiVector3D> &positions) {
   87|       |    // assume this to be constant - (fixme: must be 1.0? I think so)
   88|     30|    const ai_real fl1 = positions[0].Length();
   89|       |
   90|     30|    unsigned int origSize = (unsigned int)positions.size();
   91|  7.65k|    for (unsigned int i = 0; i < origSize; i += 3) {
  ------------------
  |  Branch (91:30): [True: 7.62k, False: 30]
  ------------------
   92|  7.62k|        aiVector3D &tv0 = positions[i];
   93|  7.62k|        aiVector3D &tv1 = positions[i + 1];
   94|  7.62k|        aiVector3D &tv2 = positions[i + 2];
   95|       |
   96|  7.62k|        aiVector3D a = tv0, b = tv1, c = tv2;
   97|  7.62k|        aiVector3D v1 = aiVector3D(a.x + b.x, a.y + b.y, a.z + b.z).Normalize() * fl1;
   98|  7.62k|        aiVector3D v2 = aiVector3D(a.x + c.x, a.y + c.y, a.z + c.z).Normalize() * fl1;
   99|  7.62k|        aiVector3D v3 = aiVector3D(b.x + c.x, b.y + c.y, b.z + c.z).Normalize() * fl1;
  100|       |
  101|  7.62k|        tv0 = v1;
  102|  7.62k|        tv1 = v3;
  103|  7.62k|        tv2 = v2; // overwrite the original
  104|  7.62k|        ADD_TRIANGLE(v1, v2, a);
  ------------------
  |  |   56|  7.62k|    positions.push_back(n0);     \
  |  |   57|  7.62k|    positions.push_back(n1);     \
  |  |   58|  7.62k|    positions.push_back(n2);
  ------------------
  105|  7.62k|        ADD_TRIANGLE(v2, v3, c);
  ------------------
  |  |   56|  7.62k|    positions.push_back(n0);     \
  |  |   57|  7.62k|    positions.push_back(n1);     \
  |  |   58|  7.62k|    positions.push_back(n2);
  ------------------
  106|  7.62k|        ADD_TRIANGLE(v3, v1, b);
  ------------------
  |  |   56|  7.62k|    positions.push_back(n0);     \
  |  |   57|  7.62k|    positions.push_back(n1);     \
  |  |   58|  7.62k|    positions.push_back(n2);
  ------------------
  107|  7.62k|    }
  108|     30|}
_ZN6Assimp14StandardShapes8MakeMeshERKNSt3__16vectorI10aiVector3tIfENS1_9allocatorIS4_EEEEj:
  113|     13|        unsigned int numIndices) {
  114|     13|    if (positions.empty() || !numIndices) {
  ------------------
  |  Branch (114:9): [True: 0, False: 13]
  |  Branch (114:30): [True: 0, False: 13]
  ------------------
  115|      0|        return nullptr;
  116|      0|    }
  117|       |
  118|       |    // Determine which kinds of primitives the mesh consists of
  119|     13|    aiMesh *out = new aiMesh();
  120|     13|    switch (numIndices) {
  121|      0|    case 1:
  ------------------
  |  Branch (121:5): [True: 0, False: 13]
  ------------------
  122|      0|        out->mPrimitiveTypes = aiPrimitiveType_POINT;
  123|      0|        break;
  124|      0|    case 2:
  ------------------
  |  Branch (124:5): [True: 0, False: 13]
  ------------------
  125|      0|        out->mPrimitiveTypes = aiPrimitiveType_LINE;
  126|      0|        break;
  127|      6|    case 3:
  ------------------
  |  Branch (127:5): [True: 6, False: 7]
  ------------------
  128|      6|        out->mPrimitiveTypes = aiPrimitiveType_TRIANGLE;
  129|      6|        break;
  130|      7|    default:
  ------------------
  |  Branch (130:5): [True: 7, False: 6]
  ------------------
  131|      7|        out->mPrimitiveTypes = aiPrimitiveType_POLYGON;
  132|      7|        break;
  133|     13|    };
  134|       |
  135|     13|    out->mNumFaces = (unsigned int)positions.size() / numIndices;
  136|     13|    out->mFaces = new aiFace[out->mNumFaces];
  137|  7.73k|    for (unsigned int i = 0, a = 0; i < out->mNumFaces; ++i) {
  ------------------
  |  Branch (137:37): [True: 7.72k, False: 13]
  ------------------
  138|  7.72k|        aiFace &f = out->mFaces[i];
  139|  7.72k|        f.mNumIndices = numIndices;
  140|  7.72k|        f.mIndices = new unsigned int[numIndices];
  141|  30.9k|        for (unsigned int j = 0; j < numIndices; ++j, ++a) {
  ------------------
  |  Branch (141:34): [True: 23.2k, False: 7.72k]
  ------------------
  142|  23.2k|            f.mIndices[j] = a;
  143|  23.2k|        }
  144|  7.72k|    }
  145|     13|    out->mNumVertices = (unsigned int)positions.size();
  146|     13|    out->mVertices = new aiVector3D[out->mNumVertices];
  147|     13|    ::memcpy(out->mVertices, &positions[0], out->mNumVertices * sizeof(aiVector3D));
  148|       |
  149|     13|    return out;
  150|     13|}
_ZN6Assimp14StandardShapes8MakeMeshEPFjRNSt3__16vectorI10aiVector3tIfENS1_9allocatorIS4_EEEEbE:
  164|      7|        std::vector<aiVector3D> &, bool)) {
  165|      7|    std::vector<aiVector3D> temp;
  166|      7|    unsigned num = (*GenerateFunc)(temp, true);
  167|      7|    return MakeMesh(temp, num);
  168|      7|}
_ZN6Assimp14StandardShapes8MakeMeshEjPFvjRNSt3__16vectorI10aiVector3tIfENS1_9allocatorIS4_EEEEE:
  173|      6|                                                           unsigned int, std::vector<aiVector3D> &)) {
  174|      6|    std::vector<aiVector3D> temp;
  175|      6|    (*GenerateFunc)(num, temp);
  176|      6|    return MakeMesh(temp, 3);
  177|      6|}
_ZN6Assimp14StandardShapes15MakeIcosahedronERNSt3__16vectorI10aiVector3tIfENS1_9allocatorIS4_EEEE:
  181|      9|unsigned int StandardShapes::MakeIcosahedron(std::vector<aiVector3D> &positions) {
  182|      9|    positions.reserve(positions.size() + 60);
  183|       |
  184|      9|    const ai_real t = (ai_real(1.0) + ai_real(2.236067977)) / ai_real(2.0);
  185|      9|    const ai_real s = std::sqrt(ai_real(1.0) + t * t);
  186|       |
  187|      9|    const aiVector3D v0 = aiVector3D(t, 1.0, 0.0) / s;
  188|      9|    const aiVector3D v1 = aiVector3D(-t, 1.0, 0.0) / s;
  189|      9|    const aiVector3D v2 = aiVector3D(t, -1.0, 0.0) / s;
  190|      9|    const aiVector3D v3 = aiVector3D(-t, -1.0, 0.0) / s;
  191|      9|    const aiVector3D v4 = aiVector3D(1.0, 0.0, t) / s;
  192|      9|    const aiVector3D v5 = aiVector3D(1.0, 0.0, -t) / s;
  193|      9|    const aiVector3D v6 = aiVector3D(-1.0, 0.0, t) / s;
  194|      9|    const aiVector3D v7 = aiVector3D(-1.0, 0.0, -t) / s;
  195|      9|    const aiVector3D v8 = aiVector3D(0.0, t, 1.0) / s;
  196|      9|    const aiVector3D v9 = aiVector3D(0.0, -t, 1.0) / s;
  197|      9|    const aiVector3D v10 = aiVector3D(0.0, t, -1.0) / s;
  198|      9|    const aiVector3D v11 = aiVector3D(0.0, -t, -1.0) / s;
  199|       |
  200|      9|    ADD_TRIANGLE(v0, v8, v4);
  ------------------
  |  |   56|      9|    positions.push_back(n0);     \
  |  |   57|      9|    positions.push_back(n1);     \
  |  |   58|      9|    positions.push_back(n2);
  ------------------
  201|      9|    ADD_TRIANGLE(v0, v5, v10);
  ------------------
  |  |   56|      9|    positions.push_back(n0);     \
  |  |   57|      9|    positions.push_back(n1);     \
  |  |   58|      9|    positions.push_back(n2);
  ------------------
  202|      9|    ADD_TRIANGLE(v2, v4, v9);
  ------------------
  |  |   56|      9|    positions.push_back(n0);     \
  |  |   57|      9|    positions.push_back(n1);     \
  |  |   58|      9|    positions.push_back(n2);
  ------------------
  203|      9|    ADD_TRIANGLE(v2, v11, v5);
  ------------------
  |  |   56|      9|    positions.push_back(n0);     \
  |  |   57|      9|    positions.push_back(n1);     \
  |  |   58|      9|    positions.push_back(n2);
  ------------------
  204|       |
  205|      9|    ADD_TRIANGLE(v1, v6, v8);
  ------------------
  |  |   56|      9|    positions.push_back(n0);     \
  |  |   57|      9|    positions.push_back(n1);     \
  |  |   58|      9|    positions.push_back(n2);
  ------------------
  206|      9|    ADD_TRIANGLE(v1, v10, v7);
  ------------------
  |  |   56|      9|    positions.push_back(n0);     \
  |  |   57|      9|    positions.push_back(n1);     \
  |  |   58|      9|    positions.push_back(n2);
  ------------------
  207|      9|    ADD_TRIANGLE(v3, v9, v6);
  ------------------
  |  |   56|      9|    positions.push_back(n0);     \
  |  |   57|      9|    positions.push_back(n1);     \
  |  |   58|      9|    positions.push_back(n2);
  ------------------
  208|      9|    ADD_TRIANGLE(v3, v7, v11);
  ------------------
  |  |   56|      9|    positions.push_back(n0);     \
  |  |   57|      9|    positions.push_back(n1);     \
  |  |   58|      9|    positions.push_back(n2);
  ------------------
  209|       |
  210|      9|    ADD_TRIANGLE(v0, v10, v8);
  ------------------
  |  |   56|      9|    positions.push_back(n0);     \
  |  |   57|      9|    positions.push_back(n1);     \
  |  |   58|      9|    positions.push_back(n2);
  ------------------
  211|      9|    ADD_TRIANGLE(v1, v8, v10);
  ------------------
  |  |   56|      9|    positions.push_back(n0);     \
  |  |   57|      9|    positions.push_back(n1);     \
  |  |   58|      9|    positions.push_back(n2);
  ------------------
  212|      9|    ADD_TRIANGLE(v2, v9, v11);
  ------------------
  |  |   56|      9|    positions.push_back(n0);     \
  |  |   57|      9|    positions.push_back(n1);     \
  |  |   58|      9|    positions.push_back(n2);
  ------------------
  213|      9|    ADD_TRIANGLE(v3, v11, v9);
  ------------------
  |  |   56|      9|    positions.push_back(n0);     \
  |  |   57|      9|    positions.push_back(n1);     \
  |  |   58|      9|    positions.push_back(n2);
  ------------------
  214|       |
  215|      9|    ADD_TRIANGLE(v4, v2, v0);
  ------------------
  |  |   56|      9|    positions.push_back(n0);     \
  |  |   57|      9|    positions.push_back(n1);     \
  |  |   58|      9|    positions.push_back(n2);
  ------------------
  216|      9|    ADD_TRIANGLE(v5, v0, v2);
  ------------------
  |  |   56|      9|    positions.push_back(n0);     \
  |  |   57|      9|    positions.push_back(n1);     \
  |  |   58|      9|    positions.push_back(n2);
  ------------------
  217|      9|    ADD_TRIANGLE(v6, v1, v3);
  ------------------
  |  |   56|      9|    positions.push_back(n0);     \
  |  |   57|      9|    positions.push_back(n1);     \
  |  |   58|      9|    positions.push_back(n2);
  ------------------
  218|      9|    ADD_TRIANGLE(v7, v3, v1);
  ------------------
  |  |   56|      9|    positions.push_back(n0);     \
  |  |   57|      9|    positions.push_back(n1);     \
  |  |   58|      9|    positions.push_back(n2);
  ------------------
  219|       |
  220|      9|    ADD_TRIANGLE(v8, v6, v4);
  ------------------
  |  |   56|      9|    positions.push_back(n0);     \
  |  |   57|      9|    positions.push_back(n1);     \
  |  |   58|      9|    positions.push_back(n2);
  ------------------
  221|      9|    ADD_TRIANGLE(v9, v4, v6);
  ------------------
  |  |   56|      9|    positions.push_back(n0);     \
  |  |   57|      9|    positions.push_back(n1);     \
  |  |   58|      9|    positions.push_back(n2);
  ------------------
  222|      9|    ADD_TRIANGLE(v10, v5, v7);
  ------------------
  |  |   56|      9|    positions.push_back(n0);     \
  |  |   57|      9|    positions.push_back(n1);     \
  |  |   58|      9|    positions.push_back(n2);
  ------------------
  223|      9|    ADD_TRIANGLE(v11, v7, v5);
  ------------------
  |  |   56|      9|    positions.push_back(n0);     \
  |  |   57|      9|    positions.push_back(n1);     \
  |  |   58|      9|    positions.push_back(n2);
  ------------------
  224|      9|    return 3;
  225|      9|}
_ZN6Assimp14StandardShapes16MakeDodecahedronERNSt3__16vectorI10aiVector3tIfENS1_9allocatorIS4_EEEEb:
  230|  1.76k|        bool polygons /*= false*/) {
  231|  1.76k|    positions.reserve(positions.size() + 108);
  232|       |
  233|  1.76k|    const ai_real a = ai_real(1.0) / ai_real(1.7320508);
  234|  1.76k|    const ai_real b = std::sqrt((ai_real(3.0) - ai_real(2.23606797)) / ai_real(6.0));
  235|  1.76k|    const ai_real c = std::sqrt((ai_real(3.0) + ai_real(2.23606797f)) / ai_real(6.0));
  236|       |
  237|  1.76k|    const aiVector3D v0 = aiVector3D(a, a, a);
  238|  1.76k|    const aiVector3D v1 = aiVector3D(a, a, -a);
  239|  1.76k|    const aiVector3D v2 = aiVector3D(a, -a, a);
  240|  1.76k|    const aiVector3D v3 = aiVector3D(a, -a, -a);
  241|  1.76k|    const aiVector3D v4 = aiVector3D(-a, a, a);
  242|  1.76k|    const aiVector3D v5 = aiVector3D(-a, a, -a);
  243|  1.76k|    const aiVector3D v6 = aiVector3D(-a, -a, a);
  244|  1.76k|    const aiVector3D v7 = aiVector3D(-a, -a, -a);
  245|  1.76k|    const aiVector3D v8 = aiVector3D(b, c, 0.0);
  246|  1.76k|    const aiVector3D v9 = aiVector3D(-b, c, 0.0);
  247|  1.76k|    const aiVector3D v10 = aiVector3D(b, -c, 0.0);
  248|  1.76k|    const aiVector3D v11 = aiVector3D(-b, -c, 0.0);
  249|  1.76k|    const aiVector3D v12 = aiVector3D(c, 0.0, b);
  250|  1.76k|    const aiVector3D v13 = aiVector3D(c, 0.0, -b);
  251|  1.76k|    const aiVector3D v14 = aiVector3D(-c, 0.0, b);
  252|  1.76k|    const aiVector3D v15 = aiVector3D(-c, 0.0, -b);
  253|  1.76k|    const aiVector3D v16 = aiVector3D(0.0, b, c);
  254|  1.76k|    const aiVector3D v17 = aiVector3D(0.0, -b, c);
  255|  1.76k|    const aiVector3D v18 = aiVector3D(0.0, b, -c);
  256|  1.76k|    const aiVector3D v19 = aiVector3D(0.0, -b, -c);
  257|       |
  258|  1.76k|    ADD_PENTAGON(v0, v8, v9, v4, v16);
  ------------------
  |  |   61|  1.76k|    if (polygons) {                      \
  |  |  ------------------
  |  |  |  Branch (61:9): [True: 0, False: 1.76k]
  |  |  ------------------
  |  |   62|      0|        positions.push_back(n0);         \
  |  |   63|      0|        positions.push_back(n1);         \
  |  |   64|      0|        positions.push_back(n2);         \
  |  |   65|      0|        positions.push_back(n3);         \
  |  |   66|      0|        positions.push_back(n4);         \
  |  |   67|  1.76k|    } else {                             \
  |  |   68|  1.76k|        ADD_TRIANGLE(n0, n1, n2)         \
  |  |  ------------------
  |  |  |  |   56|  1.76k|    positions.push_back(n0);     \
  |  |  |  |   57|  1.76k|    positions.push_back(n1);     \
  |  |  |  |   58|  1.76k|    positions.push_back(n2);
  |  |  ------------------
  |  |   69|  1.76k|        ADD_TRIANGLE(n0, n2, n3)         \
  |  |  ------------------
  |  |  |  |   56|  1.76k|    positions.push_back(n0);     \
  |  |  |  |   57|  1.76k|    positions.push_back(n1);     \
  |  |  |  |   58|  1.76k|    positions.push_back(n2);
  |  |  ------------------
  |  |   70|  1.76k|        ADD_TRIANGLE(n0, n3, n4)         \
  |  |  ------------------
  |  |  |  |   56|  1.76k|    positions.push_back(n0);     \
  |  |  |  |   57|  1.76k|    positions.push_back(n1);     \
  |  |  |  |   58|  1.76k|    positions.push_back(n2);
  |  |  ------------------
  |  |   71|  1.76k|    }
  ------------------
  259|  1.76k|    ADD_PENTAGON(v0, v12, v13, v1, v8);
  ------------------
  |  |   61|  1.76k|    if (polygons) {                      \
  |  |  ------------------
  |  |  |  Branch (61:9): [True: 0, False: 1.76k]
  |  |  ------------------
  |  |   62|      0|        positions.push_back(n0);         \
  |  |   63|      0|        positions.push_back(n1);         \
  |  |   64|      0|        positions.push_back(n2);         \
  |  |   65|      0|        positions.push_back(n3);         \
  |  |   66|      0|        positions.push_back(n4);         \
  |  |   67|  1.76k|    } else {                             \
  |  |   68|  1.76k|        ADD_TRIANGLE(n0, n1, n2)         \
  |  |  ------------------
  |  |  |  |   56|  1.76k|    positions.push_back(n0);     \
  |  |  |  |   57|  1.76k|    positions.push_back(n1);     \
  |  |  |  |   58|  1.76k|    positions.push_back(n2);
  |  |  ------------------
  |  |   69|  1.76k|        ADD_TRIANGLE(n0, n2, n3)         \
  |  |  ------------------
  |  |  |  |   56|  1.76k|    positions.push_back(n0);     \
  |  |  |  |   57|  1.76k|    positions.push_back(n1);     \
  |  |  |  |   58|  1.76k|    positions.push_back(n2);
  |  |  ------------------
  |  |   70|  1.76k|        ADD_TRIANGLE(n0, n3, n4)         \
  |  |  ------------------
  |  |  |  |   56|  1.76k|    positions.push_back(n0);     \
  |  |  |  |   57|  1.76k|    positions.push_back(n1);     \
  |  |  |  |   58|  1.76k|    positions.push_back(n2);
  |  |  ------------------
  |  |   71|  1.76k|    }
  ------------------
  260|  1.76k|    ADD_PENTAGON(v0, v16, v17, v2, v12);
  ------------------
  |  |   61|  1.76k|    if (polygons) {                      \
  |  |  ------------------
  |  |  |  Branch (61:9): [True: 0, False: 1.76k]
  |  |  ------------------
  |  |   62|      0|        positions.push_back(n0);         \
  |  |   63|      0|        positions.push_back(n1);         \
  |  |   64|      0|        positions.push_back(n2);         \
  |  |   65|      0|        positions.push_back(n3);         \
  |  |   66|      0|        positions.push_back(n4);         \
  |  |   67|  1.76k|    } else {                             \
  |  |   68|  1.76k|        ADD_TRIANGLE(n0, n1, n2)         \
  |  |  ------------------
  |  |  |  |   56|  1.76k|    positions.push_back(n0);     \
  |  |  |  |   57|  1.76k|    positions.push_back(n1);     \
  |  |  |  |   58|  1.76k|    positions.push_back(n2);
  |  |  ------------------
  |  |   69|  1.76k|        ADD_TRIANGLE(n0, n2, n3)         \
  |  |  ------------------
  |  |  |  |   56|  1.76k|    positions.push_back(n0);     \
  |  |  |  |   57|  1.76k|    positions.push_back(n1);     \
  |  |  |  |   58|  1.76k|    positions.push_back(n2);
  |  |  ------------------
  |  |   70|  1.76k|        ADD_TRIANGLE(n0, n3, n4)         \
  |  |  ------------------
  |  |  |  |   56|  1.76k|    positions.push_back(n0);     \
  |  |  |  |   57|  1.76k|    positions.push_back(n1);     \
  |  |  |  |   58|  1.76k|    positions.push_back(n2);
  |  |  ------------------
  |  |   71|  1.76k|    }
  ------------------
  261|  1.76k|    ADD_PENTAGON(v8, v1, v18, v5, v9);
  ------------------
  |  |   61|  1.76k|    if (polygons) {                      \
  |  |  ------------------
  |  |  |  Branch (61:9): [True: 0, False: 1.76k]
  |  |  ------------------
  |  |   62|      0|        positions.push_back(n0);         \
  |  |   63|      0|        positions.push_back(n1);         \
  |  |   64|      0|        positions.push_back(n2);         \
  |  |   65|      0|        positions.push_back(n3);         \
  |  |   66|      0|        positions.push_back(n4);         \
  |  |   67|  1.76k|    } else {                             \
  |  |   68|  1.76k|        ADD_TRIANGLE(n0, n1, n2)         \
  |  |  ------------------
  |  |  |  |   56|  1.76k|    positions.push_back(n0);     \
  |  |  |  |   57|  1.76k|    positions.push_back(n1);     \
  |  |  |  |   58|  1.76k|    positions.push_back(n2);
  |  |  ------------------
  |  |   69|  1.76k|        ADD_TRIANGLE(n0, n2, n3)         \
  |  |  ------------------
  |  |  |  |   56|  1.76k|    positions.push_back(n0);     \
  |  |  |  |   57|  1.76k|    positions.push_back(n1);     \
  |  |  |  |   58|  1.76k|    positions.push_back(n2);
  |  |  ------------------
  |  |   70|  1.76k|        ADD_TRIANGLE(n0, n3, n4)         \
  |  |  ------------------
  |  |  |  |   56|  1.76k|    positions.push_back(n0);     \
  |  |  |  |   57|  1.76k|    positions.push_back(n1);     \
  |  |  |  |   58|  1.76k|    positions.push_back(n2);
  |  |  ------------------
  |  |   71|  1.76k|    }
  ------------------
  262|  1.76k|    ADD_PENTAGON(v12, v2, v10, v3, v13);
  ------------------
  |  |   61|  1.76k|    if (polygons) {                      \
  |  |  ------------------
  |  |  |  Branch (61:9): [True: 0, False: 1.76k]
  |  |  ------------------
  |  |   62|      0|        positions.push_back(n0);         \
  |  |   63|      0|        positions.push_back(n1);         \
  |  |   64|      0|        positions.push_back(n2);         \
  |  |   65|      0|        positions.push_back(n3);         \
  |  |   66|      0|        positions.push_back(n4);         \
  |  |   67|  1.76k|    } else {                             \
  |  |   68|  1.76k|        ADD_TRIANGLE(n0, n1, n2)         \
  |  |  ------------------
  |  |  |  |   56|  1.76k|    positions.push_back(n0);     \
  |  |  |  |   57|  1.76k|    positions.push_back(n1);     \
  |  |  |  |   58|  1.76k|    positions.push_back(n2);
  |  |  ------------------
  |  |   69|  1.76k|        ADD_TRIANGLE(n0, n2, n3)         \
  |  |  ------------------
  |  |  |  |   56|  1.76k|    positions.push_back(n0);     \
  |  |  |  |   57|  1.76k|    positions.push_back(n1);     \
  |  |  |  |   58|  1.76k|    positions.push_back(n2);
  |  |  ------------------
  |  |   70|  1.76k|        ADD_TRIANGLE(n0, n3, n4)         \
  |  |  ------------------
  |  |  |  |   56|  1.76k|    positions.push_back(n0);     \
  |  |  |  |   57|  1.76k|    positions.push_back(n1);     \
  |  |  |  |   58|  1.76k|    positions.push_back(n2);
  |  |  ------------------
  |  |   71|  1.76k|    }
  ------------------
  263|  1.76k|    ADD_PENTAGON(v16, v4, v14, v6, v17);
  ------------------
  |  |   61|  1.76k|    if (polygons) {                      \
  |  |  ------------------
  |  |  |  Branch (61:9): [True: 0, False: 1.76k]
  |  |  ------------------
  |  |   62|      0|        positions.push_back(n0);         \
  |  |   63|      0|        positions.push_back(n1);         \
  |  |   64|      0|        positions.push_back(n2);         \
  |  |   65|      0|        positions.push_back(n3);         \
  |  |   66|      0|        positions.push_back(n4);         \
  |  |   67|  1.76k|    } else {                             \
  |  |   68|  1.76k|        ADD_TRIANGLE(n0, n1, n2)         \
  |  |  ------------------
  |  |  |  |   56|  1.76k|    positions.push_back(n0);     \
  |  |  |  |   57|  1.76k|    positions.push_back(n1);     \
  |  |  |  |   58|  1.76k|    positions.push_back(n2);
  |  |  ------------------
  |  |   69|  1.76k|        ADD_TRIANGLE(n0, n2, n3)         \
  |  |  ------------------
  |  |  |  |   56|  1.76k|    positions.push_back(n0);     \
  |  |  |  |   57|  1.76k|    positions.push_back(n1);     \
  |  |  |  |   58|  1.76k|    positions.push_back(n2);
  |  |  ------------------
  |  |   70|  1.76k|        ADD_TRIANGLE(n0, n3, n4)         \
  |  |  ------------------
  |  |  |  |   56|  1.76k|    positions.push_back(n0);     \
  |  |  |  |   57|  1.76k|    positions.push_back(n1);     \
  |  |  |  |   58|  1.76k|    positions.push_back(n2);
  |  |  ------------------
  |  |   71|  1.76k|    }
  ------------------
  264|  1.76k|    ADD_PENTAGON(v9, v5, v15, v14, v4);
  ------------------
  |  |   61|  1.76k|    if (polygons) {                      \
  |  |  ------------------
  |  |  |  Branch (61:9): [True: 0, False: 1.76k]
  |  |  ------------------
  |  |   62|      0|        positions.push_back(n0);         \
  |  |   63|      0|        positions.push_back(n1);         \
  |  |   64|      0|        positions.push_back(n2);         \
  |  |   65|      0|        positions.push_back(n3);         \
  |  |   66|      0|        positions.push_back(n4);         \
  |  |   67|  1.76k|    } else {                             \
  |  |   68|  1.76k|        ADD_TRIANGLE(n0, n1, n2)         \
  |  |  ------------------
  |  |  |  |   56|  1.76k|    positions.push_back(n0);     \
  |  |  |  |   57|  1.76k|    positions.push_back(n1);     \
  |  |  |  |   58|  1.76k|    positions.push_back(n2);
  |  |  ------------------
  |  |   69|  1.76k|        ADD_TRIANGLE(n0, n2, n3)         \
  |  |  ------------------
  |  |  |  |   56|  1.76k|    positions.push_back(n0);     \
  |  |  |  |   57|  1.76k|    positions.push_back(n1);     \
  |  |  |  |   58|  1.76k|    positions.push_back(n2);
  |  |  ------------------
  |  |   70|  1.76k|        ADD_TRIANGLE(n0, n3, n4)         \
  |  |  ------------------
  |  |  |  |   56|  1.76k|    positions.push_back(n0);     \
  |  |  |  |   57|  1.76k|    positions.push_back(n1);     \
  |  |  |  |   58|  1.76k|    positions.push_back(n2);
  |  |  ------------------
  |  |   71|  1.76k|    }
  ------------------
  265|       |
  266|  1.76k|    ADD_PENTAGON(v6, v11, v10, v2, v17);
  ------------------
  |  |   61|  1.76k|    if (polygons) {                      \
  |  |  ------------------
  |  |  |  Branch (61:9): [True: 0, False: 1.76k]
  |  |  ------------------
  |  |   62|      0|        positions.push_back(n0);         \
  |  |   63|      0|        positions.push_back(n1);         \
  |  |   64|      0|        positions.push_back(n2);         \
  |  |   65|      0|        positions.push_back(n3);         \
  |  |   66|      0|        positions.push_back(n4);         \
  |  |   67|  1.76k|    } else {                             \
  |  |   68|  1.76k|        ADD_TRIANGLE(n0, n1, n2)         \
  |  |  ------------------
  |  |  |  |   56|  1.76k|    positions.push_back(n0);     \
  |  |  |  |   57|  1.76k|    positions.push_back(n1);     \
  |  |  |  |   58|  1.76k|    positions.push_back(n2);
  |  |  ------------------
  |  |   69|  1.76k|        ADD_TRIANGLE(n0, n2, n3)         \
  |  |  ------------------
  |  |  |  |   56|  1.76k|    positions.push_back(n0);     \
  |  |  |  |   57|  1.76k|    positions.push_back(n1);     \
  |  |  |  |   58|  1.76k|    positions.push_back(n2);
  |  |  ------------------
  |  |   70|  1.76k|        ADD_TRIANGLE(n0, n3, n4)         \
  |  |  ------------------
  |  |  |  |   56|  1.76k|    positions.push_back(n0);     \
  |  |  |  |   57|  1.76k|    positions.push_back(n1);     \
  |  |  |  |   58|  1.76k|    positions.push_back(n2);
  |  |  ------------------
  |  |   71|  1.76k|    }
  ------------------
  267|  1.76k|    ADD_PENTAGON(v3, v19, v18, v1, v13);
  ------------------
  |  |   61|  1.76k|    if (polygons) {                      \
  |  |  ------------------
  |  |  |  Branch (61:9): [True: 0, False: 1.76k]
  |  |  ------------------
  |  |   62|      0|        positions.push_back(n0);         \
  |  |   63|      0|        positions.push_back(n1);         \
  |  |   64|      0|        positions.push_back(n2);         \
  |  |   65|      0|        positions.push_back(n3);         \
  |  |   66|      0|        positions.push_back(n4);         \
  |  |   67|  1.76k|    } else {                             \
  |  |   68|  1.76k|        ADD_TRIANGLE(n0, n1, n2)         \
  |  |  ------------------
  |  |  |  |   56|  1.76k|    positions.push_back(n0);     \
  |  |  |  |   57|  1.76k|    positions.push_back(n1);     \
  |  |  |  |   58|  1.76k|    positions.push_back(n2);
  |  |  ------------------
  |  |   69|  1.76k|        ADD_TRIANGLE(n0, n2, n3)         \
  |  |  ------------------
  |  |  |  |   56|  1.76k|    positions.push_back(n0);     \
  |  |  |  |   57|  1.76k|    positions.push_back(n1);     \
  |  |  |  |   58|  1.76k|    positions.push_back(n2);
  |  |  ------------------
  |  |   70|  1.76k|        ADD_TRIANGLE(n0, n3, n4)         \
  |  |  ------------------
  |  |  |  |   56|  1.76k|    positions.push_back(n0);     \
  |  |  |  |   57|  1.76k|    positions.push_back(n1);     \
  |  |  |  |   58|  1.76k|    positions.push_back(n2);
  |  |  ------------------
  |  |   71|  1.76k|    }
  ------------------
  268|  1.76k|    ADD_PENTAGON(v7, v15, v5, v18, v19);
  ------------------
  |  |   61|  1.76k|    if (polygons) {                      \
  |  |  ------------------
  |  |  |  Branch (61:9): [True: 0, False: 1.76k]
  |  |  ------------------
  |  |   62|      0|        positions.push_back(n0);         \
  |  |   63|      0|        positions.push_back(n1);         \
  |  |   64|      0|        positions.push_back(n2);         \
  |  |   65|      0|        positions.push_back(n3);         \
  |  |   66|      0|        positions.push_back(n4);         \
  |  |   67|  1.76k|    } else {                             \
  |  |   68|  1.76k|        ADD_TRIANGLE(n0, n1, n2)         \
  |  |  ------------------
  |  |  |  |   56|  1.76k|    positions.push_back(n0);     \
  |  |  |  |   57|  1.76k|    positions.push_back(n1);     \
  |  |  |  |   58|  1.76k|    positions.push_back(n2);
  |  |  ------------------
  |  |   69|  1.76k|        ADD_TRIANGLE(n0, n2, n3)         \
  |  |  ------------------
  |  |  |  |   56|  1.76k|    positions.push_back(n0);     \
  |  |  |  |   57|  1.76k|    positions.push_back(n1);     \
  |  |  |  |   58|  1.76k|    positions.push_back(n2);
  |  |  ------------------
  |  |   70|  1.76k|        ADD_TRIANGLE(n0, n3, n4)         \
  |  |  ------------------
  |  |  |  |   56|  1.76k|    positions.push_back(n0);     \
  |  |  |  |   57|  1.76k|    positions.push_back(n1);     \
  |  |  |  |   58|  1.76k|    positions.push_back(n2);
  |  |  ------------------
  |  |   71|  1.76k|    }
  ------------------
  269|  1.76k|    ADD_PENTAGON(v7, v11, v6, v14, v15);
  ------------------
  |  |   61|  1.76k|    if (polygons) {                      \
  |  |  ------------------
  |  |  |  Branch (61:9): [True: 0, False: 1.76k]
  |  |  ------------------
  |  |   62|      0|        positions.push_back(n0);         \
  |  |   63|      0|        positions.push_back(n1);         \
  |  |   64|      0|        positions.push_back(n2);         \
  |  |   65|      0|        positions.push_back(n3);         \
  |  |   66|      0|        positions.push_back(n4);         \
  |  |   67|  1.76k|    } else {                             \
  |  |   68|  1.76k|        ADD_TRIANGLE(n0, n1, n2)         \
  |  |  ------------------
  |  |  |  |   56|  1.76k|    positions.push_back(n0);     \
  |  |  |  |   57|  1.76k|    positions.push_back(n1);     \
  |  |  |  |   58|  1.76k|    positions.push_back(n2);
  |  |  ------------------
  |  |   69|  1.76k|        ADD_TRIANGLE(n0, n2, n3)         \
  |  |  ------------------
  |  |  |  |   56|  1.76k|    positions.push_back(n0);     \
  |  |  |  |   57|  1.76k|    positions.push_back(n1);     \
  |  |  |  |   58|  1.76k|    positions.push_back(n2);
  |  |  ------------------
  |  |   70|  1.76k|        ADD_TRIANGLE(n0, n3, n4)         \
  |  |  ------------------
  |  |  |  |   56|  1.76k|    positions.push_back(n0);     \
  |  |  |  |   57|  1.76k|    positions.push_back(n1);     \
  |  |  |  |   58|  1.76k|    positions.push_back(n2);
  |  |  ------------------
  |  |   71|  1.76k|    }
  ------------------
  270|  1.76k|    ADD_PENTAGON(v7, v19, v3, v10, v11);
  ------------------
  |  |   61|  1.76k|    if (polygons) {                      \
  |  |  ------------------
  |  |  |  Branch (61:9): [True: 0, False: 1.76k]
  |  |  ------------------
  |  |   62|      0|        positions.push_back(n0);         \
  |  |   63|      0|        positions.push_back(n1);         \
  |  |   64|      0|        positions.push_back(n2);         \
  |  |   65|      0|        positions.push_back(n3);         \
  |  |   66|      0|        positions.push_back(n4);         \
  |  |   67|  1.76k|    } else {                             \
  |  |   68|  1.76k|        ADD_TRIANGLE(n0, n1, n2)         \
  |  |  ------------------
  |  |  |  |   56|  1.76k|    positions.push_back(n0);     \
  |  |  |  |   57|  1.76k|    positions.push_back(n1);     \
  |  |  |  |   58|  1.76k|    positions.push_back(n2);
  |  |  ------------------
  |  |   69|  1.76k|        ADD_TRIANGLE(n0, n2, n3)         \
  |  |  ------------------
  |  |  |  |   56|  1.76k|    positions.push_back(n0);     \
  |  |  |  |   57|  1.76k|    positions.push_back(n1);     \
  |  |  |  |   58|  1.76k|    positions.push_back(n2);
  |  |  ------------------
  |  |   70|  1.76k|        ADD_TRIANGLE(n0, n3, n4)         \
  |  |  ------------------
  |  |  |  |   56|  1.76k|    positions.push_back(n0);     \
  |  |  |  |   57|  1.76k|    positions.push_back(n1);     \
  |  |  |  |   58|  1.76k|    positions.push_back(n2);
  |  |  ------------------
  |  |   71|  1.76k|    }
  ------------------
  271|  1.76k|    return (polygons ? 5 : 3);
  ------------------
  |  Branch (271:13): [True: 0, False: 1.76k]
  ------------------
  272|  1.76k|}
_ZN6Assimp14StandardShapes14MakeHexahedronERNSt3__16vectorI10aiVector3tIfENS1_9allocatorIS4_EEEEb:
  322|      7|        bool polygons /*= false*/) {
  323|      7|    positions.reserve(positions.size() + 36);
  324|      7|    const ai_real length = ai_real(1.0) / ai_real(1.73205080);
  325|       |
  326|      7|    const aiVector3D v0 = aiVector3D(-1.0, -1.0, -1.0) * length;
  327|      7|    const aiVector3D v1 = aiVector3D(1.0, -1.0, -1.0) * length;
  328|      7|    const aiVector3D v2 = aiVector3D(1.0, 1.0, -1.0) * length;
  329|      7|    const aiVector3D v3 = aiVector3D(-1.0, 1.0, -1.0) * length;
  330|      7|    const aiVector3D v4 = aiVector3D(-1.0, -1.0, 1.0) * length;
  331|      7|    const aiVector3D v5 = aiVector3D(1.0, -1.0, 1.0) * length;
  332|      7|    const aiVector3D v6 = aiVector3D(1.0, 1.0, 1.0) * length;
  333|      7|    const aiVector3D v7 = aiVector3D(-1.0, 1.0, 1.0) * length;
  334|       |
  335|      7|    ADD_QUAD(v0, v3, v2, v1);
  ------------------
  |  |   74|      7|    if (polygons) {              \
  |  |  ------------------
  |  |  |  Branch (74:9): [True: 7, False: 0]
  |  |  ------------------
  |  |   75|      7|        positions.push_back(n0); \
  |  |   76|      7|        positions.push_back(n1); \
  |  |   77|      7|        positions.push_back(n2); \
  |  |   78|      7|        positions.push_back(n3); \
  |  |   79|      7|    } else {                     \
  |  |   80|      0|        ADD_TRIANGLE(n0, n1, n2) \
  |  |  ------------------
  |  |  |  |   56|      0|    positions.push_back(n0);     \
  |  |  |  |   57|      0|    positions.push_back(n1);     \
  |  |  |  |   58|      0|    positions.push_back(n2);
  |  |  ------------------
  |  |   81|      0|        ADD_TRIANGLE(n0, n2, n3) \
  |  |  ------------------
  |  |  |  |   56|      0|    positions.push_back(n0);     \
  |  |  |  |   57|      0|    positions.push_back(n1);     \
  |  |  |  |   58|      0|    positions.push_back(n2);
  |  |  ------------------
  |  |   82|      0|    }
  ------------------
  336|      7|    ADD_QUAD(v0, v1, v5, v4);
  ------------------
  |  |   74|      7|    if (polygons) {              \
  |  |  ------------------
  |  |  |  Branch (74:9): [True: 7, False: 0]
  |  |  ------------------
  |  |   75|      7|        positions.push_back(n0); \
  |  |   76|      7|        positions.push_back(n1); \
  |  |   77|      7|        positions.push_back(n2); \
  |  |   78|      7|        positions.push_back(n3); \
  |  |   79|      7|    } else {                     \
  |  |   80|      0|        ADD_TRIANGLE(n0, n1, n2) \
  |  |  ------------------
  |  |  |  |   56|      0|    positions.push_back(n0);     \
  |  |  |  |   57|      0|    positions.push_back(n1);     \
  |  |  |  |   58|      0|    positions.push_back(n2);
  |  |  ------------------
  |  |   81|      0|        ADD_TRIANGLE(n0, n2, n3) \
  |  |  ------------------
  |  |  |  |   56|      0|    positions.push_back(n0);     \
  |  |  |  |   57|      0|    positions.push_back(n1);     \
  |  |  |  |   58|      0|    positions.push_back(n2);
  |  |  ------------------
  |  |   82|      0|    }
  ------------------
  337|      7|    ADD_QUAD(v0, v4, v7, v3);
  ------------------
  |  |   74|      7|    if (polygons) {              \
  |  |  ------------------
  |  |  |  Branch (74:9): [True: 7, False: 0]
  |  |  ------------------
  |  |   75|      7|        positions.push_back(n0); \
  |  |   76|      7|        positions.push_back(n1); \
  |  |   77|      7|        positions.push_back(n2); \
  |  |   78|      7|        positions.push_back(n3); \
  |  |   79|      7|    } else {                     \
  |  |   80|      0|        ADD_TRIANGLE(n0, n1, n2) \
  |  |  ------------------
  |  |  |  |   56|      0|    positions.push_back(n0);     \
  |  |  |  |   57|      0|    positions.push_back(n1);     \
  |  |  |  |   58|      0|    positions.push_back(n2);
  |  |  ------------------
  |  |   81|      0|        ADD_TRIANGLE(n0, n2, n3) \
  |  |  ------------------
  |  |  |  |   56|      0|    positions.push_back(n0);     \
  |  |  |  |   57|      0|    positions.push_back(n1);     \
  |  |  |  |   58|      0|    positions.push_back(n2);
  |  |  ------------------
  |  |   82|      0|    }
  ------------------
  338|      7|    ADD_QUAD(v6, v5, v1, v2);
  ------------------
  |  |   74|      7|    if (polygons) {              \
  |  |  ------------------
  |  |  |  Branch (74:9): [True: 7, False: 0]
  |  |  ------------------
  |  |   75|      7|        positions.push_back(n0); \
  |  |   76|      7|        positions.push_back(n1); \
  |  |   77|      7|        positions.push_back(n2); \
  |  |   78|      7|        positions.push_back(n3); \
  |  |   79|      7|    } else {                     \
  |  |   80|      0|        ADD_TRIANGLE(n0, n1, n2) \
  |  |  ------------------
  |  |  |  |   56|      0|    positions.push_back(n0);     \
  |  |  |  |   57|      0|    positions.push_back(n1);     \
  |  |  |  |   58|      0|    positions.push_back(n2);
  |  |  ------------------
  |  |   81|      0|        ADD_TRIANGLE(n0, n2, n3) \
  |  |  ------------------
  |  |  |  |   56|      0|    positions.push_back(n0);     \
  |  |  |  |   57|      0|    positions.push_back(n1);     \
  |  |  |  |   58|      0|    positions.push_back(n2);
  |  |  ------------------
  |  |   82|      0|    }
  ------------------
  339|      7|    ADD_QUAD(v6, v2, v3, v7);
  ------------------
  |  |   74|      7|    if (polygons) {              \
  |  |  ------------------
  |  |  |  Branch (74:9): [True: 7, False: 0]
  |  |  ------------------
  |  |   75|      7|        positions.push_back(n0); \
  |  |   76|      7|        positions.push_back(n1); \
  |  |   77|      7|        positions.push_back(n2); \
  |  |   78|      7|        positions.push_back(n3); \
  |  |   79|      7|    } else {                     \
  |  |   80|      0|        ADD_TRIANGLE(n0, n1, n2) \
  |  |  ------------------
  |  |  |  |   56|      0|    positions.push_back(n0);     \
  |  |  |  |   57|      0|    positions.push_back(n1);     \
  |  |  |  |   58|      0|    positions.push_back(n2);
  |  |  ------------------
  |  |   81|      0|        ADD_TRIANGLE(n0, n2, n3) \
  |  |  ------------------
  |  |  |  |   56|      0|    positions.push_back(n0);     \
  |  |  |  |   57|      0|    positions.push_back(n1);     \
  |  |  |  |   58|      0|    positions.push_back(n2);
  |  |  ------------------
  |  |   82|      0|    }
  ------------------
  340|      7|    ADD_QUAD(v6, v7, v4, v5);
  ------------------
  |  |   74|      7|    if (polygons) {              \
  |  |  ------------------
  |  |  |  Branch (74:9): [True: 7, False: 0]
  |  |  ------------------
  |  |   75|      7|        positions.push_back(n0); \
  |  |   76|      7|        positions.push_back(n1); \
  |  |   77|      7|        positions.push_back(n2); \
  |  |   78|      7|        positions.push_back(n3); \
  |  |   79|      7|    } else {                     \
  |  |   80|      0|        ADD_TRIANGLE(n0, n1, n2) \
  |  |  ------------------
  |  |  |  |   56|      0|    positions.push_back(n0);     \
  |  |  |  |   57|      0|    positions.push_back(n1);     \
  |  |  |  |   58|      0|    positions.push_back(n2);
  |  |  ------------------
  |  |   81|      0|        ADD_TRIANGLE(n0, n2, n3) \
  |  |  ------------------
  |  |  |  |   56|      0|    positions.push_back(n0);     \
  |  |  |  |   57|      0|    positions.push_back(n1);     \
  |  |  |  |   58|      0|    positions.push_back(n2);
  |  |  ------------------
  |  |   82|      0|    }
  ------------------
  341|      7|    return (polygons ? 4 : 3);
  ------------------
  |  Branch (341:13): [True: 7, False: 0]
  ------------------
  342|      7|}
_ZN6Assimp14StandardShapes10MakeSphereEjRNSt3__16vectorI10aiVector3tIfENS1_9allocatorIS4_EEEE:
  352|      9|        std::vector<aiVector3D> &positions) {
  353|       |    // Reserve enough storage. Every subdivision
  354|       |    // splits each triangle in 4, the icosahedron consists of 60 verts
  355|      9|    positions.reserve(positions.size() + 60 * integer_pow(4, tess));
  356|       |
  357|       |    // Construct an icosahedron to start with
  358|      9|    MakeIcosahedron(positions);
  359|       |
  360|       |    // ... and subdivide it until the requested output
  361|       |    // tessellation is reached
  362|     39|    for (unsigned int i = 0; i < tess; ++i)
  ------------------
  |  Branch (362:30): [True: 30, False: 9]
  ------------------
  363|     30|        Subdivide(positions);
  364|      9|}

_Z7mydummyv:
   56|   766k|void mydummy() {}
_ZN6Assimp10Subdivider6CreateENS0_9AlgorithmE:
  110|      6|Subdivider *Subdivider::Create(Algorithm algo) {
  111|      6|    switch (algo) {
  ------------------
  |  Branch (111:13): [True: 6, False: 0]
  ------------------
  112|      6|    case CATMULL_CLARKE:
  ------------------
  |  Branch (112:5): [True: 6, False: 0]
  ------------------
  113|      6|        return new CatmullClarkSubdivider();
  114|      6|    };
  115|       |
  116|      0|    ai_assert(false);
  117|       |
  118|      0|    return nullptr; // shouldn't happen
  119|      6|}
_ZN22CatmullClarkSubdivider9SubdivideEPP6aiMeshmS2_jb:
  140|      6|        bool discard_input) {
  141|      6|    ai_assert(nullptr != smesh);
  142|      6|    ai_assert(nullptr != out);
  143|       |
  144|       |    // course, both regions may not overlap
  145|      6|    ai_assert(smesh < out || smesh + nmesh > out + nmesh);
  146|      6|    if (!num) {
  ------------------
  |  Branch (146:9): [True: 0, False: 6]
  ------------------
  147|       |        // No subdivision at all. Need to copy all the meshes .. argh.
  148|      0|        if (discard_input) {
  ------------------
  |  Branch (148:13): [True: 0, False: 0]
  ------------------
  149|      0|            for (size_t s = 0; s < nmesh; ++s) {
  ------------------
  |  Branch (149:32): [True: 0, False: 0]
  ------------------
  150|      0|                out[s] = smesh[s];
  151|      0|                smesh[s] = nullptr;
  152|      0|            }
  153|      0|        } else {
  154|      0|            for (size_t s = 0; s < nmesh; ++s) {
  ------------------
  |  Branch (154:32): [True: 0, False: 0]
  ------------------
  155|      0|                SceneCombiner::Copy(out + s, smesh[s]);
  156|      0|            }
  157|      0|        }
  158|      0|        return;
  159|      0|    }
  160|       |
  161|      6|    std::vector<aiMesh *> inmeshes;
  162|      6|    std::vector<aiMesh *> outmeshes;
  163|      6|    std::vector<unsigned int> maptbl;
  164|       |
  165|      6|    inmeshes.reserve(nmesh);
  166|      6|    outmeshes.reserve(nmesh);
  167|      6|    maptbl.reserve(nmesh);
  168|       |
  169|       |    // Remove pure line and point meshes from the working set to reduce the
  170|       |    // number of edge cases the subdivider is forced to deal with. Line and
  171|       |    // point meshes are simply passed through.
  172|     14|    for (size_t s = 0; s < nmesh; ++s) {
  ------------------
  |  Branch (172:24): [True: 8, False: 6]
  ------------------
  173|      8|        aiMesh *i = smesh[s];
  174|       |        // FIX - mPrimitiveTypes might not yet be initialized
  175|      8|        if (i->mPrimitiveTypes && (i->mPrimitiveTypes & (aiPrimitiveType_LINE | aiPrimitiveType_POINT)) == i->mPrimitiveTypes) {
  ------------------
  |  Branch (175:13): [True: 6, False: 2]
  |  Branch (175:35): [True: 0, False: 6]
  ------------------
  176|      0|            ASSIMP_LOG_VERBOSE_DEBUG("Catmull-Clark Subdivider: Skipping pure line/point mesh");
  177|       |
  178|      0|            if (discard_input) {
  ------------------
  |  Branch (178:17): [True: 0, False: 0]
  ------------------
  179|      0|                out[s] = i;
  180|      0|                smesh[s] = nullptr;
  181|      0|            } else {
  182|      0|                SceneCombiner::Copy(out + s, i);
  183|      0|            }
  184|      0|            continue;
  185|      0|        }
  186|       |
  187|      8|        outmeshes.push_back(nullptr);
  188|      8|        inmeshes.push_back(i);
  189|      8|        maptbl.push_back(static_cast<unsigned int>(s));
  190|      8|    }
  191|       |
  192|       |    // Do the actual subdivision on the preallocated storage. InternSubdivide
  193|       |    // *always* assumes that enough storage is available, it does not bother
  194|       |    // checking any ranges.
  195|      6|    ai_assert(inmeshes.size() == outmeshes.size());
  196|      6|    ai_assert(inmeshes.size() == maptbl.size());
  197|      6|    if (inmeshes.empty()) {
  ------------------
  |  Branch (197:9): [True: 0, False: 6]
  ------------------
  198|      0|        ASSIMP_LOG_WARN("Catmull-Clark Subdivider: Pure point/line scene, I can't do anything");
  199|      0|        return;
  200|      0|    }
  201|      6|    InternSubdivide(&inmeshes.front(), inmeshes.size(), &outmeshes.front(), num);
  202|     14|    for (unsigned int i = 0; i < maptbl.size(); ++i) {
  ------------------
  |  Branch (202:30): [True: 8, False: 6]
  ------------------
  203|      8|        ai_assert(nullptr != outmeshes[i]);
  204|      8|        out[maptbl[i]] = outmeshes[i];
  205|      8|    }
  206|       |
  207|      6|    if (discard_input) {
  ------------------
  |  Branch (207:9): [True: 6, False: 0]
  ------------------
  208|     14|        for (size_t s = 0; s < nmesh; ++s) {
  ------------------
  |  Branch (208:28): [True: 8, False: 6]
  ------------------
  209|      8|            delete smesh[s];
  210|      8|        }
  211|      6|    }
  212|      6|}
_ZN22CatmullClarkSubdivider15InternSubdivideEPKPK6aiMeshmPPS0_j:
  229|     18|        unsigned int num) {
  230|     18|    ai_assert(nullptr != smesh);
  231|     18|    ai_assert(nullptr != out);
  232|       |
  233|     18|    INIT_EDGE_HASH_TEMPORARIES();
  ------------------
  |  |  101|     18|    unsigned int eh_tmp0__, eh_tmp1__;
  ------------------
  234|       |
  235|       |    // no subdivision requested or end of recursive refinement
  236|     18|    if (!num) {
  ------------------
  |  Branch (236:9): [True: 0, False: 18]
  ------------------
  237|      0|        return;
  238|      0|    }
  239|       |
  240|     18|    UIntVector maptbl;
  241|     18|    SpatialSort spatial;
  242|       |
  243|       |    // ---------------------------------------------------------------------
  244|       |    // 0. Offset table to index all meshes continuously, generate a spatially
  245|       |    // sorted representation of all vertices in all meshes.
  246|       |    // ---------------------------------------------------------------------
  247|     18|    typedef std::pair<unsigned int, unsigned int> IntPair;
  248|     18|    std::vector<IntPair> moffsets(nmesh);
  249|     18|    unsigned int totfaces = 0, totvert = 0;
  250|     41|    for (size_t t = 0; t < nmesh; ++t) {
  ------------------
  |  Branch (250:24): [True: 23, False: 18]
  ------------------
  251|     23|        const aiMesh *mesh = smesh[t];
  252|       |
  253|     23|        spatial.Append(mesh->mVertices, mesh->mNumVertices, sizeof(aiVector3D), false);
  254|     23|        moffsets[t] = IntPair(totfaces, totvert);
  255|       |
  256|     23|        totfaces += mesh->mNumFaces;
  257|     23|        totvert += mesh->mNumVertices;
  258|     23|    }
  259|       |
  260|     18|    spatial.Finalize();
  261|     18|    const unsigned int num_unique = spatial.GenerateMappingTable(maptbl, ComputePositionEpsilon(smesh, nmesh));
  262|       |
  263|     18|#define FLATTEN_VERTEX_IDX(mesh_idx, vert_idx) (moffsets[mesh_idx].second + vert_idx)
  264|     18|#define FLATTEN_FACE_IDX(mesh_idx, face_idx) (moffsets[mesh_idx].first + face_idx)
  265|       |
  266|       |    // ---------------------------------------------------------------------
  267|       |    // 1. Compute the centroid point for all faces
  268|       |    // ---------------------------------------------------------------------
  269|     18|    std::vector<Vertex> centroids(totfaces);
  270|     18|    unsigned int nfacesout = 0;
  271|     41|    for (size_t t = 0, n = 0; t < nmesh; ++t) {
  ------------------
  |  Branch (271:31): [True: 23, False: 18]
  ------------------
  272|     23|        const aiMesh *mesh = smesh[t];
  273|  76.8k|        for (unsigned int i = 0; i < mesh->mNumFaces; ++i, ++n) {
  ------------------
  |  Branch (273:34): [True: 76.8k, False: 23]
  ------------------
  274|  76.8k|            const aiFace &face = mesh->mFaces[i];
  275|  76.8k|            Vertex &c = centroids[n];
  276|       |
  277|   384k|            for (unsigned int a = 0; a < face.mNumIndices; ++a) {
  ------------------
  |  Branch (277:38): [True: 307k, False: 76.8k]
  ------------------
  278|   307k|                c += Vertex(mesh, face.mIndices[a]);
  279|   307k|            }
  280|       |
  281|  76.8k|            c /= static_cast<float>(face.mNumIndices);
  282|  76.8k|            nfacesout += face.mNumIndices;
  283|  76.8k|        }
  284|     23|    }
  285|       |
  286|     18|    {
  287|       |        // we want edges to go away before the recursive calls so begin a new scope
  288|     18|        EdgeMap edges;
  289|       |
  290|       |        // ---------------------------------------------------------------------
  291|       |        // 2. Set each edge point to be the average of all neighbouring
  292|       |        // face points and original points. Every edge exists twice
  293|       |        // if there is a neighboring face.
  294|       |        // ---------------------------------------------------------------------
  295|     41|        for (size_t t = 0; t < nmesh; ++t) {
  ------------------
  |  Branch (295:28): [True: 23, False: 18]
  ------------------
  296|     23|            const aiMesh *mesh = smesh[t];
  297|       |
  298|  76.8k|            for (unsigned int i = 0; i < mesh->mNumFaces; ++i) {
  ------------------
  |  Branch (298:38): [True: 76.8k, False: 23]
  ------------------
  299|  76.8k|                const aiFace &face = mesh->mFaces[i];
  300|       |
  301|   384k|                for (unsigned int p = 0; p < face.mNumIndices; ++p) {
  ------------------
  |  Branch (301:42): [True: 307k, False: 76.8k]
  ------------------
  302|   307k|                    const unsigned int id[] = {
  303|   307k|                        face.mIndices[p],
  304|   307k|                        face.mIndices[p == face.mNumIndices - 1 ? 0 : p + 1]
  ------------------
  |  Branch (304:39): [True: 76.8k, False: 230k]
  ------------------
  305|   307k|                    };
  306|   307k|                    const unsigned int mp[] = {
  307|   307k|                        maptbl[FLATTEN_VERTEX_IDX(t, id[0])],
  ------------------
  |  |  263|   307k|#define FLATTEN_VERTEX_IDX(mesh_idx, vert_idx) (moffsets[mesh_idx].second + vert_idx)
  ------------------
  308|   307k|                        maptbl[FLATTEN_VERTEX_IDX(t, id[1])]
  ------------------
  |  |  263|   307k|#define FLATTEN_VERTEX_IDX(mesh_idx, vert_idx) (moffsets[mesh_idx].second + vert_idx)
  ------------------
  309|   307k|                    };
  310|       |
  311|   307k|                    Edge &e = edges[MAKE_EDGE_HASH(mp[0], mp[1])];
  ------------------
  |  |   97|   307k|#define MAKE_EDGE_HASH(id0, id1) (eh_tmp0__ = id0, eh_tmp1__ = id1, \
  |  |   98|   307k|        (eh_tmp0__ < eh_tmp1__ ? std::swap(eh_tmp0__, eh_tmp1__) : mydummy()), (uint64_t)eh_tmp0__ ^ ((uint64_t)eh_tmp1__ << 32u))
  |  |  ------------------
  |  |  |  Branch (98:10): [True: 153k, False: 153k]
  |  |  ------------------
  ------------------
  312|   307k|                    e.ref++;
  313|   307k|                    if (e.ref <= 2) {
  ------------------
  |  Branch (313:25): [True: 307k, False: 0]
  ------------------
  314|   307k|                        if (e.ref == 1) { // original points (end points) - add only once
  ------------------
  |  Branch (314:29): [True: 153k, False: 153k]
  ------------------
  315|   153k|                            e.edge_point = e.midpoint = Vertex(mesh, id[0]) + Vertex(mesh, id[1]);
  316|   153k|                            e.midpoint *= 0.5f;
  317|   153k|                        }
  318|   307k|                        e.edge_point += centroids[FLATTEN_FACE_IDX(t, i)];
  ------------------
  |  |  264|   307k|#define FLATTEN_FACE_IDX(mesh_idx, face_idx) (moffsets[mesh_idx].first + face_idx)
  ------------------
  319|   307k|                    }
  320|   307k|                }
  321|  76.8k|            }
  322|     23|        }
  323|       |
  324|       |        // ---------------------------------------------------------------------
  325|       |        // 3. Normalize edge points
  326|       |        // ---------------------------------------------------------------------
  327|     18|        {
  328|     18|            unsigned int bad_cnt = 0;
  329|   154k|            for (EdgeMap::iterator it = edges.begin(); it != edges.end(); ++it) {
  ------------------
  |  Branch (329:56): [True: 153k, False: 18]
  ------------------
  330|   153k|                if ((*it).second.ref < 2) {
  ------------------
  |  Branch (330:21): [True: 790, False: 153k]
  ------------------
  331|    790|                    ai_assert((*it).second.ref);
  332|    790|                    ++bad_cnt;
  333|    790|                }
  334|   153k|                (*it).second.edge_point *= 1.f / ((*it).second.ref + 2.f);
  335|   153k|            }
  336|       |
  337|     18|            if (bad_cnt) {
  ------------------
  |  Branch (337:17): [True: 5, False: 13]
  ------------------
  338|       |                // Report the number of bad edges. bad edges are referenced by less than two
  339|       |                // faces in the mesh. They occur at outer model boundaries in non-closed
  340|       |                // shapes.
  341|      5|                ASSIMP_LOG_VERBOSE_DEBUG("Catmull-Clark Subdivider: got ", bad_cnt, " bad edges touching only one face (totally ",
  342|      5|                        static_cast<unsigned int>(edges.size()), " edges). ");
  343|      5|            }
  344|     18|        }
  345|       |
  346|       |        // ---------------------------------------------------------------------
  347|       |        // 4. Compute a vertex-face adjacency table. We can't reuse the code
  348|       |        // from VertexTriangleAdjacency because we need the table for multiple
  349|       |        // meshes and out vertex indices need to be mapped to distinct values
  350|       |        // first.
  351|       |        // ---------------------------------------------------------------------
  352|     18|        UIntVector faceadjac(nfacesout), cntadjfac(maptbl.size(), 0), ofsadjvec(maptbl.size() + 1, 0);
  353|     18|        {
  354|     41|            for (size_t t = 0; t < nmesh; ++t) {
  ------------------
  |  Branch (354:32): [True: 23, False: 18]
  ------------------
  355|     23|                const aiMesh *const minp = smesh[t];
  356|  76.8k|                for (unsigned int i = 0; i < minp->mNumFaces; ++i) {
  ------------------
  |  Branch (356:42): [True: 76.8k, False: 23]
  ------------------
  357|       |
  358|  76.8k|                    const aiFace &f = minp->mFaces[i];
  359|   384k|                    for (unsigned int n = 0; n < f.mNumIndices; ++n) {
  ------------------
  |  Branch (359:46): [True: 307k, False: 76.8k]
  ------------------
  360|   307k|                        ++cntadjfac[maptbl[FLATTEN_VERTEX_IDX(t, f.mIndices[n])]];
  ------------------
  |  |  263|   307k|#define FLATTEN_VERTEX_IDX(mesh_idx, vert_idx) (moffsets[mesh_idx].second + vert_idx)
  ------------------
  361|   307k|                    }
  362|  76.8k|                }
  363|     23|            }
  364|     18|            unsigned int cur = 0;
  365|   307k|            for (size_t i = 0; i < cntadjfac.size(); ++i) {
  ------------------
  |  Branch (365:32): [True: 307k, False: 18]
  ------------------
  366|   307k|                ofsadjvec[i + 1] = cur;
  367|   307k|                cur += cntadjfac[i];
  368|   307k|            }
  369|     41|            for (size_t t = 0; t < nmesh; ++t) {
  ------------------
  |  Branch (369:32): [True: 23, False: 18]
  ------------------
  370|     23|                const aiMesh *const minp = smesh[t];
  371|  76.8k|                for (unsigned int i = 0; i < minp->mNumFaces; ++i) {
  ------------------
  |  Branch (371:42): [True: 76.8k, False: 23]
  ------------------
  372|       |
  373|  76.8k|                    const aiFace &f = minp->mFaces[i];
  374|   384k|                    for (unsigned int n = 0; n < f.mNumIndices; ++n) {
  ------------------
  |  Branch (374:46): [True: 307k, False: 76.8k]
  ------------------
  375|   307k|                        faceadjac[ofsadjvec[1 + maptbl[FLATTEN_VERTEX_IDX(t, f.mIndices[n])]]++] = FLATTEN_FACE_IDX(t, i);
  ------------------
  |  |  263|   307k|#define FLATTEN_VERTEX_IDX(mesh_idx, vert_idx) (moffsets[mesh_idx].second + vert_idx)
  ------------------
                                      faceadjac[ofsadjvec[1 + maptbl[FLATTEN_VERTEX_IDX(t, f.mIndices[n])]]++] = FLATTEN_FACE_IDX(t, i);
  ------------------
  |  |  264|   307k|#define FLATTEN_FACE_IDX(mesh_idx, face_idx) (moffsets[mesh_idx].first + face_idx)
  ------------------
  376|   307k|                    }
  377|  76.8k|                }
  378|     23|            }
  379|       |
  380|       |            // check the other way round for consistency
  381|     18|#ifdef ASSIMP_BUILD_DEBUG
  382|       |
  383|   307k|            for (size_t t = 0; t < ofsadjvec.size() - 1; ++t) {
  ------------------
  |  Branch (383:32): [True: 307k, False: 18]
  ------------------
  384|   614k|                for (unsigned int m = 0; m < cntadjfac[t]; ++m) {
  ------------------
  |  Branch (384:42): [True: 307k, False: 307k]
  ------------------
  385|   307k|                    const unsigned int fidx = faceadjac[ofsadjvec[t] + m];
  386|   307k|                    ai_assert(fidx < totfaces);
  387|   342k|                    for (size_t n = 1; n < nmesh; ++n) {
  ------------------
  |  Branch (387:40): [True: 81.2k, False: 260k]
  ------------------
  388|       |
  389|  81.2k|                        if (moffsets[n].first > fidx) {
  ------------------
  |  Branch (389:29): [True: 46.3k, False: 34.9k]
  ------------------
  390|  46.3k|                            const aiMesh *msh = smesh[--n];
  391|  46.3k|                            const aiFace &f = msh->mFaces[fidx - moffsets[n].first];
  392|       |
  393|  46.3k|                            bool haveit = false;
  394|   115k|                            for (unsigned int i = 0; i < f.mNumIndices; ++i) {
  ------------------
  |  Branch (394:54): [True: 115k, False: 0]
  ------------------
  395|   115k|                                if (maptbl[FLATTEN_VERTEX_IDX(n, f.mIndices[i])] == (unsigned int)t) {
  ------------------
  |  |  263|   115k|#define FLATTEN_VERTEX_IDX(mesh_idx, vert_idx) (moffsets[mesh_idx].second + vert_idx)
  ------------------
  |  Branch (395:37): [True: 46.3k, False: 69.5k]
  ------------------
  396|  46.3k|                                    haveit = true;
  397|  46.3k|                                    break;
  398|  46.3k|                                }
  399|   115k|                            }
  400|  46.3k|                            ai_assert(haveit);
  401|  46.3k|                            if (!haveit) {
  ------------------
  |  Branch (401:33): [True: 0, False: 46.3k]
  ------------------
  402|      0|                                ASSIMP_LOG_VERBOSE_DEBUG("Catmull-Clark Subdivider: Index not used");
  403|      0|                            }
  404|  46.3k|                            break;
  405|  46.3k|                        }
  406|  81.2k|                    }
  407|   307k|                }
  408|   307k|            }
  409|       |
  410|     18|#endif
  411|     18|        }
  412|       |
  413|     18|#define GET_ADJACENT_FACES_AND_CNT(vidx, fstartout, numout) \
  414|     18|    fstartout = &faceadjac[ofsadjvec[vidx]], numout = cntadjfac[vidx]
  415|       |
  416|     18|        typedef std::pair<bool, Vertex> TouchedOVertex;
  417|     18|        std::vector<TouchedOVertex> new_points(num_unique, TouchedOVertex(false, Vertex()));
  418|       |        // ---------------------------------------------------------------------
  419|       |        // 5. Spawn a quad from each face point to the corresponding edge points
  420|       |        // the original points being the fourth quad points.
  421|       |        // ---------------------------------------------------------------------
  422|     41|        for (size_t t = 0; t < nmesh; ++t) {
  ------------------
  |  Branch (422:28): [True: 23, False: 18]
  ------------------
  423|     23|            const aiMesh *const minp = smesh[t];
  424|     23|            aiMesh *const mout = out[t] = new aiMesh();
  425|       |
  426|  76.8k|            for (unsigned int a = 0; a < minp->mNumFaces; ++a) {
  ------------------
  |  Branch (426:38): [True: 76.8k, False: 23]
  ------------------
  427|  76.8k|                mout->mNumFaces += minp->mFaces[a].mNumIndices;
  428|  76.8k|            }
  429|       |
  430|       |            // We need random access to the old face buffer, so reuse is not possible.
  431|     23|            mout->mFaces = new aiFace[mout->mNumFaces];
  432|       |
  433|     23|            mout->mNumVertices = mout->mNumFaces * 4;
  434|     23|            mout->mVertices = new aiVector3D[mout->mNumVertices];
  435|       |
  436|       |            // quads only, keep material index
  437|     23|            mout->mPrimitiveTypes = aiPrimitiveType_POLYGON;
  438|     23|            mout->mMaterialIndex = minp->mMaterialIndex;
  439|       |
  440|     23|            if (minp->HasNormals()) {
  ------------------
  |  Branch (440:17): [True: 16, False: 7]
  ------------------
  441|     16|                mout->mNormals = new aiVector3D[mout->mNumVertices];
  442|     16|            }
  443|       |
  444|     23|            if (minp->HasTangentsAndBitangents()) {
  ------------------
  |  Branch (444:17): [True: 0, False: 23]
  ------------------
  445|      0|                mout->mTangents = new aiVector3D[mout->mNumVertices];
  446|      0|                mout->mBitangents = new aiVector3D[mout->mNumVertices];
  447|      0|            }
  448|       |
  449|     30|            for (unsigned int i = 0; minp->HasTextureCoords(i); ++i) {
  ------------------
  |  Branch (449:38): [True: 7, False: 23]
  ------------------
  450|      7|                mout->mTextureCoords[i] = new aiVector3D[mout->mNumVertices];
  451|      7|                mout->mNumUVComponents[i] = minp->mNumUVComponents[i];
  452|      7|            }
  453|       |
  454|     23|            for (unsigned int i = 0; minp->HasVertexColors(i); ++i) {
  ------------------
  |  Branch (454:38): [True: 0, False: 23]
  ------------------
  455|      0|                mout->mColors[i] = new aiColor4D[mout->mNumVertices];
  456|      0|            }
  457|       |
  458|     23|            mout->mNumVertices = mout->mNumFaces << 2u;
  459|  76.8k|            for (unsigned int i = 0, v = 0, n = 0; i < minp->mNumFaces; ++i) {
  ------------------
  |  Branch (459:52): [True: 76.8k, False: 23]
  ------------------
  460|       |
  461|  76.8k|                const aiFace &face = minp->mFaces[i];
  462|   384k|                for (unsigned int a = 0; a < face.mNumIndices; ++a) {
  ------------------
  |  Branch (462:42): [True: 307k, False: 76.8k]
  ------------------
  463|       |
  464|       |                    // Get a clean new face.
  465|   307k|                    aiFace &faceOut = mout->mFaces[n++];
  466|   307k|                    faceOut.mIndices = new unsigned int[faceOut.mNumIndices = 4];
  467|       |
  468|       |                    // Spawn a new quadrilateral (ccw winding) for this original point between:
  469|       |                    // a) face centroid
  470|   307k|                    centroids[FLATTEN_FACE_IDX(t, i)].SortBack(mout, faceOut.mIndices[0] = v++);
  ------------------
  |  |  264|   307k|#define FLATTEN_FACE_IDX(mesh_idx, face_idx) (moffsets[mesh_idx].first + face_idx)
  ------------------
  471|       |
  472|       |                    // b) adjacent edge on the left, seen from the centroid
  473|   307k|                    const Edge &e0 = edges[MAKE_EDGE_HASH(maptbl[FLATTEN_VERTEX_IDX(t, face.mIndices[a])],
  ------------------
  |  |   97|   614k|#define MAKE_EDGE_HASH(id0, id1) (eh_tmp0__ = id0, eh_tmp1__ = id1, \
  |  |  ------------------
  |  |  |  Branch (97:64): [True: 76.8k, False: 230k]
  |  |  ------------------
  |  |   98|   307k|        (eh_tmp0__ < eh_tmp1__ ? std::swap(eh_tmp0__, eh_tmp1__) : mydummy()), (uint64_t)eh_tmp0__ ^ ((uint64_t)eh_tmp1__ << 32u))
  |  |  ------------------
  |  |  |  Branch (98:10): [True: 153k, False: 153k]
  |  |  ------------------
  ------------------
  474|   307k|                            maptbl[FLATTEN_VERTEX_IDX(t, face.mIndices[a == face.mNumIndices - 1 ? 0 : a + 1])])]; // fixme: replace with mod face.mNumIndices?
  475|       |
  476|       |                    // c) adjacent edge on the right, seen from the centroid
  477|   307k|                    const Edge &e1 = edges[MAKE_EDGE_HASH(maptbl[FLATTEN_VERTEX_IDX(t, face.mIndices[a])],
  ------------------
  |  |   97|   614k|#define MAKE_EDGE_HASH(id0, id1) (eh_tmp0__ = id0, eh_tmp1__ = id1, \
  |  |  ------------------
  |  |  |  Branch (97:64): [True: 76.8k, False: 230k]
  |  |  ------------------
  |  |   98|   307k|        (eh_tmp0__ < eh_tmp1__ ? std::swap(eh_tmp0__, eh_tmp1__) : mydummy()), (uint64_t)eh_tmp0__ ^ ((uint64_t)eh_tmp1__ << 32u))
  |  |  ------------------
  |  |  |  Branch (98:10): [True: 153k, False: 153k]
  |  |  ------------------
  ------------------
  478|   307k|                            maptbl[FLATTEN_VERTEX_IDX(t, face.mIndices[!a ? face.mNumIndices - 1 : a - 1])])]; // fixme: replace with mod face.mNumIndices?
  479|       |
  480|   307k|                    e0.edge_point.SortBack(mout, faceOut.mIndices[3] = v++);
  481|   307k|                    e1.edge_point.SortBack(mout, faceOut.mIndices[1] = v++);
  482|       |
  483|       |                    // d= original point P with distinct index i
  484|       |                    // F := 0
  485|       |                    // R := 0
  486|       |                    // n := 0
  487|       |                    // for each face f containing i
  488|       |                    //    F := F+ centroid of f
  489|       |                    //    R := R+ midpoint of edge of f from i to i+1
  490|       |                    //    n := n+1
  491|       |                    //
  492|       |                    // (F+2R+(n-3)P)/n
  493|   307k|                    const unsigned int org = maptbl[FLATTEN_VERTEX_IDX(t, face.mIndices[a])];
  ------------------
  |  |  263|   307k|#define FLATTEN_VERTEX_IDX(mesh_idx, vert_idx) (moffsets[mesh_idx].second + vert_idx)
  ------------------
  494|   307k|                    TouchedOVertex &ov = new_points[org];
  495|       |
  496|   307k|                    if (!ov.first) {
  ------------------
  |  Branch (496:25): [True: 77.1k, False: 230k]
  ------------------
  497|  77.1k|                        ov.first = true;
  498|       |
  499|  77.1k|                        const unsigned int *adj;
  500|  77.1k|                        unsigned int cnt;
  501|  77.1k|                        GET_ADJACENT_FACES_AND_CNT(org, adj, cnt);
  ------------------
  |  |  414|  77.1k|    fstartout = &faceadjac[ofsadjvec[vidx]], numout = cntadjfac[vidx]
  ------------------
  502|       |
  503|  77.1k|                        if (cnt < 3) {
  ------------------
  |  Branch (503:29): [True: 704, False: 76.4k]
  ------------------
  504|    704|                            ov.second = Vertex(minp, face.mIndices[a]);
  505|  76.4k|                        } else {
  506|       |
  507|  76.4k|                            Vertex F, R;
  508|   382k|                            for (unsigned int o = 0; o < cnt; ++o) {
  ------------------
  |  Branch (508:54): [True: 305k, False: 76.4k]
  ------------------
  509|   305k|                                ai_assert(adj[o] < totfaces);
  510|   305k|                                F += centroids[adj[o]];
  511|       |
  512|       |                                // adj[0] is a global face index - search the face in the mesh list
  513|   305k|                                const aiMesh *mp = nullptr;
  514|   305k|                                size_t nidx;
  515|       |
  516|   305k|                                if (adj[o] < moffsets[0].first) {
  ------------------
  |  Branch (516:37): [True: 0, False: 305k]
  ------------------
  517|      0|                                    mp = smesh[nidx = 0];
  518|   305k|                                } else {
  519|   340k|                                    for (nidx = 1; nidx <= nmesh; ++nidx) {
  ------------------
  |  Branch (519:52): [True: 340k, False: 0]
  ------------------
  520|   340k|                                        if (nidx == nmesh || moffsets[nidx].first > adj[o]) {
  ------------------
  |  Branch (520:45): [True: 259k, False: 81.2k]
  |  Branch (520:62): [True: 46.3k, False: 34.9k]
  ------------------
  521|   305k|                                            mp = smesh[--nidx];
  522|   305k|                                            break;
  523|   305k|                                        }
  524|   340k|                                    }
  525|   305k|                                }
  526|       |
  527|   305k|                                if (mp == nullptr) {
  ------------------
  |  Branch (527:37): [True: 0, False: 305k]
  ------------------
  528|      0|                                    continue;
  529|      0|                                }
  530|       |
  531|   305k|                                ai_assert(adj[o] - moffsets[nidx].first < mp->mNumFaces);
  532|   305k|                                const aiFace &f = mp->mFaces[adj[o] - moffsets[nidx].first];
  533|   305k|                                bool haveit = false;
  534|       |
  535|       |                                // find our original point in the face
  536|   763k|                                for (unsigned int m = 0; m < f.mNumIndices; ++m) {
  ------------------
  |  Branch (536:58): [True: 763k, False: 0]
  ------------------
  537|   763k|                                    if (maptbl[FLATTEN_VERTEX_IDX(nidx, f.mIndices[m])] == org) {
  ------------------
  |  |  263|   763k|#define FLATTEN_VERTEX_IDX(mesh_idx, vert_idx) (moffsets[mesh_idx].second + vert_idx)
  ------------------
  |  Branch (537:41): [True: 305k, False: 457k]
  ------------------
  538|       |
  539|       |                                        // add *both* edges. this way, we can be sure that we add
  540|       |                                        // *all* adjacent edges to R. In a closed shape, every
  541|       |                                        // edge is added twice - so we simply leave out the
  542|       |                                        // factor 2.f in the amove formula and get the right
  543|       |                                        // result.
  544|       |
  545|   305k|                                        const Edge &c0 = edges[MAKE_EDGE_HASH(org, maptbl[FLATTEN_VERTEX_IDX(
  ------------------
  |  |   97|   611k|#define MAKE_EDGE_HASH(id0, id1) (eh_tmp0__ = id0, eh_tmp1__ = id1, \
  |  |  ------------------
  |  |  |  Branch (97:64): [True: 76.7k, False: 229k]
  |  |  ------------------
  |  |   98|   305k|        (eh_tmp0__ < eh_tmp1__ ? std::swap(eh_tmp0__, eh_tmp1__) : mydummy()), (uint64_t)eh_tmp0__ ^ ((uint64_t)eh_tmp1__ << 32u))
  |  |  ------------------
  |  |  |  Branch (98:10): [True: 152k, False: 153k]
  |  |  ------------------
  ------------------
  546|   305k|                                                                                           nidx, f.mIndices[!m ? f.mNumIndices - 1 : m - 1])])];
  547|       |                                        // fixme: replace with mod face.mNumIndices?
  548|       |
  549|   305k|                                        const Edge &c1 = edges[MAKE_EDGE_HASH(org, maptbl[FLATTEN_VERTEX_IDX(
  ------------------
  |  |   97|   611k|#define MAKE_EDGE_HASH(id0, id1) (eh_tmp0__ = id0, eh_tmp1__ = id1, \
  |  |  ------------------
  |  |  |  Branch (97:64): [True: 76.4k, False: 229k]
  |  |  ------------------
  |  |   98|   305k|        (eh_tmp0__ < eh_tmp1__ ? std::swap(eh_tmp0__, eh_tmp1__) : mydummy()), (uint64_t)eh_tmp0__ ^ ((uint64_t)eh_tmp1__ << 32u))
  |  |  ------------------
  |  |  |  Branch (98:10): [True: 152k, False: 153k]
  |  |  ------------------
  ------------------
  550|   305k|                                                                                           nidx, f.mIndices[m == f.mNumIndices - 1 ? 0 : m + 1])])];
  551|       |                                        // fixme: replace with mod face.mNumIndices?
  552|   305k|                                        R += c0.midpoint + c1.midpoint;
  553|       |
  554|   305k|                                        haveit = true;
  555|   305k|                                        break;
  556|   305k|                                    }
  557|   763k|                                }
  558|       |
  559|       |                                // this invariant *must* hold if the vertex-to-face adjacency table is valid
  560|   305k|                                ai_assert(haveit);
  561|   305k|                                if (!haveit) {
  ------------------
  |  Branch (561:37): [True: 0, False: 305k]
  ------------------
  562|      0|                                    ASSIMP_LOG_WARN("OBJ: no name for material library specified.");
  563|      0|                                }
  564|   305k|                            }
  565|       |
  566|  76.4k|                            const float div = static_cast<float>(cnt), divsq = 1.f / (div * div);
  567|  76.4k|                            ov.second = Vertex(minp, face.mIndices[a]) * ((div - 3.f) / div) + R * divsq + F * divsq;
  568|  76.4k|                        }
  569|  77.1k|                    }
  570|   307k|                    ov.second.SortBack(mout, faceOut.mIndices[2] = v++);
  571|   307k|                }
  572|  76.8k|            }
  573|     23|        }
  574|     18|    } // end of scope for edges, freeing its memory
  575|       |
  576|       |    // ---------------------------------------------------------------------
  577|       |    // 7. Apply the next subdivision step.
  578|       |    // ---------------------------------------------------------------------
  579|     18|    if (num != 1) {
  ------------------
  |  Branch (579:9): [True: 12, False: 6]
  ------------------
  580|     12|        std::vector<aiMesh *> tmp(nmesh);
  581|     12|        InternSubdivide(out, nmesh, &tmp.front(), num - 1);
  582|     27|        for (size_t i = 0; i < nmesh; ++i) {
  ------------------
  |  Branch (582:28): [True: 15, False: 12]
  ------------------
  583|     15|            delete out[i];
  584|     15|            out[i] = tmp[i];
  585|     15|        }
  586|     12|    }
  587|     18|}
_ZN22CatmullClarkSubdivider4EdgeC2Ev:
   77|   153k|                ref(0) {}

aiGetVersionMinor:
   72|  1.11k|ASSIMP_API unsigned int aiGetVersionMinor() {
   73|  1.11k|    return VER_MINOR;
  ------------------
  |  |    8|  1.11k|#define VER_MINOR 0
  ------------------
   74|  1.11k|}
aiGetVersionMajor:
   78|  1.11k|ASSIMP_API unsigned int aiGetVersionMajor() {
   79|  1.11k|    return VER_MAJOR;
  ------------------
  |  |    7|  1.11k|#define VER_MAJOR 6
  ------------------
   80|  1.11k|}
aiGetCompileFlags:
   84|    909|ASSIMP_API unsigned int aiGetCompileFlags() {
   85|       |
   86|    909|    unsigned int flags = 0;
   87|       |
   88|       |#ifdef ASSIMP_BUILD_BOOST_WORKAROUND
   89|       |    flags |= ASSIMP_CFLAGS_NOBOOST;
   90|       |#endif
   91|    909|#ifdef ASSIMP_BUILD_SINGLETHREADED
   92|    909|    flags |= ASSIMP_CFLAGS_SINGLETHREADED;
  ------------------
  |  |  107|    909|#define ASSIMP_CFLAGS_SINGLETHREADED    0x10
  ------------------
   93|    909|#endif
   94|    909|#ifdef ASSIMP_BUILD_DEBUG
   95|    909|    flags |= ASSIMP_CFLAGS_DEBUG;
  ------------------
  |  |  102|    909|#define ASSIMP_CFLAGS_DEBUG   0x4
  ------------------
   96|    909|#endif
   97|       |#ifdef ASSIMP_BUILD_DLL_EXPORT
   98|       |    flags |= ASSIMP_CFLAGS_SHARED;
   99|       |#endif
  100|       |#ifdef _STLPORT_VERSION
  101|       |    flags |= ASSIMP_CFLAGS_STLPORT;
  102|       |#endif
  103|       |#ifdef ASSIMP_DOUBLE_PRECISION
  104|       |    flags |= ASSIMP_CFLAGS_DOUBLE_SUPPORT;
  105|       |#endif
  106|       |
  107|    909|    return flags;
  108|    909|}
aiGetVersionRevision:
  111|  1.11k|ASSIMP_API unsigned int aiGetVersionRevision() {
  112|  1.11k|    return GitVersion;
  ------------------
  |  |    4|  1.11k|#define GitVersion 0x8ff00557
  ------------------
  113|  1.11k|}

_ZN6Assimp23VertexTriangleAdjacencyC2EP6aiFacejjb:
   55|  1.91k|        bool bComputeNumTriangles /*= false*/) {
   56|       |    // compute the number of referenced vertices if it wasn't specified by the caller
   57|  1.91k|    const aiFace *const pcFaceEnd = pcFaces + iNumFaces;
   58|  1.91k|    if (0 == iNumVertices) {
  ------------------
  |  Branch (58:9): [True: 0, False: 1.91k]
  ------------------
   59|      0|        for (aiFace *pcFace = pcFaces; pcFace != pcFaceEnd; ++pcFace) {
  ------------------
  |  Branch (59:40): [True: 0, False: 0]
  ------------------
   60|      0|            ai_assert(nullptr != pcFace);
   61|      0|            ai_assert(3 == pcFace->mNumIndices);
   62|      0|            iNumVertices = std::max(iNumVertices, pcFace->mIndices[0]);
   63|      0|            iNumVertices = std::max(iNumVertices, pcFace->mIndices[1]);
   64|      0|            iNumVertices = std::max(iNumVertices, pcFace->mIndices[2]);
   65|      0|        }
   66|      0|    }
   67|       |
   68|  1.91k|    mNumVertices = iNumVertices + 1;
   69|       |
   70|  1.91k|    unsigned int *pi;
   71|       |
   72|       |    // allocate storage
   73|  1.91k|    if (bComputeNumTriangles) {
  ------------------
  |  Branch (73:9): [True: 1.91k, False: 0]
  ------------------
   74|  1.91k|        pi = mLiveTriangles = new unsigned int[iNumVertices + 1];
   75|  1.91k|        ::memset(mLiveTriangles, 0, sizeof(unsigned int) * (iNumVertices + 1));
   76|  1.91k|        mOffsetTable = new unsigned int[iNumVertices + 2] + 1;
   77|  1.91k|    } else {
   78|      0|        pi = mOffsetTable = new unsigned int[iNumVertices + 2] + 1;
   79|      0|        ::memset(mOffsetTable, 0, sizeof(unsigned int) * (iNumVertices + 1));
   80|      0|        mLiveTriangles = nullptr; // important, otherwise the d'tor would crash
   81|      0|    }
   82|       |
   83|       |    // get a pointer to the end of the buffer
   84|  1.91k|    unsigned int *piEnd = pi + iNumVertices;
   85|  1.91k|    *piEnd++ = 0u;
   86|       |
   87|       |    // first pass: compute the number of faces referencing each vertex
   88|  1.37M|    for (aiFace *pcFace = pcFaces; pcFace != pcFaceEnd; ++pcFace) {
  ------------------
  |  Branch (88:36): [True: 1.37M, False: 1.91k]
  ------------------
   89|  1.37M|        unsigned nind = pcFace->mNumIndices;
   90|  1.37M|        unsigned *ind = pcFace->mIndices;
   91|  1.37M|        if (nind > 0) pi[ind[0]]++;
  ------------------
  |  Branch (91:13): [True: 1.37M, False: 0]
  ------------------
   92|  1.37M|        if (nind > 1) pi[ind[1]]++;
  ------------------
  |  Branch (92:13): [True: 1.37M, False: 0]
  ------------------
   93|  1.37M|        if (nind > 2) pi[ind[2]]++;
  ------------------
  |  Branch (93:13): [True: 1.37M, False: 0]
  ------------------
   94|  1.37M|    }
   95|       |
   96|       |    // second pass: compute the final offset table
   97|  1.91k|    unsigned int iSum = 0;
   98|  1.91k|    unsigned int *piCurOut = this->mOffsetTable;
   99|   742k|    for (unsigned int *piCur = pi; piCur != piEnd; ++piCur, ++piCurOut) {
  ------------------
  |  Branch (99:36): [True: 740k, False: 1.91k]
  ------------------
  100|       |
  101|   740k|        unsigned int iLastSum = iSum;
  102|   740k|        iSum += *piCur;
  103|   740k|        *piCurOut = iLastSum;
  104|   740k|    }
  105|  1.91k|    pi = this->mOffsetTable;
  106|       |
  107|       |    // third pass: compute the final table
  108|  1.91k|    this->mAdjacencyTable = new unsigned int[iSum];
  109|  1.91k|    iSum = 0;
  110|  1.37M|    for (aiFace *pcFace = pcFaces; pcFace != pcFaceEnd; ++pcFace, ++iSum) {
  ------------------
  |  Branch (110:36): [True: 1.37M, False: 1.91k]
  ------------------
  111|  1.37M|        unsigned nind = pcFace->mNumIndices;
  112|  1.37M|        unsigned *ind = pcFace->mIndices;
  113|       |
  114|  1.37M|        if (nind > 0) mAdjacencyTable[pi[ind[0]]++] = iSum;
  ------------------
  |  Branch (114:13): [True: 1.37M, False: 0]
  ------------------
  115|  1.37M|        if (nind > 1) mAdjacencyTable[pi[ind[1]]++] = iSum;
  ------------------
  |  Branch (115:13): [True: 1.37M, False: 0]
  ------------------
  116|  1.37M|        if (nind > 2) mAdjacencyTable[pi[ind[2]]++] = iSum;
  ------------------
  |  Branch (116:13): [True: 1.37M, False: 0]
  ------------------
  117|  1.37M|    }
  118|       |    // fourth pass: undo the offset computations made during the third pass
  119|       |    // We could do this in a separate buffer, but this would be TIMES slower.
  120|  1.91k|    --mOffsetTable;
  121|  1.91k|    *mOffsetTable = 0u;
  122|  1.91k|}
_ZN6Assimp23VertexTriangleAdjacencyD2Ev:
  124|  1.91k|VertexTriangleAdjacency::~VertexTriangleAdjacency() {
  125|       |    // delete allocated storage
  126|  1.91k|    delete[] mOffsetTable;
  127|  1.91k|    delete[] mAdjacencyTable;
  128|  1.91k|    delete[] mLiveTriangles;
  129|  1.91k|}

_ZNK6Assimp23VertexTriangleAdjacency20GetAdjacentTrianglesEj:
   85|   558k|    unsigned int* GetAdjacentTriangles(unsigned int iVertIndex) const {
   86|       |        ai_assert(iVertIndex < mNumVertices);
   87|   558k|        return &mAdjacencyTable[ mOffsetTable[iVertIndex]];
   88|   558k|    }

_ZN6Assimp14IOSystem2Unzip4openEPvPKci:
  106|    401|voidpf IOSystem2Unzip::open(voidpf opaque, const char *filename, int mode) {
  107|    401|    IOSystem *io_system = reinterpret_cast<IOSystem *>(opaque);
  108|       |
  109|    401|    const char *mode_fopen = nullptr;
  110|    401|    if ((mode & ZLIB_FILEFUNC_MODE_READWRITEFILTER) == ZLIB_FILEFUNC_MODE_READ) {
  ------------------
  |  |  120|    401|#define ZLIB_FILEFUNC_MODE_READWRITEFILTER (3)
  ------------------
                  if ((mode & ZLIB_FILEFUNC_MODE_READWRITEFILTER) == ZLIB_FILEFUNC_MODE_READ) {
  ------------------
  |  |  118|    401|#define ZLIB_FILEFUNC_MODE_READ      (1)
  ------------------
  |  Branch (110:9): [True: 401, False: 0]
  ------------------
  111|    401|        mode_fopen = "rb";
  112|    401|    } else {
  113|      0|        if (mode & ZLIB_FILEFUNC_MODE_EXISTING) {
  ------------------
  |  |  122|      0|#define ZLIB_FILEFUNC_MODE_EXISTING (4)
  ------------------
  |  Branch (113:13): [True: 0, False: 0]
  ------------------
  114|      0|            mode_fopen = "r+b";
  115|      0|        } else {
  116|      0|            if (mode & ZLIB_FILEFUNC_MODE_CREATE) {
  ------------------
  |  |  123|      0|#define ZLIB_FILEFUNC_MODE_CREATE   (8)
  ------------------
  |  Branch (116:17): [True: 0, False: 0]
  ------------------
  117|      0|                mode_fopen = "wb";
  118|      0|            }
  119|      0|        }
  120|      0|    }
  121|       |
  122|    401|    return (voidpf)io_system->Open(filename, mode_fopen);
  123|    401|}
_ZN6Assimp14IOSystem2Unzip4readEPvS1_S1_m:
  149|  46.4k|uLong IOSystem2Unzip::read(voidpf /*opaque*/, voidpf stream, void *buf, uLong size) {
  150|  46.4k|    IOStream *io_stream = (IOStream *)stream;
  151|       |
  152|  46.4k|    return static_cast<uLong>(io_stream->Read(buf, 1, size));
  153|  46.4k|}
_ZN6Assimp14IOSystem2Unzip4tellEPvS1_:
  163|    802|long IOSystem2Unzip::tell(voidpf /*opaque*/, voidpf stream) {
  164|    802|    IOStream *io_stream = (IOStream *)stream;
  165|       |
  166|    802|    return static_cast<long>(io_stream->Tell());
  167|    802|}
_ZN6Assimp14IOSystem2Unzip4seekEPvS1_mi:
  170|  34.0k|long IOSystem2Unzip::seek(voidpf /*opaque*/, voidpf stream, uLong offset, int origin) {
  171|  34.0k|    IOStream *io_stream = (IOStream *)stream;
  172|       |
  173|  34.0k|    aiOrigin assimp_origin;
  174|  34.0k|    switch (origin) {
  175|      0|        default:
  ------------------
  |  Branch (175:9): [True: 0, False: 34.0k]
  ------------------
  176|     96|        case ZLIB_FILEFUNC_SEEK_CUR:
  ------------------
  |  |  114|     96|#define ZLIB_FILEFUNC_SEEK_CUR (1)
  ------------------
  |  Branch (176:9): [True: 96, False: 33.9k]
  ------------------
  177|     96|            assimp_origin = aiOrigin_CUR;
  178|     96|            break;
  179|    802|        case ZLIB_FILEFUNC_SEEK_END:
  ------------------
  |  |  115|    802|#define ZLIB_FILEFUNC_SEEK_END (2)
  ------------------
  |  Branch (179:9): [True: 802, False: 33.2k]
  ------------------
  180|    802|            assimp_origin = aiOrigin_END;
  181|    802|            break;
  182|  33.1k|        case ZLIB_FILEFUNC_SEEK_SET:
  ------------------
  |  |  116|  33.1k|#define ZLIB_FILEFUNC_SEEK_SET (0)
  ------------------
  |  Branch (182:9): [True: 33.1k, False: 898]
  ------------------
  183|  33.1k|            assimp_origin = aiOrigin_SET;
  184|  33.1k|            break;
  185|  34.0k|    }
  186|       |
  187|  34.0k|    return (io_stream->Seek(offset, assimp_origin) == aiReturn_SUCCESS ? 0 : -1);
  ------------------
  |  Branch (187:13): [True: 33.6k, False: 372]
  ------------------
  188|  34.0k|}
_ZN6Assimp14IOSystem2Unzip5closeEPvS1_:
  191|    401|int IOSystem2Unzip::close(voidpf opaque, voidpf stream) {
  192|    401|    IOSystem *io_system = (IOSystem *)opaque;
  193|    401|    IOStream *io_stream = (IOStream *)stream;
  194|       |
  195|    401|    io_system->Close(io_stream);
  196|       |
  197|    401|    return 0;
  198|    401|}
_ZN6Assimp14IOSystem2Unzip3getEPNS_8IOSystemE:
  206|    401|zlib_filefunc_def IOSystem2Unzip::get(IOSystem *pIOHandler) {
  207|    401|    zlib_filefunc_def mapping;
  208|       |
  209|    401|    mapping.zopen_file = (open_file_func)open;
  210|       |#ifdef _UNZ_H
  211|       |    mapping.zopendisk_file = (opendisk_file_func)opendisk;
  212|       |#endif
  213|    401|    mapping.zread_file = (read_file_func)read;
  214|    401|    mapping.zwrite_file = (write_file_func)write;
  215|    401|    mapping.ztell_file = (tell_file_func)tell;
  216|    401|    mapping.zseek_file = (seek_file_func)seek;
  217|    401|    mapping.zclose_file = (close_file_func)close;
  218|    401|    mapping.zerror_file = testerror;
  219|       |
  220|    401|    mapping.opaque = reinterpret_cast<voidpf>(pIOHandler);
  221|       |
  222|    401|    return mapping;
  223|    401|}
_ZN6Assimp11ZipFileInfoC2EPvm:
  242|    312|        m_Size(size) {
  243|    312|    ai_assert(m_Size != 0);
  ------------------
  |  |   67|    312|#   define ai_assert(expression) (void)((!!(expression)) || (Assimp::aiAssertViolation(#expression, __FILE__, __LINE__), 0))
  |  |  ------------------
  |  |  |  Branch (67:41): [True: 312, False: 0]
  |  |  |  Branch (67:61): [True: 0, False: 0]
  |  |  ------------------
  ------------------
  244|       |    // Workaround for MSVC 2013 - C2797
  245|    312|    m_ZipFilePos.num_of_file = 0;
  246|    312|    m_ZipFilePos.pos_in_zip_directory = 0;
  247|    312|    unzGetFilePos(zip_handle, &(m_ZipFilePos));
  248|    312|}
_ZNK6Assimp11ZipFileInfo7ExtractERNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEPv:
  251|      9|ZipFile *ZipFileInfo::Extract(std::string &filename, unzFile zip_handle) const {
  252|       |    // Find in the ZIP. This cannot fail
  253|      9|    unz_file_pos_s *filepos = const_cast<unz_file_pos_s *>(&(m_ZipFilePos));
  254|      9|    if (unzGoToFilePos(zip_handle, filepos) != UNZ_OK)
  ------------------
  |  |   74|      9|#define UNZ_OK                          (0)
  ------------------
  |  Branch (254:9): [True: 0, False: 9]
  ------------------
  255|      0|        return nullptr;
  256|       |
  257|      9|    if (unzOpenCurrentFile(zip_handle) != UNZ_OK)
  ------------------
  |  |   74|      9|#define UNZ_OK                          (0)
  ------------------
  |  Branch (257:9): [True: 1, False: 8]
  ------------------
  258|      1|        return nullptr;
  259|       |
  260|      8|    ZipFile *zip_file = new ZipFile(filename, m_Size);
  261|       |
  262|       |    // Unzip has a limit of UINT16_MAX bytes buffer
  263|      8|    uint16_t unzipBufferSize = zip_file->m_Size <= UINT16_MAX ? static_cast<uint16_t>(zip_file->m_Size) : UINT16_MAX;
  ------------------
  |  Branch (263:32): [True: 6, False: 2]
  ------------------
  264|      8|    std::unique_ptr<uint8_t[]> unzipBuffer = std::unique_ptr<uint8_t[]>(new uint8_t[unzipBufferSize]);
  265|      8|    size_t readCount = 0;
  266|     24|    while (readCount < zip_file->m_Size)
  ------------------
  |  Branch (266:12): [True: 16, False: 8]
  ------------------
  267|     16|    {
  268|     16|        size_t bufferSize = zip_file->m_Size - readCount;
  269|     16|        if (bufferSize > UINT16_MAX) {
  ------------------
  |  Branch (269:13): [True: 8, False: 8]
  ------------------
  270|      8|            bufferSize = UINT16_MAX;
  271|      8|        }
  272|       |
  273|     16|        int ret = unzReadCurrentFile(zip_handle, unzipBuffer.get(), static_cast<unsigned int>(bufferSize));
  274|     16|        if (ret != static_cast<int>(bufferSize))
  ------------------
  |  Branch (274:13): [True: 0, False: 16]
  ------------------
  275|      0|        {
  276|       |            // Failed, release the memory
  277|      0|            delete zip_file;
  278|      0|            zip_file = nullptr;
  279|      0|            break;
  280|      0|        }
  281|       |
  282|     16|        std::memcpy(zip_file->m_Buffer.get() + readCount, unzipBuffer.get(), ret);
  283|     16|        readCount += ret;
  284|     16|    }
  285|       |
  286|      8|    ai_assert(unzCloseCurrentFile(zip_handle) == UNZ_OK);
  ------------------
  |  |   67|      8|#   define ai_assert(expression) (void)((!!(expression)) || (Assimp::aiAssertViolation(#expression, __FILE__, __LINE__), 0))
  |  |  ------------------
  |  |  |  Branch (67:41): [True: 8, False: 0]
  |  |  |  Branch (67:61): [True: 0, False: 0]
  |  |  ------------------
  ------------------
  287|      8|    return zip_file;
  288|      9|}
_ZN6Assimp7ZipFileC2ERNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEm:
  292|      8|        m_Filename(filename), m_Size(size) {
  293|      8|    ai_assert(m_Size != 0);
  ------------------
  |  |   67|      8|#   define ai_assert(expression) (void)((!!(expression)) || (Assimp::aiAssertViolation(#expression, __FILE__, __LINE__), 0))
  |  |  ------------------
  |  |  |  Branch (67:41): [True: 8, False: 0]
  |  |  |  Branch (67:61): [True: 0, False: 0]
  |  |  ------------------
  ------------------
  294|      8|    m_Buffer = std::unique_ptr<uint8_t[]>(new uint8_t[m_Size]);
  295|      8|}
_ZN6Assimp7ZipFile4ReadEPvmm:
  298|      8|size_t ZipFile::Read(void *pvBuffer, size_t pSize, size_t pCount) {
  299|       |    // Should be impossible
  300|      8|    ai_assert(m_Buffer != nullptr);
  ------------------
  |  |   67|      8|#   define ai_assert(expression) (void)((!!(expression)) || (Assimp::aiAssertViolation(#expression, __FILE__, __LINE__), 0))
  |  |  ------------------
  |  |  |  Branch (67:41): [True: 8, False: 0]
  |  |  |  Branch (67:61): [True: 0, False: 0]
  |  |  ------------------
  ------------------
  301|      8|    ai_assert(nullptr != pvBuffer);
  ------------------
  |  |   67|      8|#   define ai_assert(expression) (void)((!!(expression)) || (Assimp::aiAssertViolation(#expression, __FILE__, __LINE__), 0))
  |  |  ------------------
  |  |  |  Branch (67:41): [True: 8, False: 0]
  |  |  |  Branch (67:61): [True: 0, False: 0]
  |  |  ------------------
  ------------------
  302|      8|    ai_assert(0 != pSize);
  ------------------
  |  |   67|      8|#   define ai_assert(expression) (void)((!!(expression)) || (Assimp::aiAssertViolation(#expression, __FILE__, __LINE__), 0))
  |  |  ------------------
  |  |  |  Branch (67:41): [True: 8, False: 0]
  |  |  |  Branch (67:61): [True: 0, False: 0]
  |  |  ------------------
  ------------------
  303|      8|    ai_assert(0 != pCount);
  ------------------
  |  |   67|      8|#   define ai_assert(expression) (void)((!!(expression)) || (Assimp::aiAssertViolation(#expression, __FILE__, __LINE__), 0))
  |  |  ------------------
  |  |  |  Branch (67:41): [True: 8, False: 0]
  |  |  |  Branch (67:61): [True: 0, False: 0]
  |  |  ------------------
  ------------------
  304|       |
  305|       |    // Clip down to file size
  306|      8|    size_t byteSize = pSize * pCount;
  307|      8|    if ((byteSize + m_SeekPtr) > m_Size) {
  ------------------
  |  Branch (307:9): [True: 0, False: 8]
  ------------------
  308|      0|        pCount = (m_Size - m_SeekPtr) / pSize;
  309|      0|        byteSize = pSize * pCount;
  310|      0|        if (byteSize == 0) {
  ------------------
  |  Branch (310:13): [True: 0, False: 0]
  ------------------
  311|      0|            return 0;
  312|      0|        }
  313|      0|    }
  314|       |
  315|      8|    std::memcpy(pvBuffer, m_Buffer.get() + m_SeekPtr, byteSize);
  316|       |
  317|      8|    m_SeekPtr += byteSize;
  318|       |
  319|      8|    return pCount;
  320|      8|}
_ZNK6Assimp7ZipFile8FileSizeEv:
  323|     10|size_t ZipFile::FileSize() const {
  324|     10|    return m_Size;
  325|     10|}
_ZN6Assimp18ZipArchiveIOSystem9ImplementC2EPNS_8IOSystemEPKcS5_:
  386|    401|ZipArchiveIOSystem::Implement::Implement(IOSystem *pIOHandler, const char *pFilename, const char *pMode) {
  387|    401|    ai_assert(strcmp(pMode, "r") == 0);
  ------------------
  |  |   67|    401|#   define ai_assert(expression) (void)((!!(expression)) || (Assimp::aiAssertViolation(#expression, __FILE__, __LINE__), 0))
  |  |  ------------------
  |  |  |  Branch (67:41): [True: 401, False: 0]
  |  |  |  Branch (67:61): [True: 0, False: 0]
  |  |  ------------------
  ------------------
  388|    401|    ai_assert(pFilename != nullptr);
  ------------------
  |  |   67|    401|#   define ai_assert(expression) (void)((!!(expression)) || (Assimp::aiAssertViolation(#expression, __FILE__, __LINE__), 0))
  |  |  ------------------
  |  |  |  Branch (67:41): [True: 401, False: 0]
  |  |  |  Branch (67:61): [True: 0, False: 0]
  |  |  ------------------
  ------------------
  389|    401|    if (pFilename[0] == 0 || nullptr == pMode) {
  ------------------
  |  Branch (389:9): [True: 0, False: 401]
  |  Branch (389:30): [True: 0, False: 401]
  ------------------
  390|      0|        return;
  391|      0|    }
  392|       |
  393|    401|    zlib_filefunc_def mapping = IOSystem2Unzip::get(pIOHandler);
  394|    401|    m_ZipFileHandle = unzOpen2(pFilename, &mapping);
  395|    401|}
_ZN6Assimp18ZipArchiveIOSystem9ImplementD2Ev:
  398|    401|ZipArchiveIOSystem::Implement::~Implement() {
  399|    401|    if (m_ZipFileHandle != nullptr) {
  ------------------
  |  Branch (399:9): [True: 27, False: 374]
  ------------------
  400|     27|        unzClose(m_ZipFileHandle);
  401|     27|    }
  402|    401|}
_ZN6Assimp18ZipArchiveIOSystem9Implement10MapArchiveEv:
  405|     34|void ZipArchiveIOSystem::Implement::MapArchive() {
  406|     34|    if (m_ZipFileHandle == nullptr)
  ------------------
  |  Branch (406:9): [True: 0, False: 34]
  ------------------
  407|      0|        return;
  408|       |
  409|     34|    if (!m_ArchiveMap.empty())
  ------------------
  |  Branch (409:9): [True: 14, False: 20]
  ------------------
  410|     14|        return;
  411|       |
  412|       |    //  At first ensure file is already open
  413|     20|    if (unzGoToFirstFile(m_ZipFileHandle) != UNZ_OK)
  ------------------
  |  |   74|     20|#define UNZ_OK                          (0)
  ------------------
  |  Branch (413:9): [True: 0, False: 20]
  ------------------
  414|      0|        return;
  415|       |
  416|       |    // Loop over all files
  417|    314|    do {
  418|    314|        char filename[FileNameSize];
  419|    314|        unz_file_info fileInfo;
  420|       |
  421|    314|        if (unzGetCurrentFileInfo(m_ZipFileHandle, &fileInfo, filename, FileNameSize, nullptr, 0, nullptr, 0) == UNZ_OK) {
  ------------------
  |  |   74|    314|#define UNZ_OK                          (0)
  ------------------
  |  Branch (421:13): [True: 312, False: 2]
  ------------------
  422|    312|            if (fileInfo.uncompressed_size != 0 && fileInfo.size_filename <= FileNameSize) {
  ------------------
  |  Branch (422:17): [True: 312, False: 0]
  |  Branch (422:52): [True: 312, False: 0]
  ------------------
  423|    312|                std::string filename_string(filename, fileInfo.size_filename);
  424|    312|                SimplifyFilename(filename_string);
  425|    312|                m_ArchiveMap.emplace(filename_string, ZipFileInfo(m_ZipFileHandle, fileInfo.uncompressed_size));
  426|    312|            }
  427|    312|        }
  428|    314|    } while (unzGoToNextFile(m_ZipFileHandle) != UNZ_END_OF_LIST_OF_FILE);
  ------------------
  |  |   75|    314|#define UNZ_END_OF_LIST_OF_FILE         (-100)
  ------------------
  |  Branch (428:14): [True: 294, False: 20]
  ------------------
  429|     20|}
_ZNK6Assimp18ZipArchiveIOSystem9Implement6isOpenEv:
  432|    410|bool ZipArchiveIOSystem::Implement::isOpen() const {
  433|    410|    return (m_ZipFileHandle != nullptr);
  434|    410|}
_ZN6Assimp18ZipArchiveIOSystem9Implement20getFileListExtensionERNSt3__16vectorINS2_12basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEENS7_IS9_EEEERKS9_:
  447|      9|void ZipArchiveIOSystem::Implement::getFileListExtension(std::vector<std::string> &rFileList, const std::string &extension) {
  448|      9|    MapArchive();
  449|      9|    rFileList.clear();
  450|       |
  451|    150|    for (const auto &file : m_ArchiveMap) {
  ------------------
  |  Branch (451:27): [True: 150, False: 9]
  ------------------
  452|    150|        if (extension == BaseImporter::GetExtension(file.first))
  ------------------
  |  Branch (452:13): [True: 2, False: 148]
  ------------------
  453|      2|            rFileList.push_back(file.first);
  454|    150|    }
  455|      9|}
_ZN6Assimp18ZipArchiveIOSystem9Implement6ExistsERNSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEE:
  458|      7|bool ZipArchiveIOSystem::Implement::Exists(std::string &filename) {
  459|      7|    MapArchive();
  460|       |
  461|      7|    ZipFileInfoMap::const_iterator it = m_ArchiveMap.find(filename);
  462|      7|    return (it != m_ArchiveMap.end());
  463|      7|}
_ZN6Assimp18ZipArchiveIOSystem9Implement8OpenFileERNSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEE:
  466|     18|IOStream *ZipArchiveIOSystem::Implement::OpenFile(std::string &filename) {
  467|     18|    MapArchive();
  468|       |
  469|     18|    SimplifyFilename(filename);
  470|       |
  471|       |    // Find in the map
  472|     18|    ZipFileInfoMap::const_iterator zip_it = m_ArchiveMap.find(filename);
  473|     18|    if (zip_it == m_ArchiveMap.cend())
  ------------------
  |  Branch (473:9): [True: 9, False: 9]
  ------------------
  474|      9|        return nullptr;
  475|       |
  476|      9|    const ZipFileInfo &zip_file = (*zip_it).second;
  477|      9|    return zip_file.Extract(filename, m_ZipFileHandle);
  478|     18|}
_ZN6Assimp18ZipArchiveIOSystem9Implement16SimplifyFilenameERNSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEE:
  499|    330|void ZipArchiveIOSystem::Implement::SimplifyFilename(std::string &filename) {
  500|    330|    ReplaceAllChar(filename, '\\', '/');
  501|       |
  502|       |    // Remove all . and / from the beginning of the path
  503|    330|    size_t pos = filename.find_first_not_of("./");
  504|    330|    if (pos != 0)
  ------------------
  |  Branch (504:9): [True: 4, False: 326]
  ------------------
  505|      4|        filename.erase(0, pos);
  506|       |
  507|       |    // Simplify "my/folder/../file.png" constructions, if any
  508|    330|    static const std::string relative("/../");
  509|    330|    const size_t relsize = relative.size() - 1;
  510|    330|    pos = filename.find(relative);
  511|    330|    while (pos != std::string::npos) {
  ------------------
  |  Branch (511:12): [True: 0, False: 330]
  ------------------
  512|       |        // Previous slash
  513|      0|        size_t prevpos = filename.rfind('/', pos - 1);
  514|      0|        if (prevpos == pos)
  ------------------
  |  Branch (514:13): [True: 0, False: 0]
  ------------------
  515|      0|            filename.erase(0, pos + relative.size());
  516|      0|        else
  517|      0|            filename.erase(prevpos, pos + relsize - prevpos);
  518|       |
  519|      0|        pos = filename.find(relative);
  520|      0|    }
  521|    330|}
_ZN6Assimp18ZipArchiveIOSystemC2EPNS_8IOSystemERKNSt3__112basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEEPKc:
  531|    358|        pImpl(new Implement(pIOHandler, rFilename.c_str(), pMode)) {
  532|    358|}
_ZN6Assimp18ZipArchiveIOSystemD2Ev:
  535|    358|ZipArchiveIOSystem::~ZipArchiveIOSystem() {
  536|    358|    delete pImpl;
  537|    358|}
_ZNK6Assimp18ZipArchiveIOSystem6ExistsEPKc:
  540|      7|bool ZipArchiveIOSystem::Exists(const char *pFilename) const {
  541|      7|    ai_assert(pFilename != nullptr);
  ------------------
  |  |   67|      7|#   define ai_assert(expression) (void)((!!(expression)) || (Assimp::aiAssertViolation(#expression, __FILE__, __LINE__), 0))
  |  |  ------------------
  |  |  |  Branch (67:41): [True: 7, False: 0]
  |  |  |  Branch (67:61): [True: 0, False: 0]
  |  |  ------------------
  ------------------
  542|       |
  543|      7|    if (pFilename == nullptr) {
  ------------------
  |  Branch (543:9): [True: 0, False: 7]
  ------------------
  544|      0|        return false;
  545|      0|    }
  546|       |
  547|      7|    std::string filename(pFilename);
  548|      7|    return pImpl->Exists(filename);
  549|      7|}
_ZN6Assimp18ZipArchiveIOSystem4OpenEPKcS2_:
  559|     18|IOStream *ZipArchiveIOSystem::Open(const char *pFilename, const char *pMode) {
  560|     18|    ai_assert(pFilename != nullptr);
  ------------------
  |  |   67|     18|#   define ai_assert(expression) (void)((!!(expression)) || (Assimp::aiAssertViolation(#expression, __FILE__, __LINE__), 0))
  |  |  ------------------
  |  |  |  Branch (67:41): [True: 18, False: 0]
  |  |  |  Branch (67:61): [True: 0, False: 0]
  |  |  ------------------
  ------------------
  561|       |
  562|     54|    for (size_t i = 0; pMode[i] != 0; ++i) {
  ------------------
  |  Branch (562:24): [True: 36, False: 18]
  ------------------
  563|     36|        ai_assert(pMode[i] != 'w');
  ------------------
  |  |   67|     36|#   define ai_assert(expression) (void)((!!(expression)) || (Assimp::aiAssertViolation(#expression, __FILE__, __LINE__), 0))
  |  |  ------------------
  |  |  |  Branch (67:41): [True: 36, False: 0]
  |  |  |  Branch (67:61): [True: 0, False: 0]
  |  |  ------------------
  ------------------
  564|     36|        if (pMode[i] == 'w')
  ------------------
  |  Branch (564:13): [True: 0, False: 36]
  ------------------
  565|      0|            return nullptr;
  566|     36|    }
  567|       |
  568|     18|    std::string filename(pFilename);
  569|     18|    return pImpl->OpenFile(filename);
  570|     18|}
_ZNK6Assimp18ZipArchiveIOSystem6isOpenEv:
  578|    367|bool ZipArchiveIOSystem::isOpen() const {
  579|    367|    return (pImpl->isOpen());
  580|    367|}
_ZNK6Assimp18ZipArchiveIOSystem20getFileListExtensionERNSt3__16vectorINS1_12basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEENS6_IS8_EEEERKS8_:
  588|      9|void ZipArchiveIOSystem::getFileListExtension(std::vector<std::string> &rFileList, const std::string &extension) const {
  589|      9|    return pImpl->getFileListExtension(rFileList, extension);
  590|      9|}
_ZN6Assimp18ZipArchiveIOSystem12isZipArchiveEPNS_8IOSystemEPKc:
  593|     43|bool ZipArchiveIOSystem::isZipArchive(IOSystem *pIOHandler, const char *pFilename) {
  594|     43|    Implement tmp(pIOHandler, pFilename, "r");
  595|     43|    return tmp.isOpen();
  596|     43|}
_ZN6Assimp18ZipArchiveIOSystem12isZipArchiveEPNS_8IOSystemERKNSt3__112basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEE:
  598|     43|bool ZipArchiveIOSystem::isZipArchive(IOSystem *pIOHandler, const std::string &rFilename) {
  599|     43|    return isZipArchive(pIOHandler, rFilename.c_str());
  600|     43|}
_ZN6Assimp7ZipFileD2Ev:
   71|      8|    ~ZipFile() override = default;
_ZN6Assimp14ReplaceAllCharERNSt3__112basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEEcc:
  490|    330|inline void ReplaceAllChar(std::string &data, const char before, const char after) {
  491|    330|    size_t pos = data.find(before);
  492|    330|    while (pos != std::string::npos) {
  ------------------
  |  Branch (492:12): [True: 0, False: 330]
  ------------------
  493|      0|        data[pos] = after;
  494|      0|        pos = data.find(before, pos + 1);
  495|      0|    }
  496|    330|}

aiTextureTypeToString:
   49|  36.3k|const char *aiTextureTypeToString(aiTextureType in) {
   50|  36.3k|    switch (in) {
   51|      0|    case aiTextureType_NONE:
  ------------------
  |  Branch (51:5): [True: 0, False: 36.3k]
  ------------------
   52|      0|        return "n/a";
   53|  2.14k|    case aiTextureType_DIFFUSE:
  ------------------
  |  Branch (53:5): [True: 2.14k, False: 34.2k]
  ------------------
   54|  2.14k|        return "Diffuse";
   55|  2.14k|    case aiTextureType_SPECULAR:
  ------------------
  |  Branch (55:5): [True: 2.14k, False: 34.2k]
  ------------------
   56|  2.14k|        return "Specular";
   57|  2.14k|    case aiTextureType_AMBIENT:
  ------------------
  |  Branch (57:5): [True: 2.14k, False: 34.2k]
  ------------------
   58|  2.14k|        return "Ambient";
   59|  2.14k|    case aiTextureType_EMISSIVE:
  ------------------
  |  Branch (59:5): [True: 2.14k, False: 34.2k]
  ------------------
   60|  2.14k|        return "Emissive";
   61|  2.14k|    case aiTextureType_OPACITY:
  ------------------
  |  Branch (61:5): [True: 2.14k, False: 34.2k]
  ------------------
   62|  2.14k|        return "Opacity";
   63|  2.14k|    case aiTextureType_NORMALS:
  ------------------
  |  Branch (63:5): [True: 2.14k, False: 34.2k]
  ------------------
   64|  2.14k|        return "Normals";
   65|  2.14k|    case aiTextureType_HEIGHT:
  ------------------
  |  Branch (65:5): [True: 2.14k, False: 34.2k]
  ------------------
   66|  2.14k|        return "Height";
   67|  2.14k|    case aiTextureType_SHININESS:
  ------------------
  |  Branch (67:5): [True: 2.14k, False: 34.2k]
  ------------------
   68|  2.14k|        return "Shininess";
   69|  2.14k|    case aiTextureType_DISPLACEMENT:
  ------------------
  |  Branch (69:5): [True: 2.14k, False: 34.2k]
  ------------------
   70|  2.14k|        return "Displacement";
   71|  2.14k|    case aiTextureType_LIGHTMAP:
  ------------------
  |  Branch (71:5): [True: 2.14k, False: 34.2k]
  ------------------
   72|  2.14k|        return "Lightmap";
   73|  2.14k|    case aiTextureType_REFLECTION:
  ------------------
  |  Branch (73:5): [True: 2.14k, False: 34.2k]
  ------------------
   74|  2.14k|        return "Reflection";
   75|  2.14k|    case aiTextureType_BASE_COLOR:
  ------------------
  |  Branch (75:5): [True: 2.14k, False: 34.2k]
  ------------------
   76|  2.14k|        return "BaseColor";
   77|  2.14k|    case aiTextureType_NORMAL_CAMERA:
  ------------------
  |  Branch (77:5): [True: 2.14k, False: 34.2k]
  ------------------
   78|  2.14k|        return "NormalCamera";
   79|  2.14k|    case aiTextureType_EMISSION_COLOR:
  ------------------
  |  Branch (79:5): [True: 2.14k, False: 34.2k]
  ------------------
   80|  2.14k|        return "EmissionColor";
   81|  2.14k|    case aiTextureType_METALNESS:
  ------------------
  |  Branch (81:5): [True: 2.14k, False: 34.2k]
  ------------------
   82|  2.14k|        return "Metalness";
   83|  2.14k|    case aiTextureType_DIFFUSE_ROUGHNESS:
  ------------------
  |  Branch (83:5): [True: 2.14k, False: 34.2k]
  ------------------
   84|  2.14k|        return "DiffuseRoughness";
   85|  2.14k|    case aiTextureType_AMBIENT_OCCLUSION:
  ------------------
  |  Branch (85:5): [True: 2.14k, False: 34.2k]
  ------------------
   86|  2.14k|        return "AmbientOcclusion";
   87|      0|    case aiTextureType_SHEEN:
  ------------------
  |  Branch (87:5): [True: 0, False: 36.3k]
  ------------------
   88|      0|        return "Sheen";
   89|      0|    case aiTextureType_CLEARCOAT:
  ------------------
  |  Branch (89:5): [True: 0, False: 36.3k]
  ------------------
   90|      0|        return "Clearcoat";
   91|      0|    case aiTextureType_TRANSMISSION:
  ------------------
  |  Branch (91:5): [True: 0, False: 36.3k]
  ------------------
   92|      0|        return "Transmission";
   93|      0|    case aiTextureType_MAYA_BASE:
  ------------------
  |  Branch (93:5): [True: 0, False: 36.3k]
  ------------------
   94|      0|        return "MayaBase";
   95|      0|    case aiTextureType_MAYA_SPECULAR:
  ------------------
  |  Branch (95:5): [True: 0, False: 36.3k]
  ------------------
   96|      0|        return "MayaSpecular";
   97|      0|    case aiTextureType_MAYA_SPECULAR_COLOR:
  ------------------
  |  Branch (97:5): [True: 0, False: 36.3k]
  ------------------
   98|      0|        return "MayaSpecularColor";
   99|      0|    case aiTextureType_MAYA_SPECULAR_ROUGHNESS:
  ------------------
  |  Branch (99:5): [True: 0, False: 36.3k]
  ------------------
  100|      0|        return "MayaSpecularRoughness";
  101|      0|    case aiTextureType_ANISOTROPY:
  ------------------
  |  Branch (101:5): [True: 0, False: 36.3k]
  ------------------
  102|      0|        return "Anisotropy";
  103|      0|    case aiTextureType_GLTF_METALLIC_ROUGHNESS:
  ------------------
  |  Branch (103:5): [True: 0, False: 36.3k]
  ------------------
  104|      0|        return "glTFMetallicRoughness";
  105|      0|    case aiTextureType_UNKNOWN:
  ------------------
  |  Branch (105:5): [True: 0, False: 36.3k]
  ------------------
  106|      0|        return "Unknown";
  107|      0|    default:
  ------------------
  |  Branch (107:5): [True: 0, False: 36.3k]
  ------------------
  108|      0|        break;
  109|  36.3k|    }
  110|      0|    ai_assert(false);
  ------------------
  |  |   67|      0|#   define ai_assert(expression) (void)((!!(expression)) || (Assimp::aiAssertViolation(#expression, __FILE__, __LINE__), 0))
  |  |  ------------------
  |  |  |  Branch (67:41): [Folded, False: 0]
  |  |  |  Branch (67:61): [True: 0, False: 0]
  |  |  ------------------
  ------------------
  111|      0|    return "BUG";
  112|  36.3k|}

_ZN7aiSceneC2Ev:
   46|    890|        mFlags(0),
   47|    890|        mRootNode(nullptr),
   48|    890|        mNumMeshes(0),
   49|    890|        mMeshes(nullptr),
   50|    890|        mNumMaterials(0),
   51|    890|        mMaterials(nullptr),
   52|    890|        mNumAnimations(0),
   53|    890|        mAnimations(nullptr),
   54|    890|        mNumTextures(0),
   55|    890|        mTextures(nullptr),
   56|    890|        mNumLights(0),
   57|    890|        mLights(nullptr),
   58|    890|        mNumCameras(0),
   59|    890|        mCameras(nullptr),
   60|    890|        mMetaData(nullptr),
   61|    890|        mName(),
   62|    890|        mNumSkeletons(0),
   63|    890|        mSkeletons(nullptr),
   64|    890|        mPrivate(new Assimp::ScenePrivateData()) {
   65|       |    // empty
   66|    890|}
_ZN7aiSceneD2Ev:
   68|    890|aiScene::~aiScene() {
   69|       |    // delete all sub-objects recursively
   70|    890|    delete mRootNode;
   71|       |
   72|       |    // To make sure we won't crash if the data is invalid it's
   73|       |    // much better to check whether both mNumXXX and mXXX are
   74|       |    // valid instead of relying on just one of them.
   75|    890|    if (mNumMeshes && mMeshes) {
  ------------------
  |  Branch (75:9): [True: 385, False: 505]
  |  Branch (75:23): [True: 374, False: 11]
  ------------------
   76|  7.69k|        for (unsigned int a = 0; a < mNumMeshes; ++a) {
  ------------------
  |  Branch (76:34): [True: 7.32k, False: 374]
  ------------------
   77|  7.32k|            delete mMeshes[a];
   78|  7.32k|        }
   79|    374|    }
   80|    890|    delete[] mMeshes;
   81|       |
   82|    890|    if (mNumMaterials && mMaterials) {
  ------------------
  |  Branch (82:9): [True: 389, False: 501]
  |  Branch (82:26): [True: 379, False: 10]
  ------------------
   83|    953|        for (unsigned int a = 0; a < mNumMaterials; ++a) {
  ------------------
  |  Branch (83:34): [True: 574, False: 379]
  ------------------
   84|    574|            delete mMaterials[a];
   85|    574|        }
   86|    379|    }
   87|    890|    delete[] mMaterials;
   88|       |
   89|    890|    if (mNumAnimations && mAnimations) {
  ------------------
  |  Branch (89:9): [True: 76, False: 814]
  |  Branch (89:27): [True: 70, False: 6]
  ------------------
   90|  16.7M|        for (unsigned int a = 0; a < mNumAnimations; ++a) {
  ------------------
  |  Branch (90:34): [True: 16.7M, False: 70]
  ------------------
   91|  16.7M|            delete mAnimations[a];
   92|  16.7M|        }
   93|     70|    }
   94|    890|    delete[] mAnimations;
   95|       |
   96|    890|    if (mNumTextures && mTextures) {
  ------------------
  |  Branch (96:9): [True: 15, False: 875]
  |  Branch (96:25): [True: 15, False: 0]
  ------------------
   97|     30|        for (unsigned int a = 0; a < mNumTextures; ++a) {
  ------------------
  |  Branch (97:34): [True: 15, False: 15]
  ------------------
   98|     15|            delete mTextures[a];
   99|     15|        }
  100|     15|    }
  101|    890|    delete[] mTextures;
  102|       |
  103|    890|    if (mNumLights && mLights) {
  ------------------
  |  Branch (103:9): [True: 90, False: 800]
  |  Branch (103:23): [True: 89, False: 1]
  ------------------
  104|    221|        for (unsigned int a = 0; a < mNumLights; ++a) {
  ------------------
  |  Branch (104:34): [True: 132, False: 89]
  ------------------
  105|    132|            delete mLights[a];
  106|    132|        }
  107|     89|    }
  108|    890|    delete[] mLights;
  109|       |
  110|    890|    if (mNumCameras && mCameras) {
  ------------------
  |  Branch (110:9): [True: 90, False: 800]
  |  Branch (110:24): [True: 90, False: 0]
  ------------------
  111|    206|        for (unsigned int a = 0; a < mNumCameras; ++a) {
  ------------------
  |  Branch (111:34): [True: 116, False: 90]
  ------------------
  112|    116|            delete mCameras[a];
  113|    116|        }
  114|     90|    }
  115|    890|    delete[] mCameras;
  116|       |
  117|    890|    aiMetadata::Dealloc(mMetaData);
  118|       |
  119|    890|    delete[] mSkeletons;
  120|       |
  121|    890|    delete static_cast<Assimp::ScenePrivateData *>(mPrivate);
  122|    890|}
_ZN6aiNodeC2Ev:
  125|   103k|        mName(""),
  126|   103k|        mParent(nullptr),
  127|   103k|        mNumChildren(0),
  128|   103k|        mChildren(nullptr),
  129|   103k|        mNumMeshes(0),
  130|   103k|        mMeshes(nullptr),
  131|   103k|        mMetaData(nullptr) {
  132|       |    // empty
  133|   103k|}
_ZN6aiNodeC2ERKNSt3__112basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEE:
  136|    251|        mName(name),
  137|    251|        mParent(nullptr),
  138|    251|        mNumChildren(0),
  139|    251|        mChildren(nullptr),
  140|    251|        mNumMeshes(0),
  141|    251|        mMeshes(nullptr),
  142|    251|        mMetaData(nullptr) {
  143|       |    // empty
  144|    251|}
_ZN6aiNodeD2Ev:
  147|   104k|aiNode::~aiNode() {
  148|       |    // delete all children recursively
  149|       |    // to make sure we won't crash if the data is invalid ...
  150|   104k|    if (mNumChildren && mChildren) {
  ------------------
  |  Branch (150:9): [True: 33.5k, False: 70.6k]
  |  Branch (150:25): [True: 33.5k, False: 0]
  ------------------
  151|   137k|        for (unsigned int a = 0; a < mNumChildren; a++)
  ------------------
  |  Branch (151:34): [True: 103k, False: 33.5k]
  ------------------
  152|   103k|            delete mChildren[a];
  153|  33.5k|    }
  154|   104k|    delete[] mChildren;
  155|   104k|    delete[] mMeshes;
  156|   104k|    delete mMetaData;
  157|   104k|}
_ZN6aiNode8FindNodeEPKc:
  176|  2.16M|aiNode *aiNode::FindNode(const char *name) {
  177|  2.16M|    if (!::strcmp(mName.data, name)) return this;
  ------------------
  |  Branch (177:9): [True: 4.67k, False: 2.16M]
  ------------------
  178|  4.31M|    for (unsigned int i = 0; i < mNumChildren; ++i) {
  ------------------
  |  Branch (178:30): [True: 2.16M, False: 2.14M]
  ------------------
  179|  2.16M|        aiNode *const p = mChildren[i]->FindNode(name);
  180|  2.16M|        if (p) {
  ------------------
  |  Branch (180:13): [True: 15.5k, False: 2.14M]
  ------------------
  181|  15.5k|            return p;
  182|  15.5k|        }
  183|  2.16M|    }
  184|       |    // there is definitely no sub-node with this name
  185|  2.14M|    return nullptr;
  186|  2.16M|}
_ZN6aiNode11addChildrenEjPPS_:
  188|      3|void aiNode::addChildren(unsigned int numChildren, aiNode **children) {
  189|      3|    if (nullptr == children || 0 == numChildren) {
  ------------------
  |  Branch (189:9): [True: 0, False: 3]
  |  Branch (189:32): [True: 0, False: 3]
  ------------------
  190|      0|        return;
  191|      0|    }
  192|       |
  193|     20|    for (unsigned int i = 0; i < numChildren; i++) {
  ------------------
  |  Branch (193:30): [True: 17, False: 3]
  ------------------
  194|     17|        aiNode *child = children[i];
  195|     17|        if (nullptr != child) {
  ------------------
  |  Branch (195:13): [True: 17, False: 0]
  ------------------
  196|     17|            child->mParent = this;
  197|     17|        }
  198|     17|    }
  199|       |
  200|      3|    if (mNumChildren > 0) {
  ------------------
  |  Branch (200:9): [True: 0, False: 3]
  ------------------
  201|      0|        aiNode **tmp = new aiNode *[mNumChildren];
  202|      0|        ::memcpy(tmp, mChildren, sizeof(aiNode *) * mNumChildren);
  203|      0|        delete[] mChildren;
  204|      0|        mChildren = new aiNode *[mNumChildren + numChildren];
  205|      0|        ::memcpy(mChildren, tmp, sizeof(aiNode *) * mNumChildren);
  206|      0|        ::memcpy(&mChildren[mNumChildren], children, sizeof(aiNode *) * numChildren);
  207|      0|        mNumChildren += numChildren;
  208|      0|        delete[] tmp;
  209|      3|    } else {
  210|      3|        mChildren = new aiNode *[numChildren];
  211|     20|        for (unsigned int i = 0; i < numChildren; i++) {
  ------------------
  |  Branch (211:34): [True: 17, False: 3]
  ------------------
  212|     17|            mChildren[i] = children[i];
  213|     17|        }
  214|      3|        mNumChildren = numChildren;
  215|      3|    }
  216|      3|}

_ZN6Assimp13GeometryUtils5heronEfff:
   49|  4.15M|ai_real GeometryUtils::heron( ai_real a, ai_real b, ai_real c ) {
   50|  4.15M|    const ai_real s    = (a + b + c) * 0.5;
   51|  4.15M|    const ai_real area = pow((s * ( s - a ) * ( s - b ) * ( s - c ) ), static_cast<ai_real>(0.5));
   52|  4.15M|    return area;
   53|  4.15M|}
_ZN6Assimp13GeometryUtils10distance3DERK10aiVector3tIfES4_:
   56|  12.4M|ai_real GeometryUtils::distance3D( const aiVector3D &vA, const aiVector3D &vB ) {
   57|  12.4M|    const ai_real lx = ( vB.x - vA.x );
   58|  12.4M|    const ai_real ly = ( vB.y - vA.y );
   59|  12.4M|    const ai_real lz = ( vB.z - vA.z );
   60|  12.4M|    const ai_real a  = lx*lx + ly*ly + lz*lz;
   61|  12.4M|    const ai_real d  = pow( a, static_cast<ai_real>(0.5));
   62|       |
   63|  12.4M|    return d;
   64|  12.4M|}
_ZN6Assimp13GeometryUtils23calculateAreaOfTriangleERK6aiFaceP6aiMesh:
   67|  4.15M|ai_real GeometryUtils::calculateAreaOfTriangle( const aiFace& face, aiMesh* mesh ) {
   68|  4.15M|    ai_real area = 0;
   69|  4.15M|    if (mesh == nullptr) {
  ------------------
  |  Branch (69:9): [True: 0, False: 4.15M]
  ------------------
   70|      0|        return area;
   71|      0|    }
   72|       |
   73|  4.15M|    const aiVector3D vA( mesh->mVertices[ face.mIndices[ 0 ] ] );
   74|  4.15M|    const aiVector3D vB( mesh->mVertices[ face.mIndices[ 1 ] ] );
   75|  4.15M|    const aiVector3D vC( mesh->mVertices[ face.mIndices[ 2 ] ] );
   76|       |
   77|  4.15M|    const ai_real a = distance3D( vA, vB );
   78|  4.15M|    const ai_real b = distance3D( vB, vC );
   79|  4.15M|    const ai_real c = distance3D( vC, vA );
   80|  4.15M|    area = heron( a, b, c );
   81|       |
   82|  4.15M|    return area;
   83|  4.15M|}
_ZN6Assimp13GeometryUtils20normalizeVectorArrayEP10aiVector3tIfES3_m:
   98|     10|void GeometryUtils::normalizeVectorArray(aiVector3D *vectorArrayIn, aiVector3D *vectorArrayOut, size_t numVectors) {
   99|     10|    if (vectorArrayIn == nullptr || vectorArrayOut == nullptr) {
  ------------------
  |  Branch (99:9): [True: 0, False: 10]
  |  Branch (99:37): [True: 0, False: 10]
  ------------------
  100|      0|        return;
  101|      0|    }
  102|       |	
  103|  2.40k|    for (size_t i=0; i<numVectors; ++i) {
  ------------------
  |  Branch (103:22): [True: 2.39k, False: 10]
  ------------------
  104|  2.39k|	vectorArrayOut[i] = vectorArrayIn[i].Normalize();
  105|  2.39k|    }
  106|     10|}

aiGetMaterialProperty:
   63|  10.8k|        const aiMaterialProperty **pPropOut) {
   64|  10.8k|    ai_assert(pMat != nullptr);
   65|  10.8k|    ai_assert(pKey != nullptr);
   66|  10.8k|    ai_assert(pPropOut != nullptr);
   67|       |
   68|       |    /*  Just search for a property with exactly this name ..
   69|       |     *  could be improved by hashing, but it's possibly
   70|       |     *  no worth the effort (we're bound to C structures,
   71|       |     *  thus std::map or derivates are not applicable. */
   72|  79.7k|    for (unsigned int i = 0; i < pMat->mNumProperties; ++i) {
  ------------------
  |  Branch (72:30): [True: 77.3k, False: 2.37k]
  ------------------
   73|  77.3k|        aiMaterialProperty *prop = pMat->mProperties[i];
   74|       |
   75|  77.3k|        if (prop /* just for safety ... */
  ------------------
  |  Branch (75:13): [True: 77.3k, False: 0]
  ------------------
   76|  77.3k|                && 0 == strncmp(prop->mKey.data, pKey, strlen(pKey)) && (UINT_MAX == type || prop->mSemantic == type) /* UINT_MAX is a wild-card, but this is undocumented :-) */
  ------------------
  |  Branch (76:20): [True: 8.74k, False: 68.5k]
  |  Branch (76:74): [True: 0, False: 8.74k]
  |  Branch (76:94): [True: 8.53k, False: 212]
  ------------------
   77|  8.53k|                && (UINT_MAX == index || prop->mIndex == index)) {
  ------------------
  |  Branch (77:21): [True: 0, False: 8.53k]
  |  Branch (77:42): [True: 8.47k, False: 62]
  ------------------
   78|  8.47k|            *pPropOut = pMat->mProperties[i];
   79|  8.47k|            return AI_SUCCESS;
   80|  8.47k|        }
   81|  77.3k|    }
   82|  2.37k|    *pPropOut = nullptr;
   83|       |
   84|       |    return AI_FAILURE;
   85|  10.8k|}
aiGetMaterialFloatArray:
  194|  3.83k|        unsigned int *pMax) {
  195|  3.83k|    return GetMaterialFloatArray(pMat, pKey, type, index, pOut, pMax);
  196|  3.83k|}
aiGetMaterialIntegerArray:
  205|  2.48k|        unsigned int *pMax) {
  206|  2.48k|    ai_assert(pOut != nullptr);
  207|  2.48k|    ai_assert(pMat != nullptr);
  208|       |
  209|  2.48k|    const aiMaterialProperty *prop;
  210|  2.48k|    aiGetMaterialProperty(pMat, pKey, type, index, &prop);
  211|  2.48k|    if (!prop) {
  ------------------
  |  Branch (211:9): [True: 407, False: 2.07k]
  ------------------
  212|    407|        return AI_FAILURE;
  213|    407|    }
  214|       |
  215|       |    // data is given in ints, simply copy it
  216|  2.07k|    unsigned int iWrite = 0;
  217|  2.07k|    if (aiPTI_Integer == prop->mType || aiPTI_Buffer == prop->mType) {
  ------------------
  |  Branch (217:9): [True: 2.07k, False: 1]
  |  Branch (217:41): [True: 1, False: 0]
  ------------------
  218|  2.07k|        iWrite = std::max(static_cast<unsigned int>(prop->mDataLength / sizeof(int32_t)), 1u);
  219|  2.07k|        if (pMax) {
  ------------------
  |  Branch (219:13): [True: 0, False: 2.07k]
  ------------------
  220|      0|            iWrite = std::min(*pMax, iWrite);
  221|      0|        }
  222|  2.07k|        if (1 == prop->mDataLength) {
  ------------------
  |  Branch (222:13): [True: 0, False: 2.07k]
  ------------------
  223|       |            // bool type, 1 byte
  224|      0|            *pOut = static_cast<int>(*prop->mData);
  225|  2.07k|        } else {
  226|  4.14k|            for (unsigned int a = 0; a < iWrite; ++a) {
  ------------------
  |  Branch (226:38): [True: 2.07k, False: 2.07k]
  ------------------
  227|  2.07k|                pOut[a] = static_cast<int>(reinterpret_cast<int32_t *>(prop->mData)[a]);
  228|  2.07k|            }
  229|  2.07k|        }
  230|  2.07k|        if (pMax) {
  ------------------
  |  Branch (230:13): [True: 0, False: 2.07k]
  ------------------
  231|      0|            *pMax = iWrite;
  232|      0|        }
  233|  2.07k|    }
  234|       |    // data is given in floats convert to int
  235|      0|    else if (aiPTI_Float == prop->mType) {
  ------------------
  |  Branch (235:14): [True: 0, False: 0]
  ------------------
  236|      0|        iWrite = prop->mDataLength / sizeof(float);
  237|      0|        if (pMax) {
  ------------------
  |  Branch (237:13): [True: 0, False: 0]
  ------------------
  238|      0|            iWrite = std::min(*pMax, iWrite);
  239|      0|            ;
  240|      0|        }
  241|      0|        for (unsigned int a = 0; a < iWrite; ++a) {
  ------------------
  |  Branch (241:34): [True: 0, False: 0]
  ------------------
  242|      0|            pOut[a] = static_cast<int>(reinterpret_cast<float *>(prop->mData)[a]);
  243|      0|        }
  244|      0|        if (pMax) {
  ------------------
  |  Branch (244:13): [True: 0, False: 0]
  ------------------
  245|      0|            *pMax = iWrite;
  246|      0|        }
  247|      0|    }
  248|       |    // it is a string ... no way to read something out of this
  249|      0|    else {
  250|      0|        if (pMax) {
  ------------------
  |  Branch (250:13): [True: 0, False: 0]
  ------------------
  251|      0|            iWrite = *pMax;
  252|      0|        }
  253|       |        // strings are zero-terminated with a 32 bit length prefix, so this is safe
  254|      0|        const char *cur = prop->mData + 4;
  255|      0|        ai_assert(prop->mDataLength >= 5);
  256|      0|        ai_assert(!prop->mData[prop->mDataLength - 1]);
  257|      0|        for (unsigned int a = 0;; ++a) {
  258|      0|            pOut[a] = strtol10(cur, &cur);
  259|      0|            if (a == iWrite - 1) {
  ------------------
  |  Branch (259:17): [True: 0, False: 0]
  ------------------
  260|      0|                break;
  261|      0|            }
  262|      0|            if (!IsSpace(*cur)) {
  ------------------
  |  Branch (262:17): [True: 0, False: 0]
  ------------------
  263|      0|                ASSIMP_LOG_ERROR("Material property", pKey,
  264|      0|                                 " is a string; failed to parse an integer array out of it.");
  265|      0|                return AI_FAILURE;
  266|      0|            }
  267|      0|        }
  268|       |
  269|      0|        if (pMax) {
  ------------------
  |  Branch (269:13): [True: 0, False: 0]
  ------------------
  270|      0|            *pMax = iWrite;
  271|      0|        }
  272|      0|    }
  273|  2.07k|    return AI_SUCCESS;
  274|  2.07k|}
aiGetMaterialColor:
  282|  2.24k|        aiColor4D *pOut) {
  283|  2.24k|    unsigned int iMax = 4;
  284|  2.24k|    const aiReturn eRet = aiGetMaterialFloatFloatArray(pMat, pKey, type, index, (float *)pOut, &iMax);
  285|       |
  286|       |    // if no alpha channel is defined: set it to 1.0
  287|  2.24k|    if (3 == iMax) {
  ------------------
  |  Branch (287:9): [True: 973, False: 1.27k]
  ------------------
  288|    973|        pOut->a = 1.0;
  289|    973|    }
  290|       |
  291|  2.24k|    return eRet;
  292|  2.24k|}
aiGetMaterialString:
  311|  2.28k|        aiString *pOut) {
  312|  2.28k|    ai_assert(pOut != nullptr);
  313|       |
  314|  2.28k|    const aiMaterialProperty *prop{nullptr};
  315|  2.28k|    aiGetMaterialProperty(pMat, pKey, type, index, &prop);
  316|  2.28k|    if (!prop) {
  ------------------
  |  Branch (316:9): [True: 36, False: 2.24k]
  ------------------
  317|     36|        return AI_FAILURE;
  318|     36|    }
  319|       |
  320|  2.24k|    if (aiPTI_String == prop->mType) {
  ------------------
  |  Branch (320:9): [True: 2.24k, False: 0]
  ------------------
  321|  2.24k|        ai_assert(prop->mDataLength >= 5);
  322|       |
  323|       |        // The string is stored as 32 but length prefix followed by zero-terminated UTF8 data
  324|  2.24k|        pOut->length = static_cast<unsigned int>(*reinterpret_cast<uint32_t *>(prop->mData));
  325|       |
  326|  2.24k|        ai_assert(pOut->length + 1 + 4 == prop->mDataLength);
  327|  2.24k|        ai_assert(!prop->mData[prop->mDataLength - 1]);
  328|  2.24k|        memcpy(pOut->data, prop->mData + 4, pOut->length + 1);
  329|  2.24k|    } else {
  330|       |        // TODO - implement lexical cast as well
  331|      0|        ASSIMP_LOG_ERROR("Material property", pKey, " was found, but is no string");
  332|      0|        return AI_FAILURE;
  333|      0|    }
  334|  2.24k|    return AI_SUCCESS;
  335|  2.24k|}
aiGetMaterialTextureCount:
  345|  16.7k|unsigned int aiGetMaterialTextureCount(const C_STRUCT aiMaterial *pMat, C_ENUM aiTextureType type) {
  346|  16.7k|    ai_assert(pMat != nullptr);
  347|       |
  348|       |    // Textures are always stored with ascending indices (ValidateDS provides a check, so we don't need to do it again)
  349|  16.7k|    unsigned int max = 0;
  350|   244k|    for (unsigned int i = 0; i < pMat->mNumProperties; ++i) {
  ------------------
  |  Branch (350:30): [True: 227k, False: 16.7k]
  ------------------
  351|   227k|        aiMaterialProperty *prop = pMat->mProperties[i];
  352|       |
  353|   227k|        if (prop /* just a sanity check ... */
  ------------------
  |  Branch (353:13): [True: 227k, False: 0]
  ------------------
  354|   227k|                && 0 == strcmp(prop->mKey.data, _AI_MATKEY_TEXTURE_BASE) && static_cast<aiTextureType>(prop->mSemantic) == type) {
  ------------------
  |  Branch (354:20): [True: 7.88k, False: 220k]
  |  Branch (354:77): [True: 464, False: 7.42k]
  ------------------
  355|       |
  356|    464|            max = std::max(max, prop->mIndex + 1);
  357|    464|        }
  358|   227k|    }
  359|  16.7k|    return max;
  360|  16.7k|}
aiGetMaterialTexture:
  373|    337|) {
  374|    337|    ai_assert(nullptr != mat);
  375|    337|    ai_assert(nullptr != path);
  376|       |
  377|       |    // Get the path to the texture
  378|    337|    if (AI_SUCCESS != aiGetMaterialString(mat, AI_MATKEY_TEXTURE(type, index), path)) {
  ------------------
  |  Branch (378:9): [True: 0, False: 337]
  ------------------
  379|      0|        return AI_FAILURE;
  380|      0|    }
  381|       |
  382|       |    // Determine mapping type
  383|    337|    int mapping_ = aiTextureMapping_UV;
  384|    337|    aiGetMaterialInteger(mat, AI_MATKEY_MAPPING(type, index), &mapping_);
  385|    337|    aiTextureMapping mapping = static_cast<aiTextureMapping>(mapping_);
  386|    337|    if (_mapping)
  ------------------
  |  Branch (386:9): [True: 0, False: 337]
  ------------------
  387|      0|        *_mapping = mapping;
  388|       |
  389|       |    // Get UV index
  390|    337|    if (aiTextureMapping_UV == mapping && uvindex) {
  ------------------
  |  Branch (390:9): [True: 337, False: 0]
  |  Branch (390:43): [True: 0, False: 337]
  ------------------
  391|      0|        aiGetMaterialInteger(mat, AI_MATKEY_UVWSRC(type, index), (int *)uvindex);
  392|      0|    }
  393|       |    // Get blend factor
  394|    337|    if (blend) {
  ------------------
  |  Branch (394:9): [True: 0, False: 337]
  ------------------
  395|      0|        aiGetMaterialFloat(mat, AI_MATKEY_TEXBLEND(type, index), blend);
  396|      0|    }
  397|       |    // Get texture operation
  398|    337|    if (op) {
  ------------------
  |  Branch (398:9): [True: 0, False: 337]
  ------------------
  399|      0|        aiGetMaterialInteger(mat, AI_MATKEY_TEXOP(type, index), (int *)op);
  400|      0|    }
  401|       |    // Get texture mapping modes
  402|    337|    if (mapmode) {
  ------------------
  |  Branch (402:9): [True: 0, False: 337]
  ------------------
  403|      0|        aiGetMaterialInteger(mat, AI_MATKEY_MAPPINGMODE_U(type, index), (int *)&mapmode[0]);
  404|      0|        aiGetMaterialInteger(mat, AI_MATKEY_MAPPINGMODE_V(type, index), (int *)&mapmode[1]);
  405|      0|    }
  406|       |    // Get texture flags
  407|    337|    if (flags) {
  ------------------
  |  Branch (407:9): [True: 0, False: 337]
  ------------------
  408|      0|        aiGetMaterialInteger(mat, AI_MATKEY_TEXFLAGS(type, index), (int *)flags);
  409|      0|    }
  410|       |
  411|       |    return AI_SUCCESS;
  412|    337|}
_ZN10aiMaterialC2Ev:
  418|  2.51k|aiMaterial::aiMaterial() : mProperties(nullptr), mNumProperties(0), mNumAllocated(DefaultNumAllocated) {
  419|       |    // Allocate 5 entries by default
  420|  2.51k|    mProperties = new aiMaterialProperty *[DefaultNumAllocated];
  421|  2.51k|}
_ZN10aiMaterialD2Ev:
  424|  2.46k|aiMaterial::~aiMaterial() {
  425|  2.46k|    Clear();
  426|       |
  427|  2.46k|    delete[] mProperties;
  428|  2.46k|}
_ZN10aiMaterial5ClearEv:
  439|  2.72k|void aiMaterial::Clear() {
  440|  24.9k|    for (unsigned int i = 0; i < mNumProperties; ++i) {
  ------------------
  |  Branch (440:30): [True: 22.1k, False: 2.72k]
  ------------------
  441|       |        // delete this entry
  442|  22.1k|        delete mProperties[i];
  443|  22.1k|        AI_DEBUG_INVALIDATE_PTR(mProperties[i]);
  444|  22.1k|    }
  445|  2.72k|    mNumProperties = 0;
  446|       |
  447|       |    // The array remains allocated, we just invalidated its contents
  448|  2.72k|}
_ZN10aiMaterial17AddBinaryPropertyEPKvjPKcjj18aiPropertyTypeInfo:
  480|  18.9k|        aiPropertyTypeInfo pType) {
  481|  18.9k|    ai_assert(pInput != nullptr);
  482|  18.9k|    ai_assert(pKey != nullptr);
  483|  18.9k|    ai_assert(0 != pSizeInBytes);
  484|       |
  485|  18.9k|    if (0 == pSizeInBytes) {
  ------------------
  |  Branch (485:9): [True: 0, False: 18.9k]
  ------------------
  486|      0|        return AI_FAILURE;
  487|      0|    }
  488|       |
  489|       |    // first search the list whether there is already an entry with this key
  490|  18.9k|    unsigned int iOutIndex(UINT_MAX);
  491|   118k|    for (unsigned int i = 0; i < mNumProperties; ++i) {
  ------------------
  |  Branch (491:30): [True: 99.6k, False: 18.9k]
  ------------------
  492|  99.6k|        aiMaterialProperty *prop(mProperties[i]);
  493|       |
  494|  99.6k|        if (prop /* just for safety */ && !strcmp(prop->mKey.data, pKey) &&
  ------------------
  |  Branch (494:13): [True: 99.6k, False: 0]
  |  Branch (494:43): [True: 1.28k, False: 98.3k]
  ------------------
  495|  1.28k|                prop->mSemantic == type && prop->mIndex == index) {
  ------------------
  |  Branch (495:17): [True: 729, False: 560]
  |  Branch (495:44): [True: 38, False: 691]
  ------------------
  496|       |
  497|     38|            delete mProperties[i];
  498|     38|            iOutIndex = i;
  499|     38|        }
  500|  99.6k|    }
  501|       |
  502|       |    // Allocate a new material property
  503|  18.9k|    auto pcNew = std::make_unique<aiMaterialProperty>();
  504|       |
  505|       |    // .. and fill it
  506|  18.9k|    pcNew->mType = pType;
  507|  18.9k|    pcNew->mSemantic = type;
  508|  18.9k|    pcNew->mIndex = index;
  509|       |
  510|  18.9k|    pcNew->mDataLength = pSizeInBytes;
  511|  18.9k|    pcNew->mData = new char[pSizeInBytes];
  512|  18.9k|    memcpy(pcNew->mData, pInput, pSizeInBytes);
  513|       |
  514|  18.9k|    pcNew->mKey.length = static_cast<ai_uint32>(::strlen(pKey));
  515|  18.9k|    ai_assert(AI_MAXLEN > pcNew->mKey.length);
  516|  18.9k|    strcpy(pcNew->mKey.data, pKey);
  517|       |
  518|  18.9k|    if (UINT_MAX != iOutIndex) {
  ------------------
  |  Branch (518:9): [True: 38, False: 18.9k]
  ------------------
  519|     38|        mProperties[iOutIndex] = pcNew.release();
  520|     38|        return AI_SUCCESS;
  521|     38|    }
  522|       |
  523|       |    // resize the array ... double the storage allocated
  524|  18.9k|    if (mNumProperties == mNumAllocated) {
  ------------------
  |  Branch (524:9): [True: 2.65k, False: 16.2k]
  ------------------
  525|  2.65k|        const unsigned int iOld = mNumAllocated;
  526|  2.65k|        mNumAllocated *= 2;
  527|       |
  528|  2.65k|        aiMaterialProperty **ppTemp;
  529|  2.65k|        try {
  530|  2.65k|            ppTemp = new aiMaterialProperty *[mNumAllocated];
  531|  2.65k|        } catch (std::bad_alloc &) {
  532|      0|            return AI_OUTOFMEMORY;
  533|      0|        }
  534|       |
  535|       |        // just copy all items over; then replace the old array
  536|  2.65k|        memcpy(ppTemp, mProperties, iOld * sizeof(void *));
  537|       |
  538|  2.65k|        delete[] mProperties;
  539|  2.65k|        mProperties = ppTemp;
  540|  2.65k|    }
  541|       |    // push back ...
  542|  18.9k|    mProperties[mNumProperties++] = pcNew.release();
  543|       |
  544|       |    return AI_SUCCESS;
  545|  18.9k|}
_ZN10aiMaterial11AddPropertyEPK8aiStringPKcjj:
  551|  2.50k|        unsigned int index) {
  552|       |    ai_assert(sizeof(ai_uint32) == 4);
  553|  2.50k|    return AddBinaryProperty(pInput,
  554|  2.50k|            static_cast<unsigned int>(pInput->length + 1 + 4),
  555|  2.50k|            pKey,
  556|  2.50k|            type,
  557|  2.50k|            index,
  558|  2.50k|            aiPTI_String);
  559|  2.50k|}
_ZN6Assimp19ComputeMaterialHashEPK10aiMaterialb:
  562|  1.95k|uint32_t Assimp::ComputeMaterialHash(const aiMaterial *mat, bool includeMatName /*= false*/) {
  563|  1.95k|    uint32_t hash = 1503; // magic start value, chosen to be my birthday :-)
  564|  17.6k|    for (unsigned int i = 0; i < mat->mNumProperties; ++i) {
  ------------------
  |  Branch (564:30): [True: 15.7k, False: 1.95k]
  ------------------
  565|       |        // Exclude all properties whose first character is '?' from the hash
  566|       |        // See doc for aiMaterialProperty.
  567|  15.7k|        const aiMaterialProperty *prop = mat->mProperties[i];
  568|  15.7k|        if (nullptr != prop && (includeMatName || prop->mKey.data[0] != '?')) {
  ------------------
  |  Branch (568:13): [True: 15.7k, False: 0]
  |  Branch (568:33): [True: 0, False: 15.7k]
  |  Branch (568:51): [True: 13.8k, False: 1.89k]
  ------------------
  569|       |
  570|  13.8k|            hash = SuperFastHash(prop->mKey.data, (unsigned int)prop->mKey.length, hash);
  571|  13.8k|            hash = SuperFastHash(prop->mData, prop->mDataLength, hash);
  572|       |
  573|       |            // Combine the semantic and the index with the hash
  574|  13.8k|            hash = SuperFastHash((const char *)&prop->mSemantic, sizeof(unsigned int), hash);
  575|  13.8k|            hash = SuperFastHash((const char *)&prop->mIndex, sizeof(unsigned int), hash);
  576|  13.8k|        }
  577|  15.7k|    }
  578|  1.95k|    return hash;
  579|  1.95k|}
MaterialSystem.cpp:_ZN12_GLOBAL__N_128aiGetMaterialFloatFloatArrayEPK10aiMaterialPKcjjPfPj:
  181|  2.24k|        unsigned int *pMax) {
  182|  2.24k|    return GetMaterialFloatArray(pMat, pKey, type, index, pOut, pMax);
  183|  2.24k|}
MaterialSystem.cpp:_ZN12_GLOBAL__N_121GetMaterialFloatArrayIfEE8aiReturnPK10aiMaterialPKcjjPT_Pj:
   97|  6.08k|        unsigned int *pMax) {
   98|  6.08k|    ai_assert(pOut != nullptr);
   99|  6.08k|    ai_assert(pMat != nullptr);
  100|       |
  101|  6.08k|    const aiMaterialProperty *prop{nullptr};
  102|  6.08k|    aiGetMaterialProperty(pMat, pKey, type, index, &prop);
  103|  6.08k|    if (nullptr == prop) {
  ------------------
  |  Branch (103:9): [True: 1.92k, False: 4.15k]
  ------------------
  104|  1.92k|        return AI_FAILURE;
  105|  1.92k|    }
  106|       |
  107|       |    // data is given in floats, convert to TReal
  108|  4.15k|    unsigned int iWrite = 0;
  109|  4.15k|    if (aiPTI_Float == prop->mType || aiPTI_Buffer == prop->mType) {
  ------------------
  |  Branch (109:9): [True: 4.14k, False: 8]
  |  Branch (109:39): [True: 0, False: 8]
  ------------------
  110|  4.14k|        iWrite = prop->mDataLength / sizeof(float);
  111|  4.14k|        if (pMax) {
  ------------------
  |  Branch (111:13): [True: 1.41k, False: 2.72k]
  ------------------
  112|  1.41k|            iWrite = std::min(*pMax, iWrite);
  113|  1.41k|        }
  114|       |
  115|  11.5k|        for (unsigned int a = 0; a < iWrite; ++a) {
  ------------------
  |  Branch (115:34): [True: 7.44k, False: 4.14k]
  ------------------
  116|  7.44k|            pOut[a] = static_cast<TReal>(reinterpret_cast<float *>(prop->mData)[a]);
  117|  7.44k|        }
  118|       |
  119|  4.14k|        if (pMax) {
  ------------------
  |  Branch (119:13): [True: 1.41k, False: 2.72k]
  ------------------
  120|  1.41k|            *pMax = iWrite;
  121|  1.41k|        }
  122|  4.14k|    } else if (aiPTI_Double == prop->mType) { // data is given in doubles, convert to TReal
  ------------------
  |  Branch (122:16): [True: 0, False: 8]
  ------------------
  123|      0|        iWrite = prop->mDataLength / sizeof(double);
  124|      0|        if (pMax) {
  ------------------
  |  Branch (124:13): [True: 0, False: 0]
  ------------------
  125|      0|            iWrite = std::min(*pMax, iWrite);
  126|      0|            ;
  127|      0|        }
  128|      0|        for (unsigned int a = 0; a < iWrite; ++a) {
  ------------------
  |  Branch (128:34): [True: 0, False: 0]
  ------------------
  129|      0|            pOut[a] = static_cast<TReal>(reinterpret_cast<double *>(prop->mData)[a]);
  130|      0|        }
  131|      0|        if (pMax) {
  ------------------
  |  Branch (131:13): [True: 0, False: 0]
  ------------------
  132|      0|            *pMax = iWrite;
  133|      0|        }
  134|      8|    } else if (aiPTI_Integer == prop->mType) { // data is given in ints, convert to TReal
  ------------------
  |  Branch (134:16): [True: 8, False: 0]
  ------------------
  135|      8|        iWrite = prop->mDataLength / sizeof(int32_t);
  136|      8|        if (pMax) {
  ------------------
  |  Branch (136:13): [True: 0, False: 8]
  ------------------
  137|      0|            iWrite = std::min(*pMax, iWrite);
  138|      0|            ;
  139|      0|        }
  140|     16|        for (unsigned int a = 0; a < iWrite; ++a) {
  ------------------
  |  Branch (140:34): [True: 8, False: 8]
  ------------------
  141|      8|            pOut[a] = static_cast<TReal>(reinterpret_cast<int32_t *>(prop->mData)[a]);
  142|      8|        }
  143|      8|        if (pMax) {
  ------------------
  |  Branch (143:13): [True: 0, False: 8]
  ------------------
  144|      0|            *pMax = iWrite;
  145|      0|        }
  146|      8|    } else { // a string ... read floats separated by spaces
  147|      0|        if (pMax) {
  ------------------
  |  Branch (147:13): [True: 0, False: 0]
  ------------------
  148|      0|            iWrite = *pMax;
  149|      0|        }
  150|       |        // strings are zero-terminated with a 32 bit length prefix, so this is safe
  151|      0|        const char *cur = prop->mData + 4;
  152|      0|        ai_assert(prop->mDataLength >= 5);
  153|      0|        ai_assert(!prop->mData[prop->mDataLength - 1]);
  154|      0|        for (unsigned int a = 0;; ++a) {
  155|      0|            cur = fast_atoreal_move(cur, pOut[a]);
  156|      0|            if (a == iWrite - 1) {
  ------------------
  |  Branch (156:17): [True: 0, False: 0]
  ------------------
  157|      0|                break;
  158|      0|            }
  159|      0|            if (!IsSpace(*cur)) {
  ------------------
  |  Branch (159:17): [True: 0, False: 0]
  ------------------
  160|      0|                ASSIMP_LOG_ERROR("Material property", pKey,
  161|      0|                                 " is a string; failed to parse a float array out of it.");
  162|      0|                return AI_FAILURE;
  163|      0|            }
  164|      0|        }
  165|       |
  166|      0|        if (pMax) {
  ------------------
  |  Branch (166:13): [True: 0, False: 0]
  ------------------
  167|      0|            *pMax = iWrite;
  168|      0|        }
  169|      0|    }
  170|       |
  171|  4.15k|    return AI_SUCCESS;
  172|  4.15k|}

_ZNK6Assimp16ArmaturePopulate8IsActiveEj:
   59|    371|bool ArmaturePopulate::IsActive(unsigned int pFlags) const {
   60|    371|    return (pFlags & aiProcess_PopulateArmatureData) != 0;
   61|    371|}

_ZN6Assimp16ArmaturePopulateC2Ev:
   71|    832|    ArmaturePopulate() = default;

_ZN6Assimp19CalcTangentsProcessC2Ev:
   59|    832|        configMaxAngle(float(AI_DEG_TO_RAD(45.f))), configSourceUV(0) {
   60|       |    // nothing to do here
   61|    832|}
_ZNK6Assimp19CalcTangentsProcess8IsActiveEj:
   65|    362|bool CalcTangentsProcess::IsActive(unsigned int pFlags) const {
   66|    362|    return (pFlags & aiProcess_CalcTangentSpace) != 0;
   67|    362|}
_ZN6Assimp19CalcTangentsProcess15SetupPropertiesEPKNS_8ImporterE:
   71|    208|void CalcTangentsProcess::SetupProperties(const Importer *pImp) {
   72|    208|    ai_assert(nullptr != pImp);
   73|       |
   74|       |    // get the current value of the property
   75|    208|    configMaxAngle = pImp->GetPropertyFloat(AI_CONFIG_PP_CT_MAX_SMOOTHING_ANGLE, 45.f);
   76|    208|    configMaxAngle = std::max(std::min(configMaxAngle, 45.0f), 0.0f);
   77|    208|    configMaxAngle = AI_DEG_TO_RAD(configMaxAngle);
   78|       |
   79|       |    configSourceUV = pImp->GetPropertyInteger(AI_CONFIG_PP_CT_TEXTURE_CHANNEL_INDEX, 0);
   80|    208|}
_ZN6Assimp19CalcTangentsProcess7ExecuteEP7aiScene:
   84|    208|void CalcTangentsProcess::Execute(aiScene *pScene) {
   85|    208|    ai_assert(nullptr != pScene);
   86|       |
   87|    208|    ASSIMP_LOG_DEBUG("CalcTangentsProcess begin");
   88|       |
   89|    208|    bool bHas = false;
   90|  3.78k|    for (unsigned int a = 0; a < pScene->mNumMeshes; a++) {
  ------------------
  |  Branch (90:30): [True: 3.57k, False: 208]
  ------------------
   91|  3.57k|        if (ProcessMesh(pScene->mMeshes[a], a)) bHas = true;
  ------------------
  |  Branch (91:13): [True: 259, False: 3.31k]
  ------------------
   92|  3.57k|    }
   93|       |
   94|    208|    if (bHas) {
  ------------------
  |  Branch (94:9): [True: 60, False: 148]
  ------------------
   95|     60|        ASSIMP_LOG_INFO("CalcTangentsProcess finished. Tangents have been calculated");
   96|    148|    } else {
   97|       |        ASSIMP_LOG_DEBUG("CalcTangentsProcess finished");
   98|    148|    }
   99|    208|}
_ZN6Assimp19CalcTangentsProcess11ProcessMeshEP6aiMeshj:
  103|  3.57k|bool CalcTangentsProcess::ProcessMesh(aiMesh *pMesh, unsigned int meshIndex) {
  104|       |    // we assume that the mesh is still in the verbose vertex format where each face has its own set
  105|       |    // of vertices and no vertices are shared between faces. Sadly I don't know any quick test to
  106|       |    // assert() it here.
  107|       |    // assert( must be verbose, dammit);
  108|       |
  109|  3.57k|    if (pMesh->mTangents) // this implies that mBitangents is also there
  ------------------
  |  Branch (109:9): [True: 0, False: 3.57k]
  ------------------
  110|      0|        return false;
  111|       |
  112|       |    // If the mesh consists of lines and/or points but not of
  113|       |    // triangles or higher-order polygons the normal vectors
  114|       |    // are undefined.
  115|  3.57k|    if (!(pMesh->mPrimitiveTypes & (aiPrimitiveType_TRIANGLE | aiPrimitiveType_POLYGON))) {
  ------------------
  |  Branch (115:9): [True: 1.05k, False: 2.52k]
  ------------------
  116|  1.05k|        ASSIMP_LOG_INFO("Tangents are undefined for line and point meshes");
  117|  1.05k|        return false;
  118|  1.05k|    }
  119|       |
  120|       |    // what we can check, though, is if the mesh has normals and texture coordinates. That's a requirement
  121|  2.52k|    if (pMesh->mNormals == nullptr) {
  ------------------
  |  Branch (121:9): [True: 0, False: 2.52k]
  ------------------
  122|      0|        ASSIMP_LOG_ERROR("Failed to compute tangents; need normals");
  123|      0|        return false;
  124|      0|    }
  125|  2.52k|    if (configSourceUV >= AI_MAX_NUMBER_OF_TEXTURECOORDS || !pMesh->mTextureCoords[configSourceUV]) {
  ------------------
  |  Branch (125:9): [True: 0, False: 2.52k]
  |  Branch (125:61): [True: 2.26k, False: 259]
  ------------------
  126|  2.26k|        ASSIMP_LOG_ERROR("Failed to compute tangents; need UV data in channel", configSourceUV);
  127|  2.26k|        return false;
  128|  2.26k|    }
  129|       |
  130|    259|    const float angleEpsilon = 0.9999f;
  131|       |
  132|    259|    std::vector<bool> vertexDone(pMesh->mNumVertices, false);
  133|    259|    const float qnan = get_qnan();
  134|       |
  135|       |    // create space for the tangents and bitangents
  136|    259|    pMesh->mTangents = new aiVector3D[pMesh->mNumVertices];
  137|    259|    pMesh->mBitangents = new aiVector3D[pMesh->mNumVertices];
  138|       |
  139|    259|    const aiVector3D *meshPos = pMesh->mVertices;
  140|    259|    const aiVector3D *meshNorm = pMesh->mNormals;
  141|    259|    const aiVector3D *meshTex = pMesh->mTextureCoords[configSourceUV];
  142|    259|    aiVector3D *meshTang = pMesh->mTangents;
  143|    259|    aiVector3D *meshBitang = pMesh->mBitangents;
  144|       |
  145|       |    // calculate the tangent and bitangent for every face
  146|   151k|    for (unsigned int a = 0; a < pMesh->mNumFaces; a++) {
  ------------------
  |  Branch (146:30): [True: 151k, False: 259]
  ------------------
  147|   151k|        const aiFace &face = pMesh->mFaces[a];
  148|   151k|        if (face.mNumIndices < 3) {
  ------------------
  |  Branch (148:13): [True: 0, False: 151k]
  ------------------
  149|       |            // There are less than three indices, thus the tangent vector
  150|       |            // is not defined. We are finished with these vertices now,
  151|       |            // their tangent vectors are set to qnan.
  152|      0|            for (unsigned int i = 0; i < face.mNumIndices; ++i) {
  ------------------
  |  Branch (152:38): [True: 0, False: 0]
  ------------------
  153|      0|                unsigned int idx = face.mIndices[i];
  154|      0|                vertexDone[idx] = true;
  155|      0|                meshTang[idx] = aiVector3D(qnan);
  156|      0|                meshBitang[idx] = aiVector3D(qnan);
  157|      0|            }
  158|       |
  159|      0|            continue;
  160|      0|        }
  161|       |
  162|       |        // triangle or polygon... we always use only the first three indices. A polygon
  163|       |        // is supposed to be planar anyways....
  164|       |        // FIXME: (thom) create correct calculation for multi-vertex polygons maybe?
  165|   151k|        const unsigned int p0 = face.mIndices[0], p1 = face.mIndices[1], p2 = face.mIndices[2];
  166|       |
  167|       |        // position differences p1->p2 and p1->p3
  168|   151k|        aiVector3D v = meshPos[p1] - meshPos[p0], w = meshPos[p2] - meshPos[p0];
  169|       |
  170|       |        // texture offset p1->p2 and p1->p3
  171|   151k|        float sx = meshTex[p1].x - meshTex[p0].x, sy = meshTex[p1].y - meshTex[p0].y;
  172|   151k|        float tx = meshTex[p2].x - meshTex[p0].x, ty = meshTex[p2].y - meshTex[p0].y;
  173|   151k|        float dirCorrection = (tx * sy - ty * sx) < 0.0f ? -1.0f : 1.0f;
  ------------------
  |  Branch (173:31): [True: 112k, False: 38.1k]
  ------------------
  174|       |        // when t1, t2, t3 in same position in UV space, just use default UV direction.
  175|   151k|        if (sx * ty == sy * tx) {
  ------------------
  |  Branch (175:13): [True: 2.77k, False: 148k]
  ------------------
  176|  2.77k|            sx = 0.0;
  177|  2.77k|            sy = 1.0;
  178|  2.77k|            tx = 1.0;
  179|  2.77k|            ty = 0.0;
  180|  2.77k|        }
  181|       |
  182|       |        // tangent points in the direction where to positive X axis of the texture coord's would point in model space
  183|       |        // bitangent's points along the positive Y axis of the texture coord's, respectively
  184|   151k|        aiVector3D tangent, bitangent;
  185|   151k|        tangent.x = (w.x * sy - v.x * ty) * dirCorrection;
  186|   151k|        tangent.y = (w.y * sy - v.y * ty) * dirCorrection;
  187|   151k|        tangent.z = (w.z * sy - v.z * ty) * dirCorrection;
  188|   151k|        bitangent.x = (w.x * sx - v.x * tx) * dirCorrection;
  189|   151k|        bitangent.y = (w.y * sx - v.y * tx) * dirCorrection;
  190|   151k|        bitangent.z = (w.z * sx - v.z * tx) * dirCorrection;
  191|       |
  192|       |        // store for every vertex of that face
  193|   604k|        for (unsigned int b = 0; b < face.mNumIndices; ++b) {
  ------------------
  |  Branch (193:34): [True: 453k, False: 151k]
  ------------------
  194|   453k|            unsigned int p = face.mIndices[b];
  195|       |
  196|       |            // project tangent and bitangent into the plane formed by the vertex' normal
  197|   453k|            aiVector3D localTangent = tangent - meshNorm[p] * (tangent * meshNorm[p]);
  198|   453k|            aiVector3D localBitangent = bitangent - meshNorm[p] * (bitangent * meshNorm[p]);
  199|   453k|            localTangent.NormalizeSafe();
  200|   453k|            localBitangent.NormalizeSafe();
  201|       |
  202|       |            // reconstruct tangent/bitangent according to normal and bitangent/tangent when it's infinite or NaN.
  203|   453k|            bool invalid_tangent = is_special_float(localTangent.x) || is_special_float(localTangent.y) || is_special_float(localTangent.z)
  ------------------
  |  Branch (203:36): [True: 2, False: 453k]
  |  Branch (203:72): [True: 0, False: 453k]
  |  Branch (203:108): [True: 1, False: 453k]
  ------------------
  204|   453k|                || (-0.5f < localTangent.x && localTangent.x < 0.5f && -0.5f < localTangent.y && localTangent.y < 0.5f && -0.5f < localTangent.z && localTangent.z < 0.5f);
  ------------------
  |  Branch (204:21): [True: 336k, False: 117k]
  |  Branch (204:47): [True: 166k, False: 169k]
  |  Branch (204:72): [True: 152k, False: 14.0k]
  |  Branch (204:98): [True: 135k, False: 17.1k]
  |  Branch (204:123): [True: 101k, False: 33.4k]
  |  Branch (204:149): [True: 0, False: 101k]
  ------------------
  205|   453k|            bool invalid_bitangent = is_special_float(localBitangent.x) || is_special_float(localBitangent.y) || is_special_float(localBitangent.z)
  ------------------
  |  Branch (205:38): [True: 2, False: 453k]
  |  Branch (205:76): [True: 0, False: 453k]
  |  Branch (205:114): [True: 1, False: 453k]
  ------------------
  206|   453k|                || (-0.5f < localBitangent.x && localBitangent.x < 0.5f && -0.5f < localBitangent.y && localBitangent.y < 0.5f && -0.5f < localBitangent.z && localBitangent.z < 0.5f);
  ------------------
  |  Branch (206:21): [True: 388k, False: 64.9k]
  |  Branch (206:49): [True: 319k, False: 68.8k]
  |  Branch (206:76): [True: 96.6k, False: 222k]
  |  Branch (206:104): [True: 82.3k, False: 14.2k]
  |  Branch (206:131): [True: 40.2k, False: 42.0k]
  |  Branch (206:159): [True: 0, False: 40.2k]
  ------------------
  207|   453k|            if (invalid_tangent != invalid_bitangent) {
  ------------------
  |  Branch (207:17): [True: 0, False: 453k]
  ------------------
  208|      0|                if (invalid_tangent) {
  ------------------
  |  Branch (208:21): [True: 0, False: 0]
  ------------------
  209|      0|                    localTangent = meshNorm[p] ^ localBitangent;
  210|      0|                    localTangent.NormalizeSafe();
  211|      0|                } else {
  212|      0|                    localBitangent = localTangent ^ meshNorm[p];
  213|      0|                    localBitangent.NormalizeSafe();
  214|      0|                }
  215|      0|            }
  216|       |
  217|       |            // and write it into the mesh.
  218|   453k|            meshTang[p] = localTangent;
  219|   453k|            meshBitang[p] = localBitangent;
  220|   453k|        }
  221|   151k|    }
  222|       |
  223|       |    // create a helper to quickly find locally close vertices among the vertex array
  224|       |    // FIX: check whether we can reuse the SpatialSort of a previous step
  225|    259|    SpatialSort *vertexFinder = nullptr;
  226|    259|    SpatialSort _vertexFinder;
  227|    259|    float posEpsilon = 10e-6f;
  228|    259|    if (shared) {
  ------------------
  |  Branch (228:9): [True: 259, False: 0]
  ------------------
  229|    259|        std::vector<std::pair<SpatialSort, float>> *avf;
  230|    259|        shared->GetProperty(AI_SPP_SPATIAL_SORT, avf);
  ------------------
  |  |  166|    259|#define AI_SPP_SPATIAL_SORT "$Spat"
  ------------------
  231|    259|        if (avf) {
  ------------------
  |  Branch (231:13): [True: 259, False: 0]
  ------------------
  232|    259|            std::pair<SpatialSort, float> &blubb = avf->operator[](meshIndex);
  233|    259|            vertexFinder = &blubb.first;
  234|    259|            posEpsilon = blubb.second;
  235|    259|            ;
  236|    259|        }
  237|    259|    }
  238|    259|    if (!vertexFinder) {
  ------------------
  |  Branch (238:9): [True: 0, False: 259]
  ------------------
  239|      0|        _vertexFinder.Fill(pMesh->mVertices, pMesh->mNumVertices, sizeof(aiVector3D));
  240|      0|        vertexFinder = &_vertexFinder;
  241|      0|        posEpsilon = ComputePositionEpsilon(pMesh);
  242|      0|    }
  243|    259|    std::vector<unsigned int> verticesFound;
  244|       |
  245|    259|    const float fLimit = std::cos(configMaxAngle);
  246|    259|    std::vector<unsigned int> closeVertices;
  247|       |
  248|       |    // in the second pass we now smooth out all tangents and bitangents at the same local position
  249|       |    // if they are not too far off.
  250|   340k|    for (unsigned int a = 0; a < pMesh->mNumVertices; a++) {
  ------------------
  |  Branch (250:30): [True: 340k, False: 259]
  ------------------
  251|   340k|        if (vertexDone[a])
  ------------------
  |  Branch (251:13): [True: 234k, False: 105k]
  ------------------
  252|   234k|            continue;
  253|       |
  254|   105k|        const aiVector3D &origPos = pMesh->mVertices[a];
  255|   105k|        const aiVector3D &origNorm = pMesh->mNormals[a];
  256|   105k|        const aiVector3D &origTang = pMesh->mTangents[a];
  257|   105k|        const aiVector3D &origBitang = pMesh->mBitangents[a];
  258|   105k|        closeVertices.resize(0);
  259|       |
  260|       |        // find all vertices close to that position
  261|   105k|        vertexFinder->FindPositions(origPos, posEpsilon, verticesFound);
  262|       |
  263|   105k|        closeVertices.reserve(verticesFound.size() + 5);
  264|   105k|        closeVertices.push_back(a);
  265|       |
  266|       |        // look among them for other vertices sharing the same normal and a close-enough tangent/bitangent
  267|   601k|        for (unsigned int b = 0; b < verticesFound.size(); b++) {
  ------------------
  |  Branch (267:34): [True: 495k, False: 105k]
  ------------------
  268|   495k|            unsigned int idx = verticesFound[b];
  269|   495k|            if (vertexDone[idx])
  ------------------
  |  Branch (269:17): [True: 82.0k, False: 413k]
  ------------------
  270|  82.0k|                continue;
  271|   413k|            if (meshNorm[idx] * origNorm < angleEpsilon)
  ------------------
  |  Branch (271:17): [True: 44.6k, False: 369k]
  ------------------
  272|  44.6k|                continue;
  273|   369k|            if (meshTang[idx] * origTang < fLimit)
  ------------------
  |  Branch (273:17): [True: 22.3k, False: 346k]
  ------------------
  274|  22.3k|                continue;
  275|   346k|            if (meshBitang[idx] * origBitang < fLimit)
  ------------------
  |  Branch (275:17): [True: 6.79k, False: 339k]
  ------------------
  276|  6.79k|                continue;
  277|       |
  278|       |            // it's similar enough -> add it to the smoothing group
  279|   339k|            closeVertices.push_back(idx);
  280|   339k|            vertexDone[idx] = true;
  281|   339k|        }
  282|       |
  283|       |        // smooth the tangents and bitangents of all vertices that were found to be close enough
  284|   105k|        aiVector3D smoothTangent(0, 0, 0), smoothBitangent(0, 0, 0);
  285|   550k|        for (unsigned int b = 0; b < closeVertices.size(); ++b) {
  ------------------
  |  Branch (285:34): [True: 445k, False: 105k]
  ------------------
  286|   445k|            smoothTangent += meshTang[closeVertices[b]];
  287|   445k|            smoothBitangent += meshBitang[closeVertices[b]];
  288|   445k|        }
  289|   105k|        smoothTangent.Normalize();
  290|   105k|        smoothBitangent.Normalize();
  291|       |
  292|       |        // and write it back into all affected tangents
  293|   550k|        for (unsigned int b = 0; b < closeVertices.size(); ++b) {
  ------------------
  |  Branch (293:34): [True: 445k, False: 105k]
  ------------------
  294|   445k|            meshTang[closeVertices[b]] = smoothTangent;
  295|   445k|            meshBitang[closeVertices[b]] = smoothBitangent;
  296|   445k|        }
  297|   105k|    }
  298|    259|    return true;
  299|  2.52k|}

_ZNK6Assimp23ComputeUVMappingProcess8IsActiveEj:
   61|    371|bool ComputeUVMappingProcess::IsActive(unsigned int pFlags) const {
   62|    371|    return (pFlags & aiProcess_GenUVCoords) != 0;
   63|    371|}
_ZN6Assimp23ComputeUVMappingProcess7ExecuteEP7aiScene:
  345|    217|void ComputeUVMappingProcess::Execute(aiScene *pScene) {
  346|    217|    ASSIMP_LOG_DEBUG("GenUVCoordsProcess begin");
  347|    217|    char buffer[1024];
  348|       |
  349|    217|    if (pScene->mFlags & AI_SCENE_FLAGS_NON_VERBOSE_FORMAT) {
  ------------------
  |  Branch (349:9): [True: 0, False: 217]
  ------------------
  350|      0|        throw DeadlyImportError("Post-processing order mismatch: expecting pseudo-indexed (\"verbose\") vertices here");
  351|      0|    }
  352|       |
  353|    217|    std::list<MappingInfo> mappingStack;
  354|       |
  355|       |    // Iterate through all materials and search for non-UV mapped textures
  356|    472|    for (unsigned int i = 0; i < pScene->mNumMaterials; ++i) {
  ------------------
  |  Branch (356:30): [True: 255, False: 217]
  ------------------
  357|    255|        mappingStack.clear();
  358|    255|        aiMaterial *mat = pScene->mMaterials[i];
  359|    255|        if (mat == nullptr) {
  ------------------
  |  Branch (359:13): [True: 0, False: 255]
  ------------------
  360|      0|            ASSIMP_LOG_INFO("Material pointer in nullptr, skipping.");
  361|      0|            continue;
  362|      0|        }
  363|  3.66k|        for (unsigned int a = 0; a < mat->mNumProperties; ++a) {
  ------------------
  |  Branch (363:34): [True: 3.40k, False: 255]
  ------------------
  364|  3.40k|            aiMaterialProperty *prop = mat->mProperties[a];
  365|  3.40k|            if (!::strcmp(prop->mKey.data, "$tex.mapping")) {
  ------------------
  |  Branch (365:17): [True: 2, False: 3.40k]
  ------------------
  366|      2|                aiTextureMapping &mapping = *((aiTextureMapping *)prop->mData);
  367|      2|                if (aiTextureMapping_UV != mapping) {
  ------------------
  |  Branch (367:21): [True: 0, False: 2]
  ------------------
  368|      0|                    if (!DefaultLogger::isNullLogger()) {
  ------------------
  |  Branch (368:25): [True: 0, False: 0]
  ------------------
  369|      0|                        ai_snprintf(buffer, 1024, "Found non-UV mapped texture (%s,%u). Mapping type: %s",
  370|      0|                                aiTextureTypeToString((aiTextureType)prop->mSemantic), prop->mIndex,
  371|      0|                                MappingTypeToString(mapping));
  372|       |
  373|      0|                        ASSIMP_LOG_INFO(buffer);
  374|      0|                    }
  375|       |
  376|      0|                    if (aiTextureMapping_OTHER == mapping)
  ------------------
  |  Branch (376:25): [True: 0, False: 0]
  ------------------
  377|      0|                        continue;
  378|       |
  379|      0|                    MappingInfo info(mapping);
  380|       |
  381|       |                    // Get further properties - currently only the major axis
  382|      0|                    for (unsigned int a2 = 0; a2 < mat->mNumProperties; ++a2) {
  ------------------
  |  Branch (382:47): [True: 0, False: 0]
  ------------------
  383|      0|                        aiMaterialProperty *prop2 = mat->mProperties[a2];
  384|      0|                        if (prop2->mSemantic != prop->mSemantic || prop2->mIndex != prop->mIndex)
  ------------------
  |  Branch (384:29): [True: 0, False: 0]
  |  Branch (384:68): [True: 0, False: 0]
  ------------------
  385|      0|                            continue;
  386|       |
  387|      0|                        if (!::strcmp(prop2->mKey.data, "$tex.mapaxis")) {
  ------------------
  |  Branch (387:29): [True: 0, False: 0]
  ------------------
  388|      0|                            info.axis = *((aiVector3D *)prop2->mData);
  389|      0|                            break;
  390|      0|                        }
  391|      0|                    }
  392|       |
  393|      0|                    unsigned int idx(99999999);
  394|       |
  395|       |                    // Check whether we have this mapping mode already
  396|      0|                    std::list<MappingInfo>::iterator it = std::find(mappingStack.begin(), mappingStack.end(), info);
  397|      0|                    if (mappingStack.end() != it) {
  ------------------
  |  Branch (397:25): [True: 0, False: 0]
  ------------------
  398|      0|                        idx = (*it).uv;
  399|      0|                    } else {
  400|       |                        /*  We have found a non-UV mapped texture. Now
  401|       |                         *   we need to find all meshes using this material
  402|       |                         *   that we can compute UV channels for them.
  403|       |                         */
  404|      0|                        for (unsigned int m = 0; m < pScene->mNumMeshes; ++m) {
  ------------------
  |  Branch (404:50): [True: 0, False: 0]
  ------------------
  405|      0|                            aiMesh *mesh = pScene->mMeshes[m];
  406|      0|                            unsigned int outIdx = 0;
  407|      0|                            if (mesh->mMaterialIndex != i || (outIdx = FindEmptyUVChannel(mesh)) == UINT_MAX ||
  ------------------
  |  Branch (407:33): [True: 0, False: 0]
  |  Branch (407:62): [True: 0, False: 0]
  ------------------
  408|      0|                                    !mesh->mNumVertices) {
  ------------------
  |  Branch (408:37): [True: 0, False: 0]
  ------------------
  409|      0|                                continue;
  410|      0|                            }
  411|       |
  412|       |                            // Allocate output storage
  413|      0|                            aiVector3D *p = mesh->mTextureCoords[outIdx] = new aiVector3D[mesh->mNumVertices];
  414|       |
  415|      0|                            switch (mapping) {
  416|      0|                            case aiTextureMapping_SPHERE:
  ------------------
  |  Branch (416:29): [True: 0, False: 0]
  ------------------
  417|      0|                                ComputeSphereMapping(mesh, info.axis, p);
  418|      0|                                break;
  419|      0|                            case aiTextureMapping_CYLINDER:
  ------------------
  |  Branch (419:29): [True: 0, False: 0]
  ------------------
  420|      0|                                ComputeCylinderMapping(mesh, info.axis, p);
  421|      0|                                break;
  422|      0|                            case aiTextureMapping_PLANE:
  ------------------
  |  Branch (422:29): [True: 0, False: 0]
  ------------------
  423|      0|                                ComputePlaneMapping(mesh, info.axis, p);
  424|      0|                                break;
  425|      0|                            case aiTextureMapping_BOX:
  ------------------
  |  Branch (425:29): [True: 0, False: 0]
  ------------------
  426|      0|                                ComputeBoxMapping(mesh, p);
  427|      0|                                break;
  428|      0|                            default:
  ------------------
  |  Branch (428:29): [True: 0, False: 0]
  ------------------
  429|      0|                                ai_assert(false);
  430|      0|                            }
  431|      0|                            if (m && idx != outIdx) {
  ------------------
  |  Branch (431:33): [True: 0, False: 0]
  |  Branch (431:38): [True: 0, False: 0]
  ------------------
  432|      0|                                ASSIMP_LOG_WARN("UV index mismatch. Not all meshes assigned to "
  433|      0|                                                "this material have equal numbers of UV channels. The UV index stored in  "
  434|      0|                                                "the material structure does therefore not apply for all meshes. ");
  435|      0|                            }
  436|      0|                            idx = outIdx;
  437|      0|                        }
  438|      0|                        info.uv = idx;
  439|      0|                        mappingStack.push_back(info);
  440|      0|                    }
  441|       |
  442|       |                    // Update the material property list
  443|      0|                    mapping = aiTextureMapping_UV;
  444|      0|                    ((aiMaterial *)mat)->AddProperty(&idx, 1, AI_MATKEY_UVWSRC(prop->mSemantic, prop->mIndex));
  445|      0|                }
  446|      2|            }
  447|  3.40k|        }
  448|    255|    }
  449|    217|    ASSIMP_LOG_DEBUG("GenUVCoordsProcess finished");
  450|    217|}

_ZN6Assimp23ComputeUVMappingProcessC2Ev:
   63|    832|    ComputeUVMappingProcess() = default;

_ZNK6Assimp21MakeLeftHandedProcess8IsActiveEj:
   82|    371|bool MakeLeftHandedProcess::IsActive(unsigned int pFlags) const {
   83|    371|    return 0 != (pFlags & aiProcess_MakeLeftHanded);
   84|    371|}
_ZN6Assimp21MakeLeftHandedProcess7ExecuteEP7aiScene:
   88|     55|void MakeLeftHandedProcess::Execute(aiScene *pScene) {
   89|       |    // Check for an existent root node to proceed
   90|     55|    ai_assert(pScene->mRootNode != nullptr);
   91|     55|    ASSIMP_LOG_DEBUG("MakeLeftHandedProcess begin");
   92|       |
   93|       |    // recursively convert all the nodes
   94|     55|    ProcessNode(pScene->mRootNode, aiMatrix4x4());
   95|       |
   96|       |    // process the meshes accordingly
   97|     81|    for (unsigned int a = 0; a < pScene->mNumMeshes; ++a) {
  ------------------
  |  Branch (97:30): [True: 26, False: 55]
  ------------------
   98|     26|        ProcessMesh(pScene->mMeshes[a]);
   99|     26|    }
  100|       |
  101|       |    // process the materials accordingly
  102|     75|    for (unsigned int a = 0; a < pScene->mNumMaterials; ++a) {
  ------------------
  |  Branch (102:30): [True: 20, False: 55]
  ------------------
  103|     20|        ProcessMaterial(pScene->mMaterials[a]);
  104|     20|    }
  105|       |
  106|       |    // transform all animation channels as well
  107|     68|    for (unsigned int a = 0; a < pScene->mNumAnimations; a++) {
  ------------------
  |  Branch (107:30): [True: 13, False: 55]
  ------------------
  108|     13|        aiAnimation *anim = pScene->mAnimations[a];
  109|    515|        for (unsigned int b = 0; b < anim->mNumChannels; b++) {
  ------------------
  |  Branch (109:34): [True: 502, False: 13]
  ------------------
  110|    502|            aiNodeAnim *nodeAnim = anim->mChannels[b];
  111|    502|            ProcessAnimation(nodeAnim);
  112|    502|        }
  113|     13|    }
  114|       |
  115|       |    // process the cameras accordingly
  116|     63|    for( unsigned int a = 0; a < pScene->mNumCameras; ++a)
  ------------------
  |  Branch (116:30): [True: 8, False: 55]
  ------------------
  117|      8|    {
  118|      8|        ProcessCamera(pScene->mCameras[a]);
  119|      8|    }
  120|       |    ASSIMP_LOG_DEBUG("MakeLeftHandedProcess finished");
  121|     55|}
_ZN6Assimp21MakeLeftHandedProcess11ProcessNodeEP6aiNodeRK12aiMatrix4x4tIfE:
  125|  22.3k|void MakeLeftHandedProcess::ProcessNode(aiNode *pNode, const aiMatrix4x4 &pParentGlobalRotation) {
  126|       |    // mirror all base vectors at the local Z axis
  127|  22.3k|    pNode->mTransformation.c1 = -pNode->mTransformation.c1;
  128|  22.3k|    pNode->mTransformation.c2 = -pNode->mTransformation.c2;
  129|  22.3k|    pNode->mTransformation.c3 = -pNode->mTransformation.c3;
  130|  22.3k|    pNode->mTransformation.c4 = -pNode->mTransformation.c4;
  131|       |
  132|       |    // now invert the Z axis again to keep the matrix determinant positive.
  133|       |    // The local meshes will be inverted accordingly so that the result should look just fine again.
  134|  22.3k|    pNode->mTransformation.a3 = -pNode->mTransformation.a3;
  135|  22.3k|    pNode->mTransformation.b3 = -pNode->mTransformation.b3;
  136|  22.3k|    pNode->mTransformation.c3 = -pNode->mTransformation.c3;
  137|  22.3k|    pNode->mTransformation.d3 = -pNode->mTransformation.d3; // useless, but anyways...
  138|       |
  139|       |    // continue for all children
  140|  44.5k|    for (size_t a = 0; a < pNode->mNumChildren; ++a) {
  ------------------
  |  Branch (140:24): [True: 22.2k, False: 22.3k]
  ------------------
  141|  22.2k|        ProcessNode(pNode->mChildren[a], pParentGlobalRotation * pNode->mTransformation);
  142|  22.2k|    }
  143|  22.3k|}
_ZN6Assimp21MakeLeftHandedProcess11ProcessMeshEP6aiMesh:
  147|     26|void MakeLeftHandedProcess::ProcessMesh(aiMesh *pMesh) {
  148|     26|    if (nullptr == pMesh) {
  ------------------
  |  Branch (148:9): [True: 0, False: 26]
  ------------------
  149|      0|        ASSIMP_LOG_ERROR("Nullptr to mesh found.");
  150|      0|        return;
  151|      0|    }
  152|       |    // mirror positions, normals and stuff along the Z axis
  153|  67.4k|    for (size_t a = 0; a < pMesh->mNumVertices; ++a) {
  ------------------
  |  Branch (153:24): [True: 67.3k, False: 26]
  ------------------
  154|  67.3k|        pMesh->mVertices[a].z *= -1.0f;
  155|  67.3k|        if (pMesh->HasNormals()) {
  ------------------
  |  Branch (155:13): [True: 67.3k, False: 0]
  ------------------
  156|  67.3k|            pMesh->mNormals[a].z *= -1.0f;
  157|  67.3k|        }
  158|  67.3k|        if (pMesh->HasTangentsAndBitangents()) {
  ------------------
  |  Branch (158:13): [True: 0, False: 67.3k]
  ------------------
  159|      0|            pMesh->mTangents[a].z *= -1.0f;
  160|      0|            pMesh->mBitangents[a].z *= -1.0f;
  161|      0|        }
  162|  67.3k|    }
  163|       |
  164|       |    // mirror anim meshes positions, normals and stuff along the Z axis
  165|     26|    for (size_t m = 0; m < pMesh->mNumAnimMeshes; ++m) {
  ------------------
  |  Branch (165:24): [True: 0, False: 26]
  ------------------
  166|      0|        for (size_t a = 0; a < pMesh->mAnimMeshes[m]->mNumVertices; ++a) {
  ------------------
  |  Branch (166:28): [True: 0, False: 0]
  ------------------
  167|      0|            pMesh->mAnimMeshes[m]->mVertices[a].z *= -1.0f;
  168|      0|            if (pMesh->mAnimMeshes[m]->HasNormals()) {
  ------------------
  |  Branch (168:17): [True: 0, False: 0]
  ------------------
  169|      0|                pMesh->mAnimMeshes[m]->mNormals[a].z *= -1.0f;
  170|      0|            }
  171|      0|            if (pMesh->mAnimMeshes[m]->HasTangentsAndBitangents()) {
  ------------------
  |  Branch (171:17): [True: 0, False: 0]
  ------------------
  172|      0|                pMesh->mAnimMeshes[m]->mTangents[a].z *= -1.0f;
  173|      0|                pMesh->mAnimMeshes[m]->mBitangents[a].z *= -1.0f;
  174|      0|            }
  175|      0|        }
  176|      0|    }
  177|       |
  178|       |    // mirror offset matrices of all bones
  179|    161|    for (size_t a = 0; a < pMesh->mNumBones; ++a) {
  ------------------
  |  Branch (179:24): [True: 135, False: 26]
  ------------------
  180|    135|        aiBone *bone = pMesh->mBones[a];
  181|    135|        bone->mOffsetMatrix.a3 = -bone->mOffsetMatrix.a3;
  182|    135|        bone->mOffsetMatrix.b3 = -bone->mOffsetMatrix.b3;
  183|    135|        bone->mOffsetMatrix.d3 = -bone->mOffsetMatrix.d3;
  184|    135|        bone->mOffsetMatrix.c1 = -bone->mOffsetMatrix.c1;
  185|    135|        bone->mOffsetMatrix.c2 = -bone->mOffsetMatrix.c2;
  186|    135|        bone->mOffsetMatrix.c4 = -bone->mOffsetMatrix.c4;
  187|    135|    }
  188|       |
  189|       |    // mirror bitangents as well as they're derived from the texture coords
  190|     26|    if (pMesh->HasTangentsAndBitangents()) {
  ------------------
  |  Branch (190:9): [True: 0, False: 26]
  ------------------
  191|      0|        for (unsigned int a = 0; a < pMesh->mNumVertices; a++)
  ------------------
  |  Branch (191:34): [True: 0, False: 0]
  ------------------
  192|      0|            pMesh->mBitangents[a] *= -1.0f;
  193|      0|    }
  194|     26|}
_ZN6Assimp21MakeLeftHandedProcess15ProcessMaterialEP10aiMaterial:
  198|     20|void MakeLeftHandedProcess::ProcessMaterial(aiMaterial *_mat) {
  199|     20|    if (nullptr == _mat) {
  ------------------
  |  Branch (199:9): [True: 0, False: 20]
  ------------------
  200|      0|        ASSIMP_LOG_ERROR("Nullptr to aiMaterial found.");
  201|      0|        return;
  202|      0|    }
  203|       |
  204|     20|    aiMaterial *mat = (aiMaterial *)_mat;
  205|    235|    for (unsigned int a = 0; a < mat->mNumProperties; ++a) {
  ------------------
  |  Branch (205:30): [True: 215, False: 20]
  ------------------
  206|    215|        aiMaterialProperty *prop = mat->mProperties[a];
  207|       |
  208|       |        // Mapping axis for UV mappings?
  209|    215|        if (!::strcmp(prop->mKey.data, "$tex.mapaxis")) {
  ------------------
  |  Branch (209:13): [True: 0, False: 215]
  ------------------
  210|       |            ai_assert(prop->mDataLength >= sizeof(aiVector3D)); // something is wrong with the validation if we end up here
  211|      0|            aiVector3D *pff = (aiVector3D *)prop->mData;
  212|      0|            pff->z *= -1.f;
  213|      0|        }
  214|    215|    }
  215|     20|}
_ZN6Assimp21MakeLeftHandedProcess16ProcessAnimationEP10aiNodeAnim:
  219|    502|void MakeLeftHandedProcess::ProcessAnimation(aiNodeAnim *pAnim) {
  220|       |    // position keys
  221|  2.51k|    for (unsigned int a = 0; a < pAnim->mNumPositionKeys; a++)
  ------------------
  |  Branch (221:30): [True: 2.01k, False: 502]
  ------------------
  222|  2.01k|        pAnim->mPositionKeys[a].mValue.z *= -1.0f;
  223|       |
  224|       |    // rotation keys
  225|  7.58k|    for (unsigned int a = 0; a < pAnim->mNumRotationKeys; a++) {
  ------------------
  |  Branch (225:30): [True: 7.08k, False: 502]
  ------------------
  226|  7.08k|        pAnim->mRotationKeys[a].mValue.x *= -1.0f;
  227|  7.08k|        pAnim->mRotationKeys[a].mValue.y *= -1.0f;
  228|  7.08k|    }
  229|    502|}
_ZN6Assimp21MakeLeftHandedProcess13ProcessCameraEP8aiCamera:
  234|      8|{
  235|      8|    pCam->mLookAt = ai_real(2.0f) * pCam->mPosition - pCam->mLookAt;
  236|      8|}
_ZN6Assimp14FlipUVsProcessC2Ev:
  244|    832|FlipUVsProcess::FlipUVsProcess() = default;
_ZN6Assimp14FlipUVsProcessD2Ev:
  248|    832|FlipUVsProcess::~FlipUVsProcess() = default;
_ZNK6Assimp14FlipUVsProcess8IsActiveEj:
  252|    371|bool FlipUVsProcess::IsActive(unsigned int pFlags) const {
  253|    371|    return 0 != (pFlags & aiProcess_FlipUVs);
  254|    371|}
_ZNK6Assimp23FlipWindingOrderProcess8IsActiveEj:
  306|    371|bool FlipWindingOrderProcess::IsActive(unsigned int pFlags) const {
  307|    371|    return 0 != (pFlags & aiProcess_FlipWindingOrder);
  308|    371|}
_ZN6Assimp23FlipWindingOrderProcess7ExecuteEP7aiScene:
  312|     55|void FlipWindingOrderProcess::Execute(aiScene *pScene) {
  313|     55|    ASSIMP_LOG_DEBUG("FlipWindingOrderProcess begin");
  314|     81|    for (unsigned int i = 0; i < pScene->mNumMeshes; ++i)
  ------------------
  |  Branch (314:30): [True: 26, False: 55]
  ------------------
  315|     26|        ProcessMesh(pScene->mMeshes[i]);
  316|       |    ASSIMP_LOG_DEBUG("FlipWindingOrderProcess finished");
  317|     55|}
_ZN6Assimp23FlipWindingOrderProcess11ProcessMeshEP6aiMesh:
  321|     26|void FlipWindingOrderProcess::ProcessMesh(aiMesh *pMesh) {
  322|       |    // invert the order of all faces in this mesh
  323|  21.5k|    for (unsigned int a = 0; a < pMesh->mNumFaces; a++) {
  ------------------
  |  Branch (323:30): [True: 21.4k, False: 26]
  ------------------
  324|  21.4k|        aiFace &face = pMesh->mFaces[a];
  325|  45.8k|        for (unsigned int b = 0; b < face.mNumIndices / 2; b++) {
  ------------------
  |  Branch (325:34): [True: 24.3k, False: 21.4k]
  ------------------
  326|  24.3k|            std::swap(face.mIndices[b], face.mIndices[face.mNumIndices - 1 - b]);
  327|  24.3k|        }
  328|  21.4k|    }
  329|       |
  330|       |    // invert the order of all components in this mesh anim meshes
  331|     26|    for (unsigned int m = 0; m < pMesh->mNumAnimMeshes; m++) {
  ------------------
  |  Branch (331:30): [True: 0, False: 26]
  ------------------
  332|      0|        aiAnimMesh *animMesh = pMesh->mAnimMeshes[m];
  333|      0|        unsigned int numVertices = animMesh->mNumVertices;
  334|      0|        if (animMesh->HasPositions()) {
  ------------------
  |  Branch (334:13): [True: 0, False: 0]
  ------------------
  335|      0|            for (unsigned int a = 0; a < numVertices; a++) {
  ------------------
  |  Branch (335:38): [True: 0, False: 0]
  ------------------
  336|      0|                std::swap(animMesh->mVertices[a], animMesh->mVertices[numVertices - 1 - a]);
  337|      0|            }
  338|      0|        }
  339|      0|        if (animMesh->HasNormals()) {
  ------------------
  |  Branch (339:13): [True: 0, False: 0]
  ------------------
  340|      0|            for (unsigned int a = 0; a < numVertices; a++) {
  ------------------
  |  Branch (340:38): [True: 0, False: 0]
  ------------------
  341|      0|                std::swap(animMesh->mNormals[a], animMesh->mNormals[numVertices - 1 - a]);
  342|      0|            }
  343|      0|        }
  344|      0|        for (unsigned int i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS; i++) {
  ------------------
  |  Branch (344:34): [True: 0, False: 0]
  ------------------
  345|      0|            if (animMesh->HasTextureCoords(i)) {
  ------------------
  |  Branch (345:17): [True: 0, False: 0]
  ------------------
  346|      0|                for (unsigned int a = 0; a < numVertices; a++) {
  ------------------
  |  Branch (346:42): [True: 0, False: 0]
  ------------------
  347|      0|                    std::swap(animMesh->mTextureCoords[i][a], animMesh->mTextureCoords[i][numVertices - 1 - a]);
  348|      0|                }
  349|      0|            }
  350|      0|        }
  351|      0|        if (animMesh->HasTangentsAndBitangents()) {
  ------------------
  |  Branch (351:13): [True: 0, False: 0]
  ------------------
  352|      0|            for (unsigned int a = 0; a < numVertices; a++) {
  ------------------
  |  Branch (352:38): [True: 0, False: 0]
  ------------------
  353|      0|                std::swap(animMesh->mTangents[a], animMesh->mTangents[numVertices - 1 - a]);
  354|      0|                std::swap(animMesh->mBitangents[a], animMesh->mBitangents[numVertices - 1 - a]);
  355|      0|            }
  356|      0|        }
  357|      0|        for (unsigned int v = 0; v < AI_MAX_NUMBER_OF_COLOR_SETS; v++) {
  ------------------
  |  Branch (357:34): [True: 0, False: 0]
  ------------------
  358|      0|            if (animMesh->HasVertexColors(v)) {
  ------------------
  |  Branch (358:17): [True: 0, False: 0]
  ------------------
  359|      0|                for (unsigned int a = 0; a < numVertices; a++) {
  ------------------
  |  Branch (359:42): [True: 0, False: 0]
  ------------------
  360|      0|                    std::swap(animMesh->mColors[v][a], animMesh->mColors[v][numVertices - 1 - a]);
  361|      0|                }
  362|      0|            }
  363|      0|        }
  364|      0|    }
  365|     26|}

_ZN6Assimp23FlipWindingOrderProcessC2Ev:
  132|    887|    FlipWindingOrderProcess() = default;
_ZN6Assimp21MakeLeftHandedProcessC2Ev:
   77|    887|    MakeLeftHandedProcess() = default;

_ZN6Assimp13DeboneProcessC2Ev:
   54|    832|DeboneProcess::DeboneProcess() : mNumBones(0), mNumBonesCanDoWithout(0), mThreshold(AI_DEBONE_THRESHOLD), mAllOrNone(false) {}
_ZNK6Assimp13DeboneProcess8IsActiveEj:
   58|    362|bool DeboneProcess::IsActive( unsigned int pFlags) const {
   59|    362|    return (pFlags & aiProcess_Debone) != 0;
   60|    362|}

_ZN6Assimp13DeboneProcessD2Ev:
   72|    832|    ~DeboneProcess() override = default;

_ZNK6Assimp22DropFaceNormalsProcess8IsActiveEj:
   58|    362|bool DropFaceNormalsProcess::IsActive(unsigned int pFlags) const {
   59|    362|    return (pFlags & aiProcess_DropNormals) != 0;
   60|    362|}

_ZN6Assimp22DropFaceNormalsProcessC2Ev:
   57|    832|    DropFaceNormalsProcess() = default;

_ZNK6Assimp20EmbedTexturesProcess8IsActiveEj:
   53|    371|bool EmbedTexturesProcess::IsActive(unsigned int pFlags) const {
   54|    371|    return (pFlags & aiProcess_EmbedTextures) != 0;
   55|    371|}

_ZN6Assimp20EmbedTexturesProcessC2Ev:
   64|    832|    EmbedTexturesProcess() = default;
_ZN6Assimp20EmbedTexturesProcessD2Ev:
   67|    832|    ~EmbedTexturesProcess() override = default;

_ZN6Assimp22FindDegeneratesProcessC2Ev:
   62|    832|        mConfigRemoveDegenerates(false),
   63|    832|        mConfigCheckAreaOfTriangle(false) {
   64|       |    // empty
   65|    832|}
_ZNK6Assimp22FindDegeneratesProcess8IsActiveEj:
   69|    371|bool FindDegeneratesProcess::IsActive(unsigned int pFlags) const {
   70|    371|    return 0 != (pFlags & aiProcess_FindDegenerates);
   71|    371|}
_ZN6Assimp22FindDegeneratesProcess15SetupPropertiesEPKNS_8ImporterE:
   75|    217|void FindDegeneratesProcess::SetupProperties(const Importer *pImp) {
   76|       |    // Get the current value of AI_CONFIG_PP_FD_REMOVE
   77|    217|    mConfigRemoveDegenerates = (0 != pImp->GetPropertyInteger(AI_CONFIG_PP_FD_REMOVE, 0));
   78|       |    mConfigCheckAreaOfTriangle = (0 != pImp->GetPropertyInteger(AI_CONFIG_PP_FD_CHECKAREA));
   79|    217|}
_ZN6Assimp22FindDegeneratesProcess7ExecuteEP7aiScene:
   83|    217|void FindDegeneratesProcess::Execute(aiScene *pScene) {
   84|    217|    ASSIMP_LOG_DEBUG("FindDegeneratesProcess begin");
   85|    217|    if (nullptr == pScene) {
  ------------------
  |  Branch (85:9): [True: 0, False: 217]
  ------------------
   86|      0|        return;
   87|      0|    }
   88|       |
   89|    217|    std::unordered_map<unsigned int, unsigned int> meshMap;
   90|    217|    meshMap.reserve(pScene->mNumMeshes);
   91|       |
   92|    217|    const unsigned int originalNumMeshes = pScene->mNumMeshes;
   93|    217|    unsigned int targetIndex = 0;
   94|  3.46k|    for (unsigned int i = 0; i < pScene->mNumMeshes; ++i) {
  ------------------
  |  Branch (94:30): [True: 3.24k, False: 217]
  ------------------
   95|       |        // Do not process point cloud, ExecuteOnMesh works only with faces data
   96|  3.24k|        if ((pScene->mMeshes[i]->mPrimitiveTypes != aiPrimitiveType::aiPrimitiveType_POINT) && ExecuteOnMesh(pScene->mMeshes[i])) {
  ------------------
  |  Branch (96:13): [True: 3.10k, False: 148]
  |  Branch (96:96): [True: 0, False: 3.10k]
  ------------------
   97|      0|            delete pScene->mMeshes[i];
   98|       |            // Not strictly required, but clean:
   99|      0|            pScene->mMeshes[i] = nullptr;
  100|  3.24k|        } else {
  101|  3.24k|            meshMap[i] = targetIndex;
  102|  3.24k|            pScene->mMeshes[targetIndex] = pScene->mMeshes[i];
  103|  3.24k|            ++targetIndex;
  104|  3.24k|        }
  105|  3.24k|    }
  106|    217|    pScene->mNumMeshes = targetIndex;
  107|       |
  108|    217|    if (meshMap.size() < originalNumMeshes) {
  ------------------
  |  Branch (108:9): [True: 0, False: 217]
  ------------------
  109|      0|        updateSceneGraph(pScene->mRootNode, meshMap);
  110|      0|    }
  111|       |
  112|       |    ASSIMP_LOG_DEBUG("FindDegeneratesProcess finished");
  113|    217|}
_ZN6Assimp22FindDegeneratesProcess13ExecuteOnMeshEP6aiMesh:
  134|  3.10k|bool FindDegeneratesProcess::ExecuteOnMesh(aiMesh *mesh) {
  135|  3.10k|    mesh->mPrimitiveTypes = 0;
  136|       |
  137|  3.10k|    std::vector<bool> remove_me;
  138|  3.10k|    if (mConfigRemoveDegenerates) {
  ------------------
  |  Branch (138:9): [True: 0, False: 3.10k]
  ------------------
  139|      0|        remove_me.resize(mesh->mNumFaces, false);
  140|      0|    }
  141|       |
  142|  3.10k|    unsigned int deg = 0, limit;
  143|  1.41M|    for (unsigned int a = 0; a < mesh->mNumFaces; ++a) {
  ------------------
  |  Branch (143:30): [True: 1.41M, False: 3.10k]
  ------------------
  144|  1.41M|        aiFace &face = mesh->mFaces[a];
  145|  1.41M|        bool first = true;
  146|  1.41M|        auto vertex_in_range = [numVertices = mesh->mNumVertices](unsigned int vertex_idx) { return vertex_idx < numVertices; };
  147|       |
  148|       |        // check whether the face contains degenerated entries
  149|  5.60M|        for (unsigned int i = 0; i < face.mNumIndices; ++i) {
  ------------------
  |  Branch (149:34): [True: 4.18M, False: 1.41M]
  ------------------
  150|  4.18M|            if (!std::all_of(face.mIndices, face.mIndices + face.mNumIndices, vertex_in_range))
  ------------------
  |  Branch (150:17): [True: 0, False: 4.18M]
  ------------------
  151|      0|                continue;
  152|       |
  153|       |            // Polygons with more than 4 points are allowed to have double points, that is
  154|       |            // simulating polygons with holes just with concave polygons. However,
  155|       |            // double points may not come directly after another.
  156|  4.18M|            limit = face.mNumIndices;
  157|  4.18M|            if (face.mNumIndices > 4) {
  ------------------
  |  Branch (157:17): [True: 0, False: 4.18M]
  ------------------
  158|      0|                limit = std::min(limit, i + 2);
  159|      0|            }
  160|       |
  161|  8.39M|            for (unsigned int t = i + 1; t < limit; ++t) {
  ------------------
  |  Branch (161:42): [True: 4.21M, False: 4.18M]
  ------------------
  162|  4.21M|                if (mesh->mVertices[face.mIndices[i]] == mesh->mVertices[face.mIndices[t]]) {
  ------------------
  |  Branch (162:21): [True: 50.4k, False: 4.15M]
  ------------------
  163|       |                    // we have found a matching vertex position
  164|       |                    // remove the corresponding index from the array
  165|  50.4k|                    --face.mNumIndices;
  166|  50.4k|                    --limit;
  167|  74.5k|                    for (unsigned int m = t; m < face.mNumIndices; ++m) {
  ------------------
  |  Branch (167:46): [True: 24.0k, False: 50.4k]
  ------------------
  168|  24.0k|                        face.mIndices[m] = face.mIndices[m + 1];
  169|  24.0k|                    }
  170|  50.4k|                    --t;
  171|       |
  172|       |                    // NOTE: we set the removed vertex index to an unique value
  173|       |                    // to make sure the developer gets notified when his
  174|       |                    // application attempts to access this data.
  175|  50.4k|                    face.mIndices[face.mNumIndices] = 0xdeadbeef;
  176|       |
  177|  50.4k|                    if (first) {
  ------------------
  |  Branch (177:25): [True: 26.9k, False: 23.5k]
  ------------------
  178|  26.9k|                        ++deg;
  179|  26.9k|                        first = false;
  180|  26.9k|                    }
  181|       |
  182|  50.4k|                    if (mConfigRemoveDegenerates) {
  ------------------
  |  Branch (182:25): [True: 0, False: 50.4k]
  ------------------
  183|      0|                        remove_me[a] = true;
  184|      0|                        goto evil_jump_outside; // hrhrhrh ... yeah, this rocks baby!
  185|      0|                    }
  186|  50.4k|                }
  187|  4.21M|            }
  188|       |
  189|  4.18M|            if (mConfigCheckAreaOfTriangle) {
  ------------------
  |  Branch (189:17): [True: 4.18M, False: 0]
  ------------------
  190|  4.18M|                if (face.mNumIndices == 3) {
  ------------------
  |  Branch (190:21): [True: 4.15M, False: 30.9k]
  ------------------
  191|  4.15M|                    ai_real area = GeometryUtils::calculateAreaOfTriangle(face, mesh);
  192|  4.15M|                    if (area < ai_epsilon) {
  ------------------
  |  Branch (192:25): [True: 272k, False: 3.88M]
  ------------------
  193|   272k|                        if (mConfigRemoveDegenerates) {
  ------------------
  |  Branch (193:29): [True: 0, False: 272k]
  ------------------
  194|      0|                            remove_me[a] = true;
  195|      0|                            ++deg;
  196|      0|                            goto evil_jump_outside;
  197|      0|                        }
  198|       |
  199|       |                        // todo: check for index which is corrupt.
  200|   272k|                    }
  201|  4.15M|                }
  202|  4.18M|            }
  203|  4.18M|        }
  204|       |
  205|       |        // We need to update the primitive flags array of the mesh.
  206|  1.41M|        switch (face.mNumIndices) {
  207|  24.4k|        case 1u:
  ------------------
  |  Branch (207:9): [True: 24.4k, False: 1.38M]
  ------------------
  208|  24.4k|            mesh->mPrimitiveTypes |= aiPrimitiveType_POINT;
  209|  24.4k|            break;
  210|  3.47k|        case 2u:
  ------------------
  |  Branch (210:9): [True: 3.47k, False: 1.40M]
  ------------------
  211|  3.47k|            mesh->mPrimitiveTypes |= aiPrimitiveType_LINE;
  212|  3.47k|            break;
  213|  1.38M|        case 3u:
  ------------------
  |  Branch (213:9): [True: 1.38M, False: 27.8k]
  ------------------
  214|  1.38M|            mesh->mPrimitiveTypes |= aiPrimitiveType_TRIANGLE;
  215|  1.38M|            break;
  216|      0|        default:
  ------------------
  |  Branch (216:9): [True: 0, False: 1.41M]
  ------------------
  217|      0|            mesh->mPrimitiveTypes |= aiPrimitiveType_POLYGON;
  218|      0|            break;
  219|  1.41M|        };
  220|  1.41M|    evil_jump_outside:
  221|  1.41M|        continue;
  222|  1.41M|    }
  223|       |
  224|       |    // If AI_CONFIG_PP_FD_REMOVE is true, remove degenerated faces from the import
  225|  3.10k|    if (mConfigRemoveDegenerates && deg) {
  ------------------
  |  Branch (225:9): [True: 0, False: 3.10k]
  |  Branch (225:37): [True: 0, False: 0]
  ------------------
  226|      0|        unsigned int n = 0;
  227|      0|        for (unsigned int a = 0; a < mesh->mNumFaces; ++a) {
  ------------------
  |  Branch (227:34): [True: 0, False: 0]
  ------------------
  228|      0|            aiFace &face_src = mesh->mFaces[a];
  229|      0|            if (!remove_me[a]) {
  ------------------
  |  Branch (229:17): [True: 0, False: 0]
  ------------------
  230|      0|                aiFace &face_dest = mesh->mFaces[n++];
  231|       |
  232|       |                // Do a manual copy, keep the index array
  233|      0|                face_dest.mNumIndices = face_src.mNumIndices;
  234|      0|                face_dest.mIndices = face_src.mIndices;
  235|       |
  236|      0|                if (&face_src != &face_dest) {
  ------------------
  |  Branch (236:21): [True: 0, False: 0]
  ------------------
  237|       |                    // clear source
  238|      0|                    face_src.mNumIndices = 0;
  239|      0|                    face_src.mIndices = nullptr;
  240|      0|                }
  241|      0|            } else {
  242|       |                // Otherwise delete it if we don't need this face
  243|      0|                delete[] face_src.mIndices;
  244|      0|                face_src.mIndices = nullptr;
  245|      0|                face_src.mNumIndices = 0;
  246|      0|            }
  247|      0|        }
  248|       |        // Just leave the rest of the array unreferenced, we don't care for now
  249|      0|        mesh->mNumFaces = n;
  250|      0|        if (!mesh->mNumFaces) {
  ------------------
  |  Branch (250:13): [True: 0, False: 0]
  ------------------
  251|       |            // The whole mesh consists of degenerated faces
  252|       |            // signal upward, that this mesh should be deleted.
  253|      0|            ASSIMP_LOG_VERBOSE_DEBUG("FindDegeneratesProcess removed a mesh full of degenerated primitives");
  254|      0|            return true;
  255|      0|        }
  256|      0|    }
  257|       |
  258|  3.10k|    if (deg && !DefaultLogger::isNullLogger()) {
  ------------------
  |  Branch (258:9): [True: 735, False: 2.36k]
  |  Branch (258:16): [True: 0, False: 735]
  ------------------
  259|       |        ASSIMP_LOG_WARN("Found ", deg, " degenerated primitives");
  260|      0|    }
  261|  3.10k|    return false;
  262|  3.10k|}
FindDegenerates.cpp:_ZZN6Assimp22FindDegeneratesProcess13ExecuteOnMeshEP6aiMeshENK3$_0clEj:
  146|  12.5M|        auto vertex_in_range = [numVertices = mesh->mNumVertices](unsigned int vertex_idx) { return vertex_idx < numVertices; };

_ZN6Assimp20FindInstancesProcessC2Ev:
   58|    832|:   configSpeedFlag (false)
   59|    832|{}
_ZNK6Assimp20FindInstancesProcess8IsActiveEj:
   64|    371|{
   65|       |    // FindInstances makes absolutely no sense together with PreTransformVertices
   66|       |    // fixme: spawn error message somewhere else?
   67|    371|    return 0 != (pFlags & aiProcess_FindInstances) && 0 == (pFlags & aiProcess_PreTransformVertices);
  ------------------
  |  Branch (67:12): [True: 0, False: 371]
  |  Branch (67:55): [True: 0, False: 0]
  ------------------
   68|    371|}

_ZN6Assimp22FindInvalidDataProcessC2Ev:
   59|    832|        configEpsilon(0.0), mIgnoreTexCoods(false) {
   60|       |    // nothing to do here
   61|    832|}
_ZNK6Assimp22FindInvalidDataProcess8IsActiveEj:
   65|    368|bool FindInvalidDataProcess::IsActive(unsigned int pFlags) const {
   66|    368|    return 0 != (pFlags & aiProcess_FindInvalidData);
   67|    368|}
_ZN6Assimp22FindInvalidDataProcess15SetupPropertiesEPKNS_8ImporterE:
   71|    214|void FindInvalidDataProcess::SetupProperties(const Importer *pImp) {
   72|       |    // Get the current value of AI_CONFIG_PP_FID_ANIM_ACCURACY
   73|    214|    configEpsilon = (0 != pImp->GetPropertyFloat(AI_CONFIG_PP_FID_ANIM_ACCURACY, 0.f));
   74|       |    mIgnoreTexCoods = pImp->GetPropertyBool(AI_CONFIG_PP_FID_IGNORE_TEXTURECOORDS, false);
   75|    214|}
_Z20UpdateMeshReferencesP6aiNodeRKNSt3__16vectorIjNS1_9allocatorIjEEEE:
   79|  1.06k|void UpdateMeshReferences(aiNode *node, const std::vector<unsigned int> &meshMapping) {
   80|  1.06k|    if (node->mNumMeshes) {
  ------------------
  |  Branch (80:9): [True: 382, False: 685]
  ------------------
   81|    382|        unsigned int out = 0;
   82|    977|        for (unsigned int a = 0; a < node->mNumMeshes; ++a) {
  ------------------
  |  Branch (82:34): [True: 595, False: 382]
  ------------------
   83|       |
   84|    595|            unsigned int ref = node->mMeshes[a];
   85|    595|            if (ref >= meshMapping.size())
  ------------------
  |  Branch (85:17): [True: 0, False: 595]
  ------------------
   86|      0|                throw DeadlyImportError("Invalid mesh ref");
   87|       |
   88|    595|            if (UINT_MAX != (ref = meshMapping[ref])) {
  ------------------
  |  Branch (88:17): [True: 365, False: 230]
  ------------------
   89|    365|                node->mMeshes[out++] = ref;
   90|    365|            }
   91|    595|        }
   92|       |        // just let the members that are unused, that's much cheaper
   93|       |        // than a full array realloc'n'copy party ...
   94|    382|        node->mNumMeshes = out;
   95|    382|        if (0 == out) {
  ------------------
  |  Branch (95:13): [True: 48, False: 334]
  ------------------
   96|     48|            delete[] node->mMeshes;
   97|     48|            node->mMeshes = nullptr;
   98|     48|        }
   99|    382|    }
  100|       |    // recursively update all children
  101|  2.12k|    for (unsigned int i = 0; i < node->mNumChildren; ++i) {
  ------------------
  |  Branch (101:30): [True: 1.05k, False: 1.06k]
  ------------------
  102|  1.05k|        UpdateMeshReferences(node->mChildren[i], meshMapping);
  103|  1.05k|    }
  104|  1.06k|}
_ZN6Assimp22FindInvalidDataProcess7ExecuteEP7aiScene:
  108|    214|void FindInvalidDataProcess::Execute(aiScene *pScene) {
  109|    214|    ASSIMP_LOG_DEBUG("FindInvalidDataProcess begin");
  110|       |
  111|    214|    bool out = false;
  112|    214|    std::vector<unsigned int> meshMapping(pScene->mNumMeshes);
  113|    214|    unsigned int real = 0;
  114|       |
  115|       |    // Process meshes
  116|  4.02k|    for (unsigned int a = 0; a < pScene->mNumMeshes; a++) {
  ------------------
  |  Branch (116:30): [True: 3.80k, False: 214]
  ------------------
  117|  3.80k|        int result = ProcessMesh(pScene->mMeshes[a]);
  118|  3.80k|        if (0 == result) {
  ------------------
  |  Branch (118:13): [True: 3.45k, False: 353]
  ------------------
  119|  3.45k|            out = true;
  120|  3.45k|        }
  121|  3.80k|        if (2 == result) {
  ------------------
  |  Branch (121:13): [True: 236, False: 3.57k]
  ------------------
  122|       |            // remove this mesh
  123|    236|            delete pScene->mMeshes[a];
  124|    236|            pScene->mMeshes[a] = nullptr;
  125|       |
  126|    236|            meshMapping[a] = UINT_MAX;
  127|    236|            out = true;
  128|    236|            continue;
  129|    236|        }
  130|       |
  131|  3.57k|        pScene->mMeshes[real] = pScene->mMeshes[a];
  132|  3.57k|        meshMapping[a] = real++;
  133|  3.57k|    }
  134|       |
  135|       |    // Process animations
  136|    256|    for (unsigned int animIdx = 0; animIdx < pScene->mNumAnimations; ++animIdx) {
  ------------------
  |  Branch (136:36): [True: 42, False: 214]
  ------------------
  137|     42|        ProcessAnimation(pScene->mAnimations[animIdx]);
  138|     42|    }
  139|       |
  140|    214|    if (out) {
  ------------------
  |  Branch (140:9): [True: 173, False: 41]
  ------------------
  141|    173|        if (real != pScene->mNumMeshes) {
  ------------------
  |  Branch (141:13): [True: 16, False: 157]
  ------------------
  142|     16|            if (!real) {
  ------------------
  |  Branch (142:17): [True: 6, False: 10]
  ------------------
  143|      6|                throw DeadlyImportError("No meshes remaining");
  144|      6|            }
  145|       |
  146|       |            // we need to remove some meshes.
  147|       |            // therefore we'll also need to remove all references
  148|       |            // to them from the scenegraph
  149|     10|            try {
  150|     10|                UpdateMeshReferences(pScene->mRootNode, meshMapping);
  151|     10|            } catch (const std::exception&) {
  152|       |                // fix the real number of meshes otherwise we'll get double free in the scene destructor
  153|      0|                pScene->mNumMeshes = real;
  154|      0|                throw;
  155|      0|            }
  156|     10|            pScene->mNumMeshes = real;
  157|     10|        }
  158|       |
  159|    173|        ASSIMP_LOG_INFO("FindInvalidDataProcess finished. Found issues ...");
  160|    167|    } else {
  161|       |        ASSIMP_LOG_DEBUG("FindInvalidDataProcess finished. Everything seems to be OK.");
  162|     41|    }
  163|    214|}
_ZN6Assimp22FindInvalidDataProcess16ProcessAnimationEP11aiAnimation:
  265|     42|void FindInvalidDataProcess::ProcessAnimation(aiAnimation *anim) {
  266|       |    // Process all animation channels
  267|    668|    for (unsigned int a = 0; a < anim->mNumChannels; ++a) {
  ------------------
  |  Branch (267:30): [True: 626, False: 42]
  ------------------
  268|    626|        ProcessAnimationChannel(anim->mChannels[a]);
  269|    626|    }
  270|     42|}
_ZN6Assimp22FindInvalidDataProcess23ProcessAnimationChannelEP10aiNodeAnim:
  273|    626|void FindInvalidDataProcess::ProcessAnimationChannel(aiNodeAnim *anim) {
  274|    626|    ai_assert(nullptr != anim);
  275|    626|    if (anim->mNumPositionKeys == 0 && anim->mNumRotationKeys == 0 && anim->mNumScalingKeys == 0) {
  ------------------
  |  Branch (275:9): [True: 0, False: 626]
  |  Branch (275:40): [True: 0, False: 0]
  |  Branch (275:71): [True: 0, False: 0]
  ------------------
  276|      0|        ASSIMP_LOG_ERROR("Invalid node anuimation instance detected.");
  277|       |
  278|      0|        return;
  279|      0|    }
  280|       |
  281|       |    // Check whether all values in a tracks are identical - in this case
  282|       |    // we can remove al keys except one.
  283|       |    // POSITIONS
  284|    626|    int i = 0;
  285|    626|    if (anim->mNumPositionKeys > 1 && AllIdentical(anim->mPositionKeys, anim->mNumPositionKeys, configEpsilon)) {
  ------------------
  |  Branch (285:9): [True: 438, False: 188]
  |  Branch (285:39): [True: 380, False: 58]
  ------------------
  286|    380|        aiVectorKey v = anim->mPositionKeys[0];
  287|       |
  288|       |        // Reallocate ... we need just ONE element, it makes no sense to reuse the array
  289|    380|        delete[] anim->mPositionKeys;
  290|    380|        anim->mPositionKeys = new aiVectorKey[anim->mNumPositionKeys = 1];
  291|    380|        anim->mPositionKeys[0] = v;
  292|    380|        i = 1;
  293|    380|    }
  294|       |
  295|       |    // ROTATIONS
  296|    626|    if (anim->mNumRotationKeys > 1 && AllIdentical(anim->mRotationKeys, anim->mNumRotationKeys, configEpsilon)) {
  ------------------
  |  Branch (296:9): [True: 235, False: 391]
  |  Branch (296:39): [True: 47, False: 188]
  ------------------
  297|     47|        aiQuatKey v = anim->mRotationKeys[0];
  298|       |
  299|       |        // Reallocate ... we need just ONE element, it makes no sense to reuse the array
  300|     47|        delete[] anim->mRotationKeys;
  301|     47|        anim->mRotationKeys = new aiQuatKey[anim->mNumRotationKeys = 1];
  302|     47|        anim->mRotationKeys[0] = v;
  303|     47|        i = 1;
  304|     47|    }
  305|       |
  306|       |    // SCALINGS
  307|    626|    if (anim->mNumScalingKeys > 1 && AllIdentical(anim->mScalingKeys, anim->mNumScalingKeys, configEpsilon)) {
  ------------------
  |  Branch (307:9): [True: 81, False: 545]
  |  Branch (307:38): [True: 70, False: 11]
  ------------------
  308|     70|        aiVectorKey v = anim->mScalingKeys[0];
  309|       |
  310|       |        // Reallocate ... we need just ONE element, it makes no sense to reuse the array
  311|     70|        delete[] anim->mScalingKeys;
  312|     70|        anim->mScalingKeys = new aiVectorKey[anim->mNumScalingKeys = 1];
  313|     70|        anim->mScalingKeys[0] = v;
  314|     70|        i = 1;
  315|     70|    }
  316|    626|    if (1 == i) {
  ------------------
  |  Branch (316:9): [True: 383, False: 243]
  ------------------
  317|       |        ASSIMP_LOG_WARN("Simplified dummy tracks with just one key");
  318|    383|    }
  319|    626|}
_ZN6Assimp22FindInvalidDataProcess11ProcessMeshEP6aiMesh:
  323|  3.80k|int FindInvalidDataProcess::ProcessMesh(aiMesh *pMesh) {
  324|  3.80k|    bool ret = false;
  325|  3.80k|    std::vector<bool> dirtyMask(pMesh->mNumVertices, pMesh->mNumFaces != 0);
  326|       |
  327|       |    // Ignore elements that are not referenced by vertices.
  328|       |    // (they are, for example, caused by the FindDegenerates step)
  329|  1.41M|    for (unsigned int m = 0; m < pMesh->mNumFaces; ++m) {
  ------------------
  |  Branch (329:30): [True: 1.41M, False: 3.80k]
  ------------------
  330|  1.41M|        const aiFace &f = pMesh->mFaces[m];
  331|       |
  332|  5.59M|        for (unsigned int i = 0; i < f.mNumIndices; ++i) {
  ------------------
  |  Branch (332:34): [True: 4.18M, False: 1.41M]
  ------------------
  333|  4.18M|            dirtyMask[f.mIndices[i]] = false;
  334|  4.18M|        }
  335|  1.41M|    }
  336|       |
  337|       |    // Process vertex positions
  338|  3.80k|    if (pMesh->mVertices && ProcessArray(pMesh->mVertices, pMesh->mNumVertices, "positions", dirtyMask)) {
  ------------------
  |  Branch (338:9): [True: 3.80k, False: 0]
  |  Branch (338:29): [True: 236, False: 3.57k]
  ------------------
  339|    236|        ASSIMP_LOG_ERROR("Deleting mesh: Unable to continue without vertex positions");
  340|       |
  341|    236|        return 2;
  342|    236|    }
  343|       |
  344|       |    // process texture coordinates
  345|  3.57k|    if (!mIgnoreTexCoods) {
  ------------------
  |  Branch (345:9): [True: 3.57k, False: 0]
  ------------------
  346|  3.86k|        for (unsigned int i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS && pMesh->mTextureCoords[i]; ++i) {
  ------------------
  |  Branch (346:34): [True: 3.86k, False: 0]
  |  Branch (346:72): [True: 295, False: 3.57k]
  ------------------
  347|    295|            if (ProcessArray(pMesh->mTextureCoords[i], pMesh->mNumVertices, "uvcoords", dirtyMask)) {
  ------------------
  |  Branch (347:17): [True: 18, False: 277]
  ------------------
  348|     18|                pMesh->mNumUVComponents[i] = 0;
  349|       |
  350|       |                // delete all subsequent texture coordinate sets.
  351|    144|                for (unsigned int a = i + 1; a < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++a) {
  ------------------
  |  Branch (351:46): [True: 126, False: 18]
  ------------------
  352|    126|                    delete[] pMesh->mTextureCoords[a];
  353|    126|                    pMesh->mTextureCoords[a] = nullptr;
  354|    126|                    pMesh->mNumUVComponents[a] = 0;
  355|    126|                }
  356|       |
  357|     18|                ret = true;
  358|     18|            }
  359|    295|        }
  360|  3.57k|    }
  361|       |
  362|       |    // -- we don't validate vertex colors, it's difficult to say whether
  363|       |    // they are invalid or not.
  364|       |
  365|       |    // Normals and tangents are undefined for point and line faces.
  366|  3.57k|    if (pMesh->mNormals || pMesh->mTangents) {
  ------------------
  |  Branch (366:9): [True: 433, False: 3.13k]
  |  Branch (366:28): [True: 0, False: 3.13k]
  ------------------
  367|       |
  368|    433|        if (aiPrimitiveType_POINT & pMesh->mPrimitiveTypes ||
  ------------------
  |  Branch (368:13): [True: 13, False: 420]
  ------------------
  369|    420|                aiPrimitiveType_LINE & pMesh->mPrimitiveTypes) {
  ------------------
  |  Branch (369:17): [True: 19, False: 401]
  ------------------
  370|     32|            if (aiPrimitiveType_TRIANGLE & pMesh->mPrimitiveTypes ||
  ------------------
  |  Branch (370:17): [True: 0, False: 32]
  ------------------
  371|     32|                    aiPrimitiveType_POLYGON & pMesh->mPrimitiveTypes) {
  ------------------
  |  Branch (371:21): [True: 0, False: 32]
  ------------------
  372|       |                // We need to update the lookup-table
  373|      0|                for (unsigned int m = 0; m < pMesh->mNumFaces; ++m) {
  ------------------
  |  Branch (373:42): [True: 0, False: 0]
  ------------------
  374|      0|                    const aiFace &f = pMesh->mFaces[m];
  375|       |
  376|      0|                    if (f.mNumIndices < 3) {
  ------------------
  |  Branch (376:25): [True: 0, False: 0]
  ------------------
  377|      0|                        dirtyMask[f.mIndices[0]] = true;
  378|      0|                        if (f.mNumIndices == 2) {
  ------------------
  |  Branch (378:29): [True: 0, False: 0]
  ------------------
  379|      0|                            dirtyMask[f.mIndices[1]] = true;
  380|      0|                        }
  381|      0|                    }
  382|      0|                }
  383|      0|            }
  384|       |            // Normals, tangents and bitangents are undefined for
  385|       |            // the whole mesh (and should not even be there)
  386|     32|            else {
  387|     32|                return ret;
  388|     32|            }
  389|     32|        }
  390|       |
  391|       |        // Process mesh normals
  392|    401|        if (pMesh->mNormals && ProcessArray(pMesh->mNormals, pMesh->mNumVertices,
  ------------------
  |  Branch (392:13): [True: 401, False: 0]
  |  Branch (392:32): [True: 99, False: 302]
  ------------------
  393|    401|                                       "normals", dirtyMask, true, false))
  394|     99|            ret = true;
  395|       |
  396|       |        // Process mesh tangents
  397|    401|        if (pMesh->mTangents && ProcessArray(pMesh->mTangents, pMesh->mNumVertices, "tangents", dirtyMask)) {
  ------------------
  |  Branch (397:13): [True: 0, False: 401]
  |  Branch (397:33): [True: 0, False: 0]
  ------------------
  398|      0|            delete[] pMesh->mBitangents;
  399|      0|            pMesh->mBitangents = nullptr;
  400|      0|            ret = true;
  401|      0|        }
  402|       |
  403|       |        // Process mesh bitangents
  404|    401|        if (pMesh->mBitangents && ProcessArray(pMesh->mBitangents, pMesh->mNumVertices, "bitangents", dirtyMask)) {
  ------------------
  |  Branch (404:13): [True: 0, False: 401]
  |  Branch (404:35): [True: 0, False: 0]
  ------------------
  405|      0|            delete[] pMesh->mTangents;
  406|      0|            pMesh->mTangents = nullptr;
  407|      0|            ret = true;
  408|      0|        }
  409|    401|    }
  410|  3.54k|    return ret ? 1 : 0;
  ------------------
  |  Branch (410:12): [True: 116, False: 3.42k]
  ------------------
  411|  3.57k|}
_Z12AllIdenticalI11aiVectorKeyEbPT_jf:
  242|    519|inline bool AllIdentical(T *in, unsigned int num, ai_real epsilon) {
  243|    519|    if (num <= 1) {
  ------------------
  |  Branch (243:9): [True: 0, False: 519]
  ------------------
  244|      0|        return true;
  245|      0|    }
  246|       |
  247|    519|    if (fabs(epsilon) > 0.f) {
  ------------------
  |  Branch (247:9): [True: 0, False: 519]
  ------------------
  248|      0|        for (unsigned int i = 0; i < num - 1; ++i) {
  ------------------
  |  Branch (248:34): [True: 0, False: 0]
  ------------------
  249|      0|            if (!EpsilonCompare(in[i], in[i + 1], epsilon)) {
  ------------------
  |  Branch (249:17): [True: 0, False: 0]
  ------------------
  250|      0|                return false;
  251|      0|            }
  252|      0|        }
  253|    519|    } else {
  254|  2.68k|        for (unsigned int i = 0; i < num - 1; ++i) {
  ------------------
  |  Branch (254:34): [True: 2.23k, False: 450]
  ------------------
  255|  2.23k|            if (in[i] != in[i + 1]) {
  ------------------
  |  Branch (255:17): [True: 69, False: 2.16k]
  ------------------
  256|     69|                return false;
  257|     69|            }
  258|  2.23k|        }
  259|    519|    }
  260|    450|    return true;
  261|    519|}
_Z12AllIdenticalI9aiQuatKeyEbPT_jf:
  242|    235|inline bool AllIdentical(T *in, unsigned int num, ai_real epsilon) {
  243|    235|    if (num <= 1) {
  ------------------
  |  Branch (243:9): [True: 0, False: 235]
  ------------------
  244|      0|        return true;
  245|      0|    }
  246|       |
  247|    235|    if (fabs(epsilon) > 0.f) {
  ------------------
  |  Branch (247:9): [True: 0, False: 235]
  ------------------
  248|      0|        for (unsigned int i = 0; i < num - 1; ++i) {
  ------------------
  |  Branch (248:34): [True: 0, False: 0]
  ------------------
  249|      0|            if (!EpsilonCompare(in[i], in[i + 1], epsilon)) {
  ------------------
  |  Branch (249:17): [True: 0, False: 0]
  ------------------
  250|      0|                return false;
  251|      0|            }
  252|      0|        }
  253|    235|    } else {
  254|  1.00k|        for (unsigned int i = 0; i < num - 1; ++i) {
  ------------------
  |  Branch (254:34): [True: 959, False: 47]
  ------------------
  255|    959|            if (in[i] != in[i + 1]) {
  ------------------
  |  Branch (255:17): [True: 188, False: 771]
  ------------------
  256|    188|                return false;
  257|    188|            }
  258|    959|        }
  259|    235|    }
  260|     47|    return true;
  261|    235|}
_Z12ProcessArrayI10aiVector3tIfEEbRPT_jPKcRKNSt3__16vectorIbNS7_9allocatorIbEEEEbb:
  203|  4.50k|        const std::vector<bool> &dirtyMask, bool mayBeIdentical = false, bool mayBeZero = true) {
  204|  4.50k|    const char *err = ValidateArrayContents(in, num, dirtyMask, mayBeIdentical, mayBeZero);
  205|  4.50k|    if (err) {
  ------------------
  |  Branch (205:9): [True: 353, False: 4.15k]
  ------------------
  206|    353|        ASSIMP_LOG_ERROR("FindInvalidDataProcess fails on mesh ", name, ": ", err);
  207|    353|        delete[] in;
  208|    353|        in = nullptr;
  209|    353|        return true;
  210|    353|    }
  211|  4.15k|    return false;
  212|  4.50k|}
_Z21ValidateArrayContentsI10aiVector3tIfEEPKcPKT_jRKNSt3__16vectorIbNS7_9allocatorIbEEEEbb:
  175|  4.50k|        const std::vector<bool> &dirtyMask, bool mayBeIdentical, bool mayBeZero) {
  176|  4.50k|    bool b = false;
  177|  4.50k|    unsigned int cnt = 0;
  178|  4.55M|    for (unsigned int i = 0; i < size; ++i) {
  ------------------
  |  Branch (178:30): [True: 4.54M, False: 4.38k]
  ------------------
  179|       |
  180|  4.54M|        if (dirtyMask.size() && dirtyMask[i]) {
  ------------------
  |  Branch (180:13): [True: 4.54M, False: 0]
  |  Branch (180:13): [True: 3.70k, False: 4.54M]
  |  Branch (180:33): [True: 3.70k, False: 4.54M]
  ------------------
  181|  3.70k|            continue;
  182|  3.70k|        }
  183|  4.54M|        ++cnt;
  184|       |
  185|  4.54M|        const aiVector3D &v = arr[i];
  186|  4.54M|        if (is_special_float(v.x) || is_special_float(v.y) || is_special_float(v.z)) {
  ------------------
  |  Branch (186:13): [True: 20, False: 4.54M]
  |  Branch (186:38): [True: 0, False: 4.54M]
  |  Branch (186:63): [True: 0, False: 4.54M]
  ------------------
  187|     20|            return "INF/NAN was found in a vector component";
  188|     20|        }
  189|  4.54M|        if (!mayBeZero && !v.x && !v.y && !v.z) {
  ------------------
  |  Branch (189:13): [True: 1.15M, False: 3.38M]
  |  Branch (189:27): [True: 58.9k, False: 1.09M]
  |  Branch (189:35): [True: 20.5k, False: 38.3k]
  |  Branch (189:43): [True: 98, False: 20.4k]
  ------------------
  190|     98|            return "Found zero-length vector";
  191|     98|        }
  192|  4.54M|        if (i && v != arr[i - 1]) b = true;
  ------------------
  |  Branch (192:13): [True: 4.53M, False: 4.21k]
  |  Branch (192:18): [True: 4.03M, False: 508k]
  ------------------
  193|  4.54M|    }
  194|  4.38k|    if (cnt > 1 && !b && !mayBeIdentical) {
  ------------------
  |  Branch (194:9): [True: 4.07k, False: 315]
  |  Branch (194:20): [True: 245, False: 3.82k]
  |  Branch (194:26): [True: 235, False: 10]
  ------------------
  195|    235|        return "All vectors are identical";
  196|    235|    }
  197|  4.15k|    return nullptr;
  198|  4.38k|}

_ZNK6Assimp25FixInfacingNormalsProcess8IsActiveEj:
   61|    362|bool FixInfacingNormalsProcess::IsActive( unsigned int pFlags) const {
   62|    362|    return (pFlags & aiProcess_FixInfacingNormals) != 0;
   63|    362|}

_ZN6Assimp25FixInfacingNormalsProcessC2Ev:
   62|    832|    FixInfacingNormalsProcess() = default;

_ZNK6Assimp23GenBoundingBoxesProcess8IsActiveEj:
   51|    362|bool GenBoundingBoxesProcess::IsActive(unsigned int pFlags) const {
   52|    362|    return 0 != ( pFlags & aiProcess_GenBoundingBoxes );
   53|    362|}

_ZN6Assimp23GenBoundingBoxesProcessC2Ev:
   65|    832|    GenBoundingBoxesProcess() = default;

_ZNK6Assimp21GenFaceNormalsProcess8IsActiveEj:
   61|    362|bool GenFaceNormalsProcess::IsActive(unsigned int pFlags) const {
   62|    362|    force_ = (pFlags & aiProcess_ForceGenNormals) != 0;
   63|    362|    flippedWindingOrder_ = (pFlags & aiProcess_FlipWindingOrder) != 0;
   64|    362|    leftHanded_ = (pFlags & aiProcess_MakeLeftHanded) != 0;
   65|    362|    return (pFlags & aiProcess_GenNormals) != 0;
   66|    362|}

_ZN6Assimp21GenFaceNormalsProcessC2Ev:
   59|    832|    GenFaceNormalsProcess() = default;

_ZN6Assimp23GenVertexNormalsProcessC2Ev:
   57|    832|        configMaxAngle(AI_DEG_TO_RAD(175.f)) {
   58|       |    // empty
   59|    832|}
_ZNK6Assimp23GenVertexNormalsProcess8IsActiveEj:
   63|    362|bool GenVertexNormalsProcess::IsActive(unsigned int pFlags) const {
   64|    362|    force_ = (pFlags & aiProcess_ForceGenNormals) != 0;
   65|    362|    flippedWindingOrder_ = (pFlags & aiProcess_FlipWindingOrder) != 0;
   66|    362|    leftHanded_ = (pFlags & aiProcess_MakeLeftHanded) != 0;
   67|    362|    return (pFlags & aiProcess_GenSmoothNormals) != 0;
   68|    362|}
_ZN6Assimp23GenVertexNormalsProcess15SetupPropertiesEPKNS_8ImporterE:
   72|    208|void GenVertexNormalsProcess::SetupProperties(const Importer *pImp) {
   73|       |    // Get the current value of the AI_CONFIG_PP_GSN_MAX_SMOOTHING_ANGLE property
   74|    208|    configMaxAngle = pImp->GetPropertyFloat(AI_CONFIG_PP_GSN_MAX_SMOOTHING_ANGLE, (ai_real)175.0);
   75|       |    configMaxAngle = AI_DEG_TO_RAD(std::max(std::min(configMaxAngle, (ai_real)175.0), (ai_real)0.0));
   76|    208|}
_ZN6Assimp23GenVertexNormalsProcess7ExecuteEP7aiScene:
   80|    208|void GenVertexNormalsProcess::Execute(aiScene *pScene) {
   81|    208|    ASSIMP_LOG_DEBUG("GenVertexNormalsProcess begin");
   82|       |
   83|    208|    if (pScene->mFlags & AI_SCENE_FLAGS_NON_VERBOSE_FORMAT) {
  ------------------
  |  Branch (83:9): [True: 0, False: 208]
  ------------------
   84|      0|        throw DeadlyImportError("Post-processing order mismatch: expecting pseudo-indexed (\"verbose\") vertices here");
   85|      0|    }
   86|       |
   87|    208|    bool bHas = false;
   88|  3.78k|    for (unsigned int a = 0; a < pScene->mNumMeshes; ++a) {
  ------------------
  |  Branch (88:30): [True: 3.57k, False: 208]
  ------------------
   89|  3.57k|        if (GenMeshVertexNormals(pScene->mMeshes[a], a))
  ------------------
  |  Branch (89:13): [True: 2.21k, False: 1.35k]
  ------------------
   90|  2.21k|            bHas = true;
   91|  3.57k|    }
   92|       |
   93|    208|    if (bHas) {
  ------------------
  |  Branch (93:9): [True: 47, False: 161]
  ------------------
   94|     47|        ASSIMP_LOG_INFO("GenVertexNormalsProcess finished. "
   95|     47|                        "Vertex normals have been calculated");
   96|    161|    } else {
   97|       |        ASSIMP_LOG_DEBUG("GenVertexNormalsProcess finished. "
   98|    161|                         "Normals are already there");
   99|    161|    }
  100|    208|}
_ZN6Assimp23GenVertexNormalsProcess20GenMeshVertexNormalsEP6aiMeshj:
  104|  3.57k|bool GenVertexNormalsProcess::GenMeshVertexNormals(aiMesh *pMesh, unsigned int meshIndex) {
  105|  3.57k|    if (nullptr != pMesh->mNormals) {
  ------------------
  |  Branch (105:9): [True: 334, False: 3.23k]
  ------------------
  106|    334|        if (!force_) {
  ------------------
  |  Branch (106:13): [True: 334, False: 0]
  ------------------
  107|    334|            return false;
  108|    334|        }
  109|      0|        delete[] pMesh->mNormals;
  110|      0|        pMesh->mNormals = nullptr;
  111|      0|    }
  112|       |
  113|       |    // If the mesh consists of lines and/or points but not of
  114|       |    // triangles or higher-order polygons the normal vectors
  115|       |    // are undefined.
  116|  3.23k|    if (!(pMesh->mPrimitiveTypes & (aiPrimitiveType_TRIANGLE | aiPrimitiveType_POLYGON))) {
  ------------------
  |  Branch (116:9): [True: 1.02k, False: 2.21k]
  ------------------
  117|  1.02k|        ASSIMP_LOG_INFO("Normal vectors are undefined for line and point meshes");
  118|  1.02k|        return false;
  119|  1.02k|    }
  120|       |
  121|       |    // Allocate the array to hold the output normals
  122|  2.21k|    const float qnan = std::numeric_limits<ai_real>::quiet_NaN();
  123|  2.21k|    pMesh->mNormals = new aiVector3D[pMesh->mNumVertices];
  124|       |
  125|       |    // Compute per-face normals but store them per-vertex
  126|   865k|    for (unsigned int a = 0; a < pMesh->mNumFaces; a++) {
  ------------------
  |  Branch (126:30): [True: 862k, False: 2.21k]
  ------------------
  127|   862k|        const aiFace &face = pMesh->mFaces[a];
  128|   862k|        if (face.mNumIndices < 3) {
  ------------------
  |  Branch (128:13): [True: 0, False: 862k]
  ------------------
  129|       |            // either a point or a line -> no normal vector
  130|      0|            for (unsigned int i = 0; i < face.mNumIndices; ++i) {
  ------------------
  |  Branch (130:38): [True: 0, False: 0]
  ------------------
  131|      0|                pMesh->mNormals[face.mIndices[i]] = aiVector3D(qnan);
  132|      0|            }
  133|       |
  134|      0|            continue;
  135|      0|        }
  136|       |
  137|   862k|        const aiVector3D *pV1 = &pMesh->mVertices[face.mIndices[0]];
  138|   862k|        const aiVector3D *pV2 = &pMesh->mVertices[face.mIndices[1]];
  139|   862k|        const aiVector3D *pV3 = &pMesh->mVertices[face.mIndices[face.mNumIndices - 1]];
  140|       |        // Boolean XOR - if either but not both of these flags is set, then the winding order has
  141|       |        // changed and the cross product to calculate the normal needs to be reversed
  142|   862k|        if (flippedWindingOrder_ != leftHanded_) {
  ------------------
  |  Branch (142:13): [True: 0, False: 862k]
  ------------------
  143|      0|            std::swap(pV2, pV3);
  144|      0|        }
  145|   862k|        const aiVector3D vNor = ((*pV2 - *pV1) ^ (*pV3 - *pV1)).NormalizeSafe();
  146|       |
  147|  3.45M|        for (unsigned int i = 0; i < face.mNumIndices; ++i) {
  ------------------
  |  Branch (147:34): [True: 2.58M, False: 862k]
  ------------------
  148|  2.58M|            pMesh->mNormals[face.mIndices[i]] = vNor;
  149|  2.58M|        }
  150|   862k|    }
  151|       |
  152|       |    // Set up a SpatialSort to quickly find all vertices close to a given position
  153|       |    // check whether we can reuse the SpatialSort of a previous step.
  154|  2.21k|    SpatialSort *vertexFinder = nullptr;
  155|  2.21k|    SpatialSort _vertexFinder;
  156|  2.21k|    ai_real posEpsilon = ai_real(1e-5);
  157|  2.21k|    if (shared) {
  ------------------
  |  Branch (157:9): [True: 2.21k, False: 0]
  ------------------
  158|  2.21k|        std::vector<std::pair<SpatialSort, ai_real>> *avf;
  159|  2.21k|        shared->GetProperty(AI_SPP_SPATIAL_SORT, avf);
  ------------------
  |  |  166|  2.21k|#define AI_SPP_SPATIAL_SORT "$Spat"
  ------------------
  160|  2.21k|        if (avf) {
  ------------------
  |  Branch (160:13): [True: 2.21k, False: 0]
  ------------------
  161|  2.21k|            std::pair<SpatialSort, ai_real> &blubb = avf->operator[](meshIndex);
  162|  2.21k|            vertexFinder = &blubb.first;
  163|  2.21k|            posEpsilon = blubb.second;
  164|  2.21k|        }
  165|  2.21k|    }
  166|  2.21k|    if (!vertexFinder) {
  ------------------
  |  Branch (166:9): [True: 0, False: 2.21k]
  ------------------
  167|      0|        _vertexFinder.Fill(pMesh->mVertices, pMesh->mNumVertices, sizeof(aiVector3D));
  168|      0|        vertexFinder = &_vertexFinder;
  169|      0|        posEpsilon = ComputePositionEpsilon(pMesh);
  170|      0|    }
  171|  2.21k|    std::vector<unsigned int> verticesFound;
  172|  2.21k|    aiVector3D *pcNew = new aiVector3D[pMesh->mNumVertices];
  173|       |
  174|  2.21k|    if (configMaxAngle >= AI_DEG_TO_RAD(175.f)) {
  ------------------
  |  Branch (174:9): [True: 2.21k, False: 0]
  ------------------
  175|       |        // There is no angle limit. Thus all vertices with positions close
  176|       |        // to each other will receive the same vertex normal. This allows us
  177|       |        // to optimize the whole algorithm a little bit ...
  178|  2.21k|        std::vector<bool> abHad(pMesh->mNumVertices, false);
  179|  1.83M|        for (unsigned int i = 0; i < pMesh->mNumVertices; ++i) {
  ------------------
  |  Branch (179:34): [True: 1.83M, False: 2.21k]
  ------------------
  180|  1.83M|            if (abHad[i]) {
  ------------------
  |  Branch (180:17): [True: 1.41M, False: 423k]
  ------------------
  181|  1.41M|                continue;
  182|  1.41M|            }
  183|       |
  184|       |            // Get all vertices that share this one ...
  185|   423k|            vertexFinder->FindPositions(pMesh->mVertices[i], posEpsilon, verticesFound);
  186|       |
  187|   423k|            aiVector3D pcNor;
  188|  2.25M|            for (unsigned int a = 0; a < verticesFound.size(); ++a) {
  ------------------
  |  Branch (188:38): [True: 1.83M, False: 423k]
  ------------------
  189|  1.83M|                const aiVector3D &v = pMesh->mNormals[verticesFound[a]];
  190|  1.83M|                if (is_not_qnan(v.x)) pcNor += v;
  ------------------
  |  Branch (190:21): [True: 1.83M, False: 0]
  ------------------
  191|  1.83M|            }
  192|   423k|            pcNor.NormalizeSafe();
  193|       |
  194|       |            // Write the smoothed normal back to all affected normals
  195|  2.25M|            for (unsigned int a = 0; a < verticesFound.size(); ++a) {
  ------------------
  |  Branch (195:38): [True: 1.83M, False: 423k]
  ------------------
  196|  1.83M|                unsigned int vidx = verticesFound[a];
  197|  1.83M|                pcNew[vidx] = pcNor;
  198|  1.83M|                abHad[vidx] = true;
  199|  1.83M|            }
  200|   423k|        }
  201|  2.21k|    }
  202|       |    // Slower code path if a smooth angle is set. There are many ways to achieve
  203|       |    // the effect, this one is the most straightforward one.
  204|      0|    else {
  205|      0|        const ai_real fLimit = std::cos(configMaxAngle);
  206|      0|        for (unsigned int i = 0; i < pMesh->mNumVertices; ++i) {
  ------------------
  |  Branch (206:34): [True: 0, False: 0]
  ------------------
  207|       |            // Get all vertices that share this one ...
  208|      0|            vertexFinder->FindPositions(pMesh->mVertices[i], posEpsilon, verticesFound);
  209|       |
  210|      0|            aiVector3D vr = pMesh->mNormals[i];
  211|       |
  212|      0|            aiVector3D pcNor;
  213|      0|            for (unsigned int a = 0; a < verticesFound.size(); ++a) {
  ------------------
  |  Branch (213:38): [True: 0, False: 0]
  ------------------
  214|      0|                aiVector3D v = pMesh->mNormals[verticesFound[a]];
  215|       |
  216|       |                // Check whether the angle between the two normals is not too large.
  217|       |                // Skip the angle check on our own normal to avoid false negatives
  218|       |                // (v*v is not guaranteed to be 1.0 for all unit vectors v)
  219|      0|                if (is_not_qnan(v.x) && (verticesFound[a] == i || (v * vr >= fLimit)))
  ------------------
  |  Branch (219:21): [True: 0, False: 0]
  |  Branch (219:42): [True: 0, False: 0]
  |  Branch (219:67): [True: 0, False: 0]
  ------------------
  220|      0|                    pcNor += v;
  221|      0|            }
  222|      0|            pcNew[i] = pcNor.NormalizeSafe();
  223|      0|        }
  224|      0|    }
  225|       |
  226|  2.21k|    delete[] pMesh->mNormals;
  227|  2.21k|    pMesh->mNormals = pcNew;
  228|       |
  229|  2.21k|    return true;
  230|  3.23k|}

_ZN6Assimp27ImproveCacheLocalityProcessC2Ev:
   65|    832|        mConfigCacheDepth(PP_ICL_PTCACHE_SIZE) {
   66|       |    // empty
   67|    832|}
_ZNK6Assimp27ImproveCacheLocalityProcess8IsActiveEj:
   71|    362|bool ImproveCacheLocalityProcess::IsActive(unsigned int pFlags) const {
   72|    362|    return (pFlags & aiProcess_ImproveCacheLocality) != 0;
   73|    362|}
_ZN6Assimp27ImproveCacheLocalityProcess15SetupPropertiesEPKNS_8ImporterE:
   77|    208|void ImproveCacheLocalityProcess::SetupProperties(const Importer *pImp) {
   78|       |    // AI_CONFIG_PP_ICL_PTCACHE_SIZE controls the target cache size for the optimizer
   79|    208|    mConfigCacheDepth = pImp->GetPropertyInteger(AI_CONFIG_PP_ICL_PTCACHE_SIZE, PP_ICL_PTCACHE_SIZE);
   80|    208|}
_ZN6Assimp27ImproveCacheLocalityProcess7ExecuteEP7aiScene:
   84|    208|void ImproveCacheLocalityProcess::Execute(aiScene *pScene) {
   85|    208|    if (!pScene->mNumMeshes) {
  ------------------
  |  Branch (85:9): [True: 34, False: 174]
  ------------------
   86|     34|        ASSIMP_LOG_DEBUG("ImproveCacheLocalityProcess skipped; there are no meshes");
   87|     34|        return;
   88|     34|    }
   89|       |
   90|    208|    ASSIMP_LOG_DEBUG("ImproveCacheLocalityProcess begin");
   91|       |
   92|    174|    float out = 0.f;
   93|    174|    unsigned int numf = 0, numm = 0;
   94|  3.74k|    for (unsigned int a = 0; a < pScene->mNumMeshes; ++a) {
  ------------------
  |  Branch (94:30): [True: 3.57k, False: 174]
  ------------------
   95|  3.57k|        const float res = ProcessMesh(pScene->mMeshes[a], a);
   96|  3.57k|        if (res) {
  ------------------
  |  Branch (96:13): [True: 0, False: 3.57k]
  ------------------
   97|      0|            numf += pScene->mMeshes[a]->mNumFaces;
   98|      0|            out += res;
   99|      0|            ++numm;
  100|      0|        }
  101|  3.57k|    }
  102|    174|    if (!DefaultLogger::isNullLogger()) {
  ------------------
  |  Branch (102:9): [True: 0, False: 174]
  ------------------
  103|      0|        if (numf > 0) {
  ------------------
  |  Branch (103:13): [True: 0, False: 0]
  ------------------
  104|      0|            ASSIMP_LOG_INFO("Cache relevant are ", numm, " meshes (", numf, " faces). Average output ACMR is ", out / numf);
  105|      0|        }
  106|       |        ASSIMP_LOG_DEBUG("ImproveCacheLocalityProcess finished. ");
  107|      0|    }
  108|    174|}
_ZN6Assimp27ImproveCacheLocalityProcess11ProcessMeshEP6aiMeshj:
  157|  3.57k|ai_real ImproveCacheLocalityProcess::ProcessMesh(aiMesh *pMesh, unsigned int meshNum) {
  158|       |    // TODO: rewrite this to use std::vector or boost::shared_array
  159|  3.57k|    ai_assert(nullptr != pMesh);
  160|       |
  161|       |    // Check whether the input data is valid
  162|       |    // - there must be vertices and faces
  163|       |    // - all faces must be triangulated or we can't operate on them
  164|  3.57k|    if (!pMesh->HasFaces() || !pMesh->HasPositions())
  ------------------
  |  Branch (164:9): [True: 0, False: 3.57k]
  |  Branch (164:31): [True: 0, False: 3.57k]
  ------------------
  165|      0|        return static_cast<ai_real>(0.f);
  166|       |
  167|  3.57k|    if (pMesh->mPrimitiveTypes != aiPrimitiveType_TRIANGLE) {
  ------------------
  |  Branch (167:9): [True: 1.05k, False: 2.52k]
  ------------------
  168|  1.05k|        ASSIMP_LOG_ERROR("This algorithm works on triangle meshes only");
  169|  1.05k|        return static_cast<ai_real>(0.f);
  170|  1.05k|    }
  171|       |
  172|  2.52k|    if (pMesh->mNumVertices <= mConfigCacheDepth) {
  ------------------
  |  Branch (172:9): [True: 609, False: 1.91k]
  ------------------
  173|    609|        return static_cast<ai_real>(0.f);
  174|    609|    }
  175|       |
  176|  1.91k|    ai_real fACMR = 3.f;
  177|  1.91k|    const aiFace *const pcEnd = pMesh->mFaces + pMesh->mNumFaces;
  178|       |
  179|       |    // Input ACMR is for logging purposes only
  180|  1.91k|    if (!DefaultLogger::isNullLogger()) {
  ------------------
  |  Branch (180:9): [True: 0, False: 1.91k]
  ------------------
  181|      0|        fACMR = calculateInputACMR(pMesh, pcEnd, mConfigCacheDepth, meshNum);
  182|      0|    }
  183|       |
  184|       |    // first we need to build a vertex-triangle adjacency list
  185|  1.91k|    VertexTriangleAdjacency adj(pMesh->mFaces, pMesh->mNumFaces, pMesh->mNumVertices, true);
  186|       |
  187|       |    // build a list to store per-vertex caching time stamps
  188|  1.91k|    std::vector<unsigned int> piCachingStamps;
  189|  1.91k|    piCachingStamps.resize(pMesh->mNumVertices);
  190|  1.91k|    memset(&piCachingStamps[0], 0x0, pMesh->mNumVertices * sizeof(unsigned int));
  191|       |
  192|       |    // allocate an empty output index buffer. We store the output indices in one large array.
  193|       |    // Since the number of triangles won't change the input faces can be reused. This is how
  194|       |    // we save thousands of redundant mini allocations for aiFace::mIndices
  195|  1.91k|    const unsigned int iIdxCnt = pMesh->mNumFaces * 3;
  196|  1.91k|    std::vector<unsigned int> piIBOutput;
  197|  1.91k|    piIBOutput.resize(iIdxCnt);
  198|  1.91k|    std::vector<unsigned int>::iterator piCSIter = piIBOutput.begin();
  199|       |
  200|       |    // allocate the flag array to hold the information
  201|       |    // whether a face has already been emitted or not
  202|  1.91k|    std::vector<bool> abEmitted(pMesh->mNumFaces, false);
  203|       |
  204|       |    // dead-end vertex index stack
  205|  1.91k|    std::stack<unsigned int, std::vector<unsigned int>> sDeadEndVStack;
  206|       |
  207|       |    // create a copy of the piNumTriPtr buffer
  208|  1.91k|    unsigned int *const piNumTriPtr = adj.mLiveTriangles;
  209|  1.91k|    const std::vector<unsigned int> piNumTriPtrNoModify(piNumTriPtr, piNumTriPtr + pMesh->mNumVertices);
  210|       |
  211|       |    // get the largest number of referenced triangles and allocate the "candidate buffer"
  212|  1.91k|    unsigned int iMaxRefTris = 0;
  213|  1.91k|    {
  214|  1.91k|        const unsigned int *piCur = adj.mLiveTriangles;
  215|  1.91k|        const unsigned int *const piCurEnd = adj.mLiveTriangles + pMesh->mNumVertices;
  216|   740k|        for (; piCur != piCurEnd; ++piCur) {
  ------------------
  |  Branch (216:16): [True: 738k, False: 1.91k]
  ------------------
  217|   738k|            iMaxRefTris = std::max(iMaxRefTris, *piCur);
  218|   738k|        }
  219|  1.91k|    }
  220|  1.91k|    ai_assert(iMaxRefTris > 0);
  221|  1.91k|    std::vector<unsigned int> piCandidates;
  222|  1.91k|    piCandidates.resize(iMaxRefTris * 3);
  223|  1.91k|    unsigned int iCacheMisses = 0;
  224|       |
  225|       |    // ...................................................................................
  226|       |    /** PSEUDOCODE for the algorithm
  227|       |
  228|       |        A = Build-Adjacency(I) Vertex-triangle adjacency
  229|       |        L = Get-Triangle-Counts(A) Per-vertex live triangle counts
  230|       |        C = Zero(Vertex-Count(I)) Per-vertex caching time stamps
  231|       |        D = Empty-Stack() Dead-end vertex stack
  232|       |        E = False(Triangle-Count(I)) Per triangle emitted flag
  233|       |        O = Empty-Index-Buffer() Empty output buffer
  234|       |        f = 0 Arbitrary starting vertex
  235|       |        s = k+1, i = 1 Time stamp and cursor
  236|       |        while f >= 0 For all valid fanning vertices
  237|       |            N = Empty-Set() 1-ring of next candidates
  238|       |            for each Triangle t in Neighbors(A, f)
  239|       |                if !Emitted(E,t)
  240|       |                    for each Vertex v in t
  241|       |                        Append(O,v) Output vertex
  242|       |                        Push(D,v) Add to dead-end stack
  243|       |                        Insert(N,v) Register as candidate
  244|       |                        L[v] = L[v]-1 Decrease live triangle count
  245|       |                        if s-C[v] > k If not in cache
  246|       |                            C[v] = s Set time stamp
  247|       |                            s = s+1 Increment time stamp
  248|       |                    E[t] = true Flag triangle as emitted
  249|       |            Select next fanning vertex
  250|       |            f = Get-Next-Vertex(I,i,k,N,C,s,L,D)
  251|       |        return O
  252|       |        */
  253|       |    // ...................................................................................
  254|       |
  255|  1.91k|    int ivdx = 0;
  256|  1.91k|    int ics = 1;
  257|  1.91k|    int iStampCnt = mConfigCacheDepth + 1;
  258|   560k|    while (ivdx >= 0) {
  ------------------
  |  Branch (258:12): [True: 558k, False: 1.91k]
  ------------------
  259|       |
  260|   558k|        unsigned int icnt = piNumTriPtrNoModify[ivdx];
  261|   558k|        unsigned int *piList = adj.GetAdjacentTriangles(ivdx);
  262|   558k|        std::vector<unsigned int>::iterator piCurCandidate = piCandidates.begin();
  263|       |
  264|       |        // get all triangles in the neighborhood
  265|  3.88M|        for (unsigned int tri = 0; tri < icnt; ++tri) {
  ------------------
  |  Branch (265:36): [True: 3.32M, False: 558k]
  ------------------
  266|       |
  267|       |            // if they have not yet been emitted, add them to the output IB
  268|  3.32M|            const unsigned int fidx = *piList++;
  269|  3.32M|            if (!abEmitted[fidx]) {
  ------------------
  |  Branch (269:17): [True: 1.37M, False: 1.94M]
  ------------------
  270|       |
  271|       |                // so iterate through all vertices of the current triangle
  272|  1.37M|                const aiFace *pcFace = &pMesh->mFaces[fidx];
  273|  1.37M|                const unsigned nind = pcFace->mNumIndices;
  274|  5.51M|                for (unsigned ind = 0; ind < nind; ind++) {
  ------------------
  |  Branch (274:40): [True: 4.13M, False: 1.37M]
  ------------------
  275|  4.13M|                    unsigned dp = pcFace->mIndices[ind];
  276|       |
  277|       |                    // the current vertex won't have any free triangles after this step
  278|  4.13M|                    if (ivdx != (int)dp) {
  ------------------
  |  Branch (278:25): [True: 2.75M, False: 1.37M]
  ------------------
  279|       |                        // append the vertex to the dead-end stack
  280|  2.75M|                        sDeadEndVStack.push(dp);
  281|       |
  282|       |                        // register as candidate for the next step
  283|  2.75M|                        *piCurCandidate++ = dp;
  284|       |
  285|       |                        // decrease the per-vertex triangle counts
  286|  2.75M|                        piNumTriPtr[dp]--;
  287|  2.75M|                    }
  288|       |
  289|       |                    // append the vertex to the output index buffer
  290|  4.13M|                    *piCSIter++ = dp;
  291|       |
  292|       |                    // if the vertex is not yet in cache, set its cache count
  293|  4.13M|                    if (iStampCnt - piCachingStamps[dp] > mConfigCacheDepth) {
  ------------------
  |  Branch (293:25): [True: 997k, False: 3.13M]
  ------------------
  294|   997k|                        piCachingStamps[dp] = iStampCnt++;
  295|   997k|                        ++iCacheMisses;
  296|   997k|                    }
  297|  4.13M|                }
  298|       |                // flag triangle as emitted
  299|  1.37M|                abEmitted[fidx] = true;
  300|  1.37M|            }
  301|  3.32M|        }
  302|       |
  303|       |        // the vertex has now no living adjacent triangles anymore
  304|   558k|        piNumTriPtr[ivdx] = 0;
  305|       |
  306|       |        // get next fanning vertex
  307|   558k|        ivdx = -1;
  308|   558k|        int max_priority = -1;
  309|  3.31M|        for (std::vector<unsigned int>::iterator piCur = piCandidates.begin(); piCur != piCurCandidate; ++piCur) {
  ------------------
  |  Branch (309:80): [True: 2.75M, False: 558k]
  ------------------
  310|  2.75M|            const unsigned int dp = *piCur;
  311|       |
  312|       |            // must have live triangles
  313|  2.75M|            if (piNumTriPtr[dp] > 0) {
  ------------------
  |  Branch (313:17): [True: 2.52M, False: 228k]
  ------------------
  314|  2.52M|                int priority = 0;
  315|       |
  316|       |                // will the vertex be in cache, even after fanning occurs?
  317|  2.52M|                unsigned int tmp;
  318|  2.52M|                if ((tmp = iStampCnt - piCachingStamps[dp]) + 2 * piNumTriPtr[dp] <= mConfigCacheDepth) {
  ------------------
  |  Branch (318:21): [True: 2.01M, False: 509k]
  ------------------
  319|  2.01M|                    priority = tmp;
  320|  2.01M|                }
  321|       |
  322|       |                // keep best candidate
  323|  2.52M|                if (priority > max_priority) {
  ------------------
  |  Branch (323:21): [True: 896k, False: 1.63M]
  ------------------
  324|   896k|                    max_priority = priority;
  325|   896k|                    ivdx = dp;
  326|   896k|                }
  327|  2.52M|            }
  328|  2.75M|        }
  329|       |        // did we reach a dead end?
  330|   558k|        if (-1 == ivdx) {
  ------------------
  |  Branch (330:13): [True: 23.8k, False: 535k]
  ------------------
  331|       |            // need to get a non-local vertex for which we have a good chance that it is still
  332|       |            // in the cache ...
  333|  2.77M|            while (!sDeadEndVStack.empty()) {
  ------------------
  |  Branch (333:20): [True: 2.75M, False: 16.8k]
  ------------------
  334|  2.75M|                unsigned int iCachedIdx = sDeadEndVStack.top();
  335|  2.75M|                sDeadEndVStack.pop();
  336|  2.75M|                if (piNumTriPtr[iCachedIdx] > 0) {
  ------------------
  |  Branch (336:21): [True: 6.98k, False: 2.74M]
  ------------------
  337|  6.98k|                    ivdx = iCachedIdx;
  338|  6.98k|                    break;
  339|  6.98k|                }
  340|  2.75M|            }
  341|       |
  342|  23.8k|            if (-1 == ivdx) {
  ------------------
  |  Branch (342:17): [True: 16.8k, False: 6.98k]
  ------------------
  343|       |                // well, there isn't such a vertex. Simply get the next vertex in input order and
  344|       |                // hope it is not too bad ...
  345|   738k|                while (ics < (int)pMesh->mNumVertices) {
  ------------------
  |  Branch (345:24): [True: 736k, False: 1.91k]
  ------------------
  346|   736k|                    ++ics;
  347|   736k|                    if (piNumTriPtr[ics] > 0) {
  ------------------
  |  Branch (347:25): [True: 14.9k, False: 721k]
  ------------------
  348|  14.9k|                        ivdx = ics;
  349|  14.9k|                        break;
  350|  14.9k|                    }
  351|   736k|                }
  352|  16.8k|            }
  353|  23.8k|        }
  354|   558k|    }
  355|  1.91k|    ai_real fACMR2 = 0.0f;
  356|  1.91k|    if (!DefaultLogger::isNullLogger()) {
  ------------------
  |  Branch (356:9): [True: 0, False: 1.91k]
  ------------------
  357|      0|        fACMR2 = static_cast<ai_real>(iCacheMisses / pMesh->mNumFaces);
  358|      0|        const ai_real averageACMR = ((fACMR - fACMR2) / fACMR) * 100.f;
  359|       |        // very intense verbose logging ... prepare for much text if there are many meshes
  360|      0|        if (DefaultLogger::get()->getLogSeverity() == Logger::VERBOSE) {
  ------------------
  |  Branch (360:13): [True: 0, False: 0]
  ------------------
  361|      0|            ASSIMP_LOG_VERBOSE_DEBUG("Mesh ", meshNum, "| ACMR in: ", fACMR, " out: ", fACMR2, " | average ACMR ", averageACMR);
  362|      0|        }
  363|      0|        fACMR2 *= pMesh->mNumFaces;
  364|      0|    }
  365|       |
  366|       |    // sort the output index buffer back to the input array
  367|  1.91k|    piCSIter = piIBOutput.begin();
  368|  1.37M|    for (aiFace *pcFace = pMesh->mFaces; pcFace != pcEnd; ++pcFace) {
  ------------------
  |  Branch (368:42): [True: 1.37M, False: 1.91k]
  ------------------
  369|  1.37M|        unsigned nind = pcFace->mNumIndices;
  370|  1.37M|        unsigned *ind = pcFace->mIndices;
  371|  1.37M|        if (nind > 0)
  ------------------
  |  Branch (371:13): [True: 1.37M, False: 0]
  ------------------
  372|  1.37M|            ind[0] = *piCSIter++;
  373|  1.37M|        if (nind > 1)
  ------------------
  |  Branch (373:13): [True: 1.37M, False: 0]
  ------------------
  374|  1.37M|            ind[1] = *piCSIter++;
  375|  1.37M|        if (nind > 2)
  ------------------
  |  Branch (375:13): [True: 1.37M, False: 0]
  ------------------
  376|  1.37M|            ind[2] = *piCSIter++;
  377|  1.37M|    }
  378|       |
  379|  1.91k|    return fACMR2;
  380|  2.52k|}

_ZNK6Assimp19JoinVerticesProcess8IsActiveEj:
   63|    362|bool JoinVerticesProcess::IsActive( unsigned int pFlags) const {
   64|    362|    return (pFlags & aiProcess_JoinIdenticalVertices) != 0;
   65|    362|}
_ZN6Assimp19JoinVerticesProcess7ExecuteEP7aiScene:
   68|    208|void JoinVerticesProcess::Execute( aiScene* pScene) {
   69|    208|    ASSIMP_LOG_DEBUG("JoinVerticesProcess begin");
   70|       |
   71|       |    // get the total number of vertices BEFORE the step is executed
   72|    208|    int iNumOldVertices = 0;
   73|    208|    if (!DefaultLogger::isNullLogger()) {
  ------------------
  |  Branch (73:9): [True: 0, False: 208]
  ------------------
   74|      0|        for( unsigned int a = 0; a < pScene->mNumMeshes; a++)   {
  ------------------
  |  Branch (74:34): [True: 0, False: 0]
  ------------------
   75|      0|            iNumOldVertices +=  pScene->mMeshes[a]->mNumVertices;
   76|      0|        }
   77|      0|    }
   78|       |
   79|       |    // execute the step
   80|    208|    int iNumVertices = 0;
   81|  3.78k|    for( unsigned int a = 0; a < pScene->mNumMeshes; a++) {
  ------------------
  |  Branch (81:30): [True: 3.57k, False: 208]
  ------------------
   82|  3.57k|        iNumVertices += ProcessMesh( pScene->mMeshes[a],a);
   83|  3.57k|    }
   84|       |
   85|    208|    pScene->mFlags |= AI_SCENE_FLAGS_NON_VERBOSE_FORMAT;
   86|       |
   87|       |    // if logging is active, print detailed statistics
   88|    208|    if (!DefaultLogger::isNullLogger()) {
  ------------------
  |  Branch (88:9): [True: 0, False: 208]
  ------------------
   89|      0|        if (iNumOldVertices == iNumVertices) {
  ------------------
  |  Branch (89:13): [True: 0, False: 0]
  ------------------
   90|      0|            ASSIMP_LOG_DEBUG("JoinVerticesProcess finished ");
   91|      0|            return;
   92|      0|        }
   93|       |
   94|       |        // Show statistics
   95|      0|        ASSIMP_LOG_INFO("JoinVerticesProcess finished | Verts in: ", iNumOldVertices,
   96|      0|            " out: ", iNumVertices, " | ~",
   97|      0|            ((iNumOldVertices - iNumVertices) / (float)iNumOldVertices) * 100.f );
   98|      0|    }
   99|    208|}
_ZN6Assimp19JoinVerticesProcess11ProcessMeshEP6aiMeshj:
  225|  3.57k|int JoinVerticesProcess::ProcessMesh( aiMesh* pMesh, unsigned int meshIndex) {
  226|  3.57k|    static_assert( AI_MAX_NUMBER_OF_COLOR_SETS    == 8, "AI_MAX_NUMBER_OF_COLOR_SETS    == 8");
  227|  3.57k|	static_assert( AI_MAX_NUMBER_OF_TEXTURECOORDS == 8, "AI_MAX_NUMBER_OF_TEXTURECOORDS == 8");
  228|       |
  229|       |    // Return early if we don't have any positions
  230|  3.57k|    if (!pMesh->HasPositions() || !pMesh->HasFaces()) {
  ------------------
  |  Branch (230:9): [True: 0, False: 3.57k]
  |  Branch (230:35): [True: 0, False: 3.57k]
  ------------------
  231|      0|        return 0;
  232|      0|    }
  233|       |
  234|       |    // We should care only about used vertices, not all of them
  235|       |    // (this can happen due to original file vertices buffer being used by
  236|       |    // multiple meshes)
  237|  3.57k|    std::vector<bool> usedVertexIndicesMask;
  238|  3.57k|    usedVertexIndicesMask.resize(pMesh->mNumVertices, false);
  239|  1.41M|    for (unsigned int a = 0; a < pMesh->mNumFaces; a++) {
  ------------------
  |  Branch (239:30): [True: 1.41M, False: 3.57k]
  ------------------
  240|  1.41M|        aiFace& face = pMesh->mFaces[a];
  241|  5.59M|        for (unsigned int b = 0; b < face.mNumIndices; b++) {
  ------------------
  |  Branch (241:34): [True: 4.18M, False: 1.41M]
  ------------------
  242|  4.18M|            usedVertexIndicesMask[face.mIndices[b]] = true;
  243|  4.18M|        }
  244|  1.41M|    }
  245|       |
  246|       |    // We'll never have more vertices afterwards.
  247|  3.57k|    std::vector<int> uniqueVertices;
  248|       |
  249|       |    // For each vertex the index of the vertex it was replaced by.
  250|       |    // Since the maximal number of vertices is 2^31-1, the most significand bit can be used to mark
  251|       |    //  whether a new vertex was created for the index (true) or if it was replaced by an existing
  252|       |    //  unique vertex (false). This saves an additional std::vector<bool> and greatly enhances
  253|       |    //  branching performance.
  254|  3.57k|    static_assert(AI_MAX_VERTICES == 0x7fffffff, "AI_MAX_VERTICES == 0x7fffffff");
  255|  3.57k|    std::vector<unsigned int> replaceIndex( pMesh->mNumVertices, 0xffffffff);
  256|       |
  257|       |    // Run an optimized code path if we don't have multiple UVs or vertex colors.
  258|       |    // This should yield false in more than 99% of all imports ...
  259|  3.57k|    const bool hasAnimMeshes = pMesh->mNumAnimMeshes > 0;
  260|       |
  261|       |    // We'll never have more vertices afterwards.
  262|  3.57k|    std::vector<std::vector<int>> uniqueAnimatedVertices;
  263|  3.57k|    if (hasAnimMeshes) {
  ------------------
  |  Branch (263:9): [True: 0, False: 3.57k]
  ------------------
  264|      0|        uniqueAnimatedVertices.resize(pMesh->mNumAnimMeshes);
  265|      0|        for (unsigned int animMeshIndex = 0; animMeshIndex < pMesh->mNumAnimMeshes; animMeshIndex++) {
  ------------------
  |  Branch (265:46): [True: 0, False: 0]
  ------------------
  266|      0|            uniqueAnimatedVertices[animMeshIndex].reserve(pMesh->mNumVertices);
  267|      0|        }
  268|      0|    }
  269|       |    // a map that maps a vertex to its new index
  270|  3.57k|    std::unordered_map<Vertex, int, HashVertex, CompareVerticesAlmostEqual> vertex2Index = {};
  271|       |    // we can not end up with more vertices than we started with
  272|       |    // Now check each vertex if it brings something new to the table
  273|  3.57k|    int newIndex = 0;
  274|  3.01M|    for( unsigned int a = 0; a < pMesh->mNumVertices; a++)  {
  ------------------
  |  Branch (274:30): [True: 3.01M, False: 3.57k]
  ------------------
  275|       |        // if the vertex is unused Do nothing
  276|  3.01M|        if (!usedVertexIndicesMask[a]) {
  ------------------
  |  Branch (276:13): [True: 3.35k, False: 3.01M]
  ------------------
  277|  3.35k|            continue;
  278|  3.35k|        }
  279|       |        // collect the vertex data
  280|  3.01M|        Vertex v(pMesh,a);
  281|       |        // is the vertex already in the map?
  282|  3.01M|        auto it = vertex2Index.find(v);
  283|       |        // if the vertex is not in the map then it is a new vertex add it.
  284|  3.01M|        if (it == vertex2Index.end()) {
  ------------------
  |  Branch (284:13): [True: 744k, False: 2.26M]
  ------------------
  285|       |            // this is a new vertex give it a new index
  286|   744k|            vertex2Index.emplace(v, newIndex);
  287|       |            // keep track of its index and increment 1
  288|   744k|            replaceIndex[a] = newIndex++;
  289|       |            // add the vertex to the unique vertices
  290|   744k|            uniqueVertices.push_back(a);
  291|   744k|            if (hasAnimMeshes) {
  ------------------
  |  Branch (291:17): [True: 0, False: 744k]
  ------------------
  292|      0|                for (unsigned int animMeshIndex = 0; animMeshIndex < pMesh->mNumAnimMeshes; animMeshIndex++) {
  ------------------
  |  Branch (292:54): [True: 0, False: 0]
  ------------------
  293|      0|                    uniqueAnimatedVertices[animMeshIndex].emplace_back(a);
  294|      0|                }
  295|      0|            }
  296|  2.26M|        } else{
  297|       |            // if the vertex is already there just find the replace index that is appropriate to it
  298|       |			// mark it with JOINED_VERTICES_MARK
  299|  2.26M|            replaceIndex[a] = it->second | JOINED_VERTICES_MARK;
  300|  2.26M|        }
  301|  3.01M|    }
  302|       |
  303|  3.57k|    if (!DefaultLogger::isNullLogger() && DefaultLogger::get()->getLogSeverity() == Logger::VERBOSE)    {
  ------------------
  |  Branch (303:9): [True: 0, False: 3.57k]
  |  Branch (303:43): [True: 0, False: 0]
  ------------------
  304|      0|        ASSIMP_LOG_VERBOSE_DEBUG(
  ------------------
  |  Branch (304:9): [True: 0, False: 0]
  ------------------
  305|      0|            "Mesh ",meshIndex,
  306|      0|            " (",
  307|      0|            (pMesh->mName.length ? pMesh->mName.data : "unnamed"),
  308|      0|            ") | Verts in: ",pMesh->mNumVertices,
  309|      0|            " out: ",
  310|      0|            uniqueVertices.size(),
  311|      0|            " | ~",
  312|      0|            ((pMesh->mNumVertices - uniqueVertices.size()) / (float)pMesh->mNumVertices) * 100.f,
  313|      0|            "%"
  314|      0|        );
  315|      0|    }
  316|       |
  317|  3.57k|    updateXMeshVertices(pMesh, uniqueVertices);
  318|  3.57k|    if (hasAnimMeshes) {
  ------------------
  |  Branch (318:9): [True: 0, False: 3.57k]
  ------------------
  319|      0|        for (unsigned int animMeshIndex = 0; animMeshIndex < pMesh->mNumAnimMeshes; animMeshIndex++) {
  ------------------
  |  Branch (319:46): [True: 0, False: 0]
  ------------------
  320|      0|            updateXMeshVertices(pMesh->mAnimMeshes[animMeshIndex], uniqueAnimatedVertices[animMeshIndex]);
  321|      0|        }
  322|      0|    }
  323|       |
  324|       |    // adjust the indices in all faces
  325|  1.41M|    for( unsigned int a = 0; a < pMesh->mNumFaces; a++) {
  ------------------
  |  Branch (325:30): [True: 1.41M, False: 3.57k]
  ------------------
  326|  1.41M|        aiFace& face = pMesh->mFaces[a];
  327|  5.59M|        for( unsigned int b = 0; b < face.mNumIndices; b++) {
  ------------------
  |  Branch (327:34): [True: 4.18M, False: 1.41M]
  ------------------
  328|  4.18M|            face.mIndices[b] = replaceIndex[face.mIndices[b]] & ~JOINED_VERTICES_MARK;
  329|  4.18M|        }
  330|  1.41M|    }
  331|       |
  332|       |    // adjust bone vertex weights.
  333|  6.66k|    for( int a = 0; a < (int)pMesh->mNumBones; a++) {
  ------------------
  |  Branch (333:21): [True: 3.08k, False: 3.57k]
  ------------------
  334|  3.08k|        aiBone* bone = pMesh->mBones[a];
  335|  3.08k|        std::vector<aiVertexWeight> newWeights;
  336|  3.08k|        newWeights.reserve( bone->mNumWeights);
  337|       |
  338|  3.08k|        if (nullptr != bone->mWeights) {
  ------------------
  |  Branch (338:13): [True: 3.08k, False: 0]
  ------------------
  339|  88.4k|            for ( unsigned int b = 0; b < bone->mNumWeights; b++ ) {
  ------------------
  |  Branch (339:39): [True: 85.3k, False: 3.08k]
  ------------------
  340|  85.3k|                const aiVertexWeight& ow = bone->mWeights[ b ];
  341|       |                // if the vertex is a unique one, translate it
  342|       |				// filter out joined vertices by JOINED_VERTICES_MARK.
  343|  85.3k|                if ( !( replaceIndex[ ow.mVertexId ] & JOINED_VERTICES_MARK ) ) {
  ------------------
  |  Branch (343:22): [True: 18.5k, False: 66.7k]
  ------------------
  344|  18.5k|                    aiVertexWeight nw;
  345|  18.5k|                    nw.mVertexId = replaceIndex[ ow.mVertexId ];
  346|  18.5k|                    nw.mWeight = ow.mWeight;
  347|  18.5k|                    newWeights.push_back( nw );
  348|  18.5k|                }
  349|  85.3k|            }
  350|  3.08k|        } else {
  351|      0|            ASSIMP_LOG_ERROR( "X-Export: aiBone shall contain weights, but pointer to them is nullptr." );
  352|      0|        }
  353|       |
  354|  3.08k|        if (newWeights.size() > 0) {
  ------------------
  |  Branch (354:13): [True: 193, False: 2.89k]
  ------------------
  355|       |            // kill the old and replace them with the translated weights
  356|    193|            delete [] bone->mWeights;
  357|    193|            bone->mNumWeights = (unsigned int)newWeights.size();
  358|       |
  359|    193|            bone->mWeights = new aiVertexWeight[bone->mNumWeights];
  360|    193|            memcpy( bone->mWeights, &newWeights[0], bone->mNumWeights * sizeof( aiVertexWeight));
  361|    193|        }
  362|  3.08k|    }
  363|  3.57k|    return pMesh->mNumVertices;
  364|  3.57k|}
JoinVerticesProcess.cpp:_ZNK12_GLOBAL__N_110HashVertexclERKN6Assimp6VertexE:
  151|  3.75M|    size_t operator () (const Vertex & v) const {
  152|  3.75M|        size_t hash = 0;
  153|       |
  154|  3.75M|        hash_combine(hash, v.position.x);
  155|  3.75M|        hash_combine(hash, v.position.y);
  156|  3.75M|        hash_combine(hash, v.position.z);
  157|       |
  158|  3.75M|        return hash;
  159|  3.75M|    }
JoinVerticesProcess.cpp:_ZNK12_GLOBAL__N_110HashVertex12hash_combineERmRKf:
  146|  11.2M|    inline void hash_combine(std::size_t& seed, const ai_real& v) const {
  147|  11.2M|        std::hash<ai_real> hasher;
  148|  11.2M|        seed ^= hasher(v) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
  149|  11.2M|    }
JoinVerticesProcess.cpp:_ZNK12_GLOBAL__N_126CompareVerticesAlmostEqualclERKN6Assimp6VertexES4_:
  104|  2.52M|    bool operator () (const Vertex & a, const Vertex & b) const {
  105|  2.52M|        static const float epsilon = 1e-5f;
  106|  2.52M|        static const float squareEpsilon = epsilon * epsilon;
  107|       |
  108|  2.52M|        if ((a.position - b.position).SquareLength() > squareEpsilon) {
  ------------------
  |  Branch (108:13): [True: 108, False: 2.52M]
  ------------------
  109|    108|            return false;
  110|    108|        }
  111|       |
  112|       |        // We just test the other attributes even if they're not present in the mesh.
  113|       |        // In this case they're initialized to 0 so the comparison succeeds.
  114|       |        // By this method the non-present attributes are effectively ignored in the comparison.
  115|       |
  116|  2.52M|        if ((a.normal - b.normal).SquareLength() > squareEpsilon) {
  ------------------
  |  Branch (116:13): [True: 201k, False: 2.32M]
  ------------------
  117|   201k|            return false;
  118|   201k|        }
  119|       |
  120|  2.32M|        if ((a.tangent - b.tangent).SquareLength() > squareEpsilon) {
  ------------------
  |  Branch (120:13): [True: 47.9k, False: 2.27M]
  ------------------
  121|  47.9k|            return false;
  122|  47.9k|        }
  123|       |
  124|  2.27M|        if ((a.bitangent - b.bitangent).SquareLength() > squareEpsilon) {
  ------------------
  |  Branch (124:13): [True: 711, False: 2.27M]
  ------------------
  125|    711|            return false;
  126|    711|        }
  127|       |
  128|  20.4M|        for (uint32_t i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS; i ++) {
  ------------------
  |  Branch (128:30): [True: 18.1M, False: 2.26M]
  ------------------
  129|  18.1M|            if ((a.texcoords[i] - b.texcoords[i]).SquareLength() > squareEpsilon) {
  ------------------
  |  Branch (129:17): [True: 7.25k, False: 18.1M]
  ------------------
  130|  7.25k|                return false;
  131|  7.25k|            }
  132|  18.1M|        }
  133|       |
  134|  20.4M|        for (uint32_t i = 0; i < AI_MAX_NUMBER_OF_COLOR_SETS; i ++) {
  ------------------
  |  Branch (134:30): [True: 18.1M, False: 2.26M]
  ------------------
  135|  18.1M|            if (GetColorDifference(a.colors[i], b.colors[i]) > squareEpsilon) {
  ------------------
  |  Branch (135:17): [True: 509, False: 18.1M]
  ------------------
  136|    509|                return false;
  137|    509|            }
  138|  18.1M|        }
  139|       |
  140|       |        // If reached this point, they are ~equal
  141|  2.26M|        return true;
  142|  2.26M|    }
JoinVerticesProcess.cpp:_ZN12_GLOBAL__N_119updateXMeshVerticesI6aiMeshEEvPT_RNSt3__16vectorIiNS4_9allocatorIiEEEE:
  163|  3.57k|void updateXMeshVertices(XMesh *pMesh, std::vector<int> &uniqueVertices) {
  164|       |    // replace vertex data with the unique data sets
  165|  3.57k|    pMesh->mNumVertices = (unsigned int)uniqueVertices.size();
  166|       |
  167|       |    // ----------------------------------------------------------------------------
  168|       |    // NOTE - we're *not* calling Vertex::SortBack() because it would check for
  169|       |    // presence of every single vertex component once PER VERTEX. And our CPU
  170|       |    // dislikes branches, even if they're easily predictable.
  171|       |    // ----------------------------------------------------------------------------
  172|       |
  173|       |    // Position, if present (check made for aiAnimMesh)
  174|  3.57k|    if (pMesh->mVertices) {
  ------------------
  |  Branch (174:9): [True: 3.57k, False: 0]
  ------------------
  175|  3.57k|        std::unique_ptr<aiVector3D[]> oldVertices(pMesh->mVertices);
  176|  3.57k|        pMesh->mVertices = new aiVector3D[pMesh->mNumVertices];
  177|   748k|        for (unsigned int a = 0; a < pMesh->mNumVertices; a++)
  ------------------
  |  Branch (177:34): [True: 744k, False: 3.57k]
  ------------------
  178|   744k|            pMesh->mVertices[a] = oldVertices[uniqueVertices[a]];
  179|  3.57k|    }
  180|       |
  181|       |    // Normals, if present
  182|  3.57k|    if (pMesh->mNormals) {
  ------------------
  |  Branch (182:9): [True: 2.55k, False: 1.02k]
  ------------------
  183|  2.55k|        std::unique_ptr<aiVector3D[]> oldNormals(pMesh->mNormals);
  184|  2.55k|        pMesh->mNormals = new aiVector3D[pMesh->mNumVertices];
  185|   744k|        for (unsigned int a = 0; a < pMesh->mNumVertices; a++)
  ------------------
  |  Branch (185:34): [True: 741k, False: 2.55k]
  ------------------
  186|   741k|            pMesh->mNormals[a] = oldNormals[uniqueVertices[a]];
  187|  2.55k|    }
  188|       |    // Tangents, if present
  189|  3.57k|    if (pMesh->mTangents) {
  ------------------
  |  Branch (189:9): [True: 259, False: 3.31k]
  ------------------
  190|    259|        std::unique_ptr<aiVector3D[]> oldTangents(pMesh->mTangents);
  191|    259|        pMesh->mTangents = new aiVector3D[pMesh->mNumVertices];
  192|   108k|        for (unsigned int a = 0; a < pMesh->mNumVertices; a++)
  ------------------
  |  Branch (192:34): [True: 108k, False: 259]
  ------------------
  193|   108k|            pMesh->mTangents[a] = oldTangents[uniqueVertices[a]];
  194|    259|    }
  195|       |    // Bitangents as well
  196|  3.57k|    if (pMesh->mBitangents) {
  ------------------
  |  Branch (196:9): [True: 259, False: 3.31k]
  ------------------
  197|    259|        std::unique_ptr<aiVector3D[]> oldBitangents(pMesh->mBitangents);
  198|    259|        pMesh->mBitangents = new aiVector3D[pMesh->mNumVertices];
  199|   108k|        for (unsigned int a = 0; a < pMesh->mNumVertices; a++)
  ------------------
  |  Branch (199:34): [True: 108k, False: 259]
  ------------------
  200|   108k|            pMesh->mBitangents[a] = oldBitangents[uniqueVertices[a]];
  201|    259|    }
  202|       |    // Vertex colors
  203|  3.78k|    for (unsigned int a = 0; pMesh->HasVertexColors(a); a++) {
  ------------------
  |  Branch (203:30): [True: 216, False: 3.57k]
  ------------------
  204|    216|        std::unique_ptr<aiColor4D[]> oldColors(pMesh->mColors[a]);
  205|    216|        pMesh->mColors[a] = new aiColor4D[pMesh->mNumVertices];
  206|  4.87k|        for (unsigned int b = 0; b < pMesh->mNumVertices; b++)
  ------------------
  |  Branch (206:34): [True: 4.66k, False: 216]
  ------------------
  207|  4.66k|            pMesh->mColors[a][b] = oldColors[uniqueVertices[b]];
  208|    216|    }
  209|       |    // Texture coords
  210|  3.84k|    for (unsigned int a = 0; pMesh->HasTextureCoords(a); a++) {
  ------------------
  |  Branch (210:30): [True: 277, False: 3.57k]
  ------------------
  211|    277|        std::unique_ptr<aiVector3D[]> oldTextureCoords(pMesh->mTextureCoords[a]);
  212|    277|        pMesh->mTextureCoords[a] = new aiVector3D[pMesh->mNumVertices];
  213|   110k|        for (unsigned int b = 0; b < pMesh->mNumVertices; b++)
  ------------------
  |  Branch (213:34): [True: 110k, False: 277]
  ------------------
  214|   110k|            pMesh->mTextureCoords[a][b] = oldTextureCoords[uniqueVertices[b]];
  215|    277|    }
  216|  3.57k|}

_ZN6Assimp19JoinVerticesProcessC2Ev:
   67|    832|    JoinVerticesProcess() = default;

_ZN6Assimp23LimitBoneWeightsProcessC2Ev:
   57|    832|        mMaxWeights(AI_LMW_MAX_WEIGHTS), mRemoveEmptyBones(true) {
   58|       |    // empty
   59|    832|}
_ZNK6Assimp23LimitBoneWeightsProcess8IsActiveEj:
   63|    362|bool LimitBoneWeightsProcess::IsActive( unsigned int pFlags) const {
   64|    362|    return (pFlags & aiProcess_LimitBoneWeights) != 0;
   65|    362|}
_ZN6Assimp23LimitBoneWeightsProcess7ExecuteEP7aiScene:
   69|    208|void LimitBoneWeightsProcess::Execute( aiScene* pScene) {
   70|    208|    ai_assert(pScene != nullptr);
   71|       |
   72|    208|    ASSIMP_LOG_DEBUG("LimitBoneWeightsProcess begin");
   73|       |
   74|  3.78k|    for (unsigned int m = 0; m < pScene->mNumMeshes; ++m) {
  ------------------
  |  Branch (74:30): [True: 3.57k, False: 208]
  ------------------
   75|  3.57k|        ProcessMesh(pScene->mMeshes[m]);
   76|  3.57k|    }
   77|       |
   78|       |    ASSIMP_LOG_DEBUG("LimitBoneWeightsProcess end");
   79|    208|}
_ZN6Assimp23LimitBoneWeightsProcess15SetupPropertiesEPKNS_8ImporterE:
   83|    208|void LimitBoneWeightsProcess::SetupProperties(const Importer* pImp) {
   84|    208|    this->mMaxWeights = pImp->GetPropertyInteger(AI_CONFIG_PP_LBW_MAX_WEIGHTS,AI_LMW_MAX_WEIGHTS);
   85|       |    this->mRemoveEmptyBones = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_REMOVE_EMPTY_BONES, 1) != 0;
   86|    208|}
_ZN6Assimp23LimitBoneWeightsProcess11ProcessMeshEP6aiMesh:
  107|  3.57k|void LimitBoneWeightsProcess::ProcessMesh(aiMesh* pMesh) {
  108|  3.57k|    if (!pMesh->HasBones())
  ------------------
  |  Branch (108:9): [True: 3.54k, False: 27]
  ------------------
  109|  3.54k|        return;
  110|       |
  111|       |    // collect all bone weights per vertex
  112|     27|    typedef SmallVector<Weight,8> VertexWeightArray;
  113|     27|    typedef std::vector<VertexWeightArray> WeightsPerVertex;
  114|     27|    WeightsPerVertex vertexWeights(pMesh->mNumVertices);
  115|     27|    size_t maxVertexWeights = 0;
  116|       |
  117|  3.11k|    for (unsigned int b = 0; b < pMesh->mNumBones; ++b) {
  ------------------
  |  Branch (117:30): [True: 3.08k, False: 27]
  ------------------
  118|  3.08k|        const aiBone* bone = pMesh->mBones[b];
  119|  44.8k|        for (unsigned int w = 0; w < bone->mNumWeights; ++w) {
  ------------------
  |  Branch (119:34): [True: 41.7k, False: 3.08k]
  ------------------
  120|  41.7k|            const aiVertexWeight& vw = bone->mWeights[w];
  121|       |
  122|  41.7k|            if (vertexWeights.size() <= vw.mVertexId)
  ------------------
  |  Branch (122:17): [True: 23.1k, False: 18.5k]
  ------------------
  123|  23.1k|                continue;
  124|       |
  125|  18.5k|            vertexWeights[vw.mVertexId].push_back(Weight(b, vw.mWeight));
  126|  18.5k|            maxVertexWeights = std::max(maxVertexWeights, vertexWeights[vw.mVertexId].size());
  127|  18.5k|        }
  128|  3.08k|    }
  129|       |
  130|     27|    if (maxVertexWeights <= mMaxWeights)
  ------------------
  |  Branch (130:9): [True: 27, False: 0]
  ------------------
  131|     27|        return;
  132|       |
  133|      0|    unsigned int removed = 0, old_bones = pMesh->mNumBones;
  134|       |
  135|       |    // now cut the weight count if it exceeds the maximum
  136|      0|    for (WeightsPerVertex::iterator vit = vertexWeights.begin(); vit != vertexWeights.end(); ++vit) {
  ------------------
  |  Branch (136:66): [True: 0, False: 0]
  ------------------
  137|      0|        if (vit->size() <= mMaxWeights)
  ------------------
  |  Branch (137:13): [True: 0, False: 0]
  ------------------
  138|      0|            continue;
  139|       |
  140|       |        // more than the defined maximum -> first sort by weight in descending order. That's
  141|       |        // why we defined the < operator in such a weird way.
  142|      0|        std::sort(vit->begin(), vit->end());
  143|       |
  144|       |        // now kill everything beyond the maximum count
  145|      0|        unsigned int m = static_cast<unsigned int>(vit->size());
  146|      0|        vit->resize(mMaxWeights);
  147|      0|        removed += static_cast<unsigned int>(m - vit->size());
  148|       |
  149|       |        // and renormalize the weights
  150|      0|        float sum = 0.0f;
  151|      0|        for(const Weight* it = vit->begin(); it != vit->end(); ++it) {
  ------------------
  |  Branch (151:46): [True: 0, False: 0]
  ------------------
  152|      0|            sum += it->mWeight;
  153|      0|        }
  154|      0|        if (0.0f != sum) {
  ------------------
  |  Branch (154:13): [True: 0, False: 0]
  ------------------
  155|      0|            const float invSum = 1.0f / sum;
  156|      0|            for(Weight* it = vit->begin(); it != vit->end(); ++it) {
  ------------------
  |  Branch (156:44): [True: 0, False: 0]
  ------------------
  157|      0|                it->mWeight *= invSum;
  158|      0|            }
  159|      0|        }
  160|      0|    }
  161|       |
  162|       |    // clear weight count for all bone
  163|      0|    for (unsigned int a = 0; a < pMesh->mNumBones; ++a) {
  ------------------
  |  Branch (163:30): [True: 0, False: 0]
  ------------------
  164|      0|        pMesh->mBones[a]->mNumWeights = 0;
  165|      0|    }
  166|       |
  167|       |    // rebuild the vertex weight array for all bones
  168|      0|    for (unsigned int a = 0; a < vertexWeights.size(); ++a) {
  ------------------
  |  Branch (168:30): [True: 0, False: 0]
  ------------------
  169|      0|        const VertexWeightArray& vw = vertexWeights[a];
  170|      0|        for (const Weight* it = vw.begin(); it != vw.end(); ++it) {
  ------------------
  |  Branch (170:45): [True: 0, False: 0]
  ------------------
  171|      0|            aiBone* bone = pMesh->mBones[it->mBone];
  172|      0|            bone->mWeights[bone->mNumWeights++] = aiVertexWeight(a, it->mWeight);
  173|      0|        }
  174|      0|    }
  175|       |
  176|       |    // remove empty bones
  177|      0|    if (mRemoveEmptyBones) {
  ------------------
  |  Branch (177:9): [True: 0, False: 0]
  ------------------
  178|      0|        pMesh->mNumBones = removeEmptyBones(pMesh);
  179|      0|    }
  180|       |
  181|      0|    if (!DefaultLogger::isNullLogger()) {
  ------------------
  |  Branch (181:9): [True: 0, False: 0]
  ------------------
  182|       |        ASSIMP_LOG_INFO("Removed ", removed, " weights. Input bones: ", old_bones, ". Output bones: ", pMesh->mNumBones);
  183|      0|    }
  184|      0|}

_ZN6Assimp23LimitBoneWeightsProcess6WeightC2Ev:
  116|  95.0k|        : mBone(0)
  117|  95.0k|        , mWeight(0.0f) {
  118|       |            // empty
  119|  95.0k|        }
_ZN6Assimp23LimitBoneWeightsProcess6WeightC2Ejf:
  122|  18.5k|        : mBone(pBone)
  123|  18.5k|        , mWeight(pWeight) {
  124|       |            // empty
  125|  18.5k|        }

_Z21IsMeshInVerboseFormatPK6aiMesh:
  198|    775|bool IsMeshInVerboseFormat(const aiMesh *mesh) {
  199|       |    // avoid slow vector<bool> specialization
  200|    775|    std::vector<unsigned int> seen(mesh->mNumVertices, 0);
  201|  3.34k|    for (unsigned int i = 0; i < mesh->mNumFaces; ++i) {
  ------------------
  |  Branch (201:30): [True: 2.72k, False: 621]
  ------------------
  202|  2.72k|        const aiFace &f = mesh->mFaces[i];
  203|  9.63k|        for (unsigned int j = 0; j < f.mNumIndices; ++j) {
  ------------------
  |  Branch (203:34): [True: 7.05k, False: 2.57k]
  ------------------
  204|  7.05k|            if (++seen[f.mIndices[j]] == 2) {
  ------------------
  |  Branch (204:17): [True: 154, False: 6.90k]
  ------------------
  205|       |                // found a duplicate index
  206|    154|                return false;
  207|    154|            }
  208|  7.05k|        }
  209|  2.72k|    }
  210|       |
  211|    621|    return true;
  212|    775|}
_ZN6Assimp24MakeVerboseFormatProcess15IsVerboseFormatEPK7aiScene:
  215|    208|bool MakeVerboseFormatProcess::IsVerboseFormat(const aiScene *pScene) {
  216|    829|    for (unsigned int i = 0; i < pScene->mNumMeshes; ++i) {
  ------------------
  |  Branch (216:30): [True: 775, False: 54]
  ------------------
  217|    775|        if (!IsMeshInVerboseFormat(pScene->mMeshes[i])) {
  ------------------
  |  Branch (217:13): [True: 154, False: 621]
  ------------------
  218|    154|            return false;
  219|    154|        }
  220|    775|    }
  221|       |
  222|     54|    return true;
  223|    208|}

_ZN6Assimp20OptimizeGraphProcessC2Ev:
   77|    832|		count_merged() {
   78|       |	// empty
   79|    832|}
_ZNK6Assimp20OptimizeGraphProcess8IsActiveEj:
   83|    371|bool OptimizeGraphProcess::IsActive(unsigned int pFlags) const {
   84|    371|	return (0 != (pFlags & aiProcess_OptimizeGraph));
   85|    371|}

_ZN6Assimp20OptimizeGraphProcessD2Ev:
   76|    832|    ~OptimizeGraphProcess() override = default;

_ZN6Assimp21OptimizeMeshesProcessC2Ev:
   66|    832|    , pts(false)
   67|    832|    , max_verts( NotSet )
   68|    832|    , max_faces( NotSet ) {
   69|       |    // empty
   70|    832|}
_ZNK6Assimp21OptimizeMeshesProcess8IsActiveEj:
   75|    362|{
   76|       |    // Our behaviour needs to be different if the SortByPType or SplitLargeMeshes
   77|       |    // steps are active. Thus we need to query their flags here and store the
   78|       |    // information, although we're breaking const-correctness.
   79|       |    // That's a serious design flaw, consider redesign.
   80|    362|    if( 0 != (pFlags & aiProcess_OptimizeMeshes) ) {
  ------------------
  |  Branch (80:9): [True: 0, False: 362]
  ------------------
   81|      0|        pts = (0 != (pFlags & aiProcess_SortByPType));
   82|      0|        max_verts = ( 0 != ( pFlags & aiProcess_SplitLargeMeshes ) ) ? DeadBeef : max_verts;
  ------------------
  |  Branch (82:21): [True: 0, False: 0]
  ------------------
   83|      0|        return true;
   84|      0|    }
   85|    362|    return false;
   86|    362|}

_ZN6Assimp21OptimizeMeshesProcessD2Ev:
   73|    832|    ~OptimizeMeshesProcess() override = default;

_ZN6Assimp20PretransformVerticesC2Ev:
   90|    832|		mConfigKeepHierarchy(false),
   91|    832|		mConfigNormalize(false),
   92|    832|		mConfigTransform(false),
   93|    832|		mConfigTransformation(),
   94|    832|		mConfigPointCloud(false) {}
_ZNK6Assimp20PretransformVertices8IsActiveEj:
   98|    371|bool PretransformVertices::IsActive(unsigned int pFlags) const {
   99|    371|	return (pFlags & aiProcess_PreTransformVertices) != 0;
  100|    371|}

_ZN6Assimp22ComputePositionEpsilonEPK6aiMesh:
  136|  3.58k|ai_real ComputePositionEpsilon(const aiMesh *pMesh) {
  137|  3.58k|    const ai_real epsilon = ai_real(1e-4);
  138|       |
  139|       |    // calculate the position bounds so we have a reliable epsilon to check position differences against
  140|  3.58k|    aiVector3D minVec, maxVec;
  141|  3.58k|    ArrayBounds(pMesh->mVertices, pMesh->mNumVertices, minVec, maxVec);
  142|  3.58k|    return (maxVec - minVec).Length() * epsilon;
  143|  3.58k|}
_ZN6Assimp22ComputePositionEpsilonEPKPK6aiMeshm:
  146|     18|ai_real ComputePositionEpsilon(const aiMesh *const *pMeshes, size_t num) {
  147|     18|    ai_assert(nullptr != pMeshes);
  148|       |
  149|     18|    const ai_real epsilon = ai_real(1e-4);
  150|       |
  151|       |    // calculate the position bounds so we have a reliable epsilon to check position differences against
  152|     18|    aiVector3D minVec, maxVec, mi, ma;
  153|     18|    MinMaxChooser<aiVector3D>()(minVec, maxVec);
  154|       |
  155|     41|    for (size_t a = 0; a < num; ++a) {
  ------------------
  |  Branch (155:24): [True: 23, False: 18]
  ------------------
  156|     23|        const aiMesh *pMesh = pMeshes[a];
  157|     23|        ArrayBounds(pMesh->mVertices, pMesh->mNumVertices, mi, ma);
  158|       |
  159|     23|        minVec = std::min(minVec, mi);
  160|     23|        maxVec = std::max(maxVec, ma);
  161|     23|    }
  162|     18|    return (maxVec - minVec).Length() * epsilon;
  163|     18|}
_ZN6Assimp28ComputeVertexBoneWeightTableEPK6aiMesh:
  199|    664|VertexWeightTable *ComputeVertexBoneWeightTable(const aiMesh *pMesh) {
  200|    664|    if (!pMesh || !pMesh->mNumVertices || !pMesh->mNumBones) {
  ------------------
  |  Branch (200:9): [True: 0, False: 664]
  |  Branch (200:19): [True: 0, False: 664]
  |  Branch (200:43): [True: 659, False: 5]
  ------------------
  201|    659|        return nullptr;
  202|    659|    }
  203|       |
  204|      5|    VertexWeightTable *avPerVertexWeights = new VertexWeightTable[pMesh->mNumVertices];
  205|  2.91k|    for (unsigned int i = 0; i < pMesh->mNumBones; ++i) {
  ------------------
  |  Branch (205:30): [True: 2.91k, False: 5]
  ------------------
  206|       |
  207|  2.91k|        aiBone *bone = pMesh->mBones[i];
  208|  76.0k|        for (unsigned int a = 0; a < bone->mNumWeights; ++a) {
  ------------------
  |  Branch (208:34): [True: 73.0k, False: 2.91k]
  ------------------
  209|  73.0k|            const aiVertexWeight &weight = bone->mWeights[a];
  210|  73.0k|            avPerVertexWeights[weight.mVertexId].emplace_back(i, weight.mWeight);
  211|  73.0k|        }
  212|  2.91k|    }
  213|      5|    return avPerVertexWeights;
  214|    664|}

_ZNK6Assimp25ComputeSpatialSortProcess8IsActiveEj:
  337|    362|    bool IsActive(unsigned int pFlags) const {
  338|    362|        return nullptr != shared && 0 != (pFlags & (aiProcess_CalcTangentSpace |
  ------------------
  |  Branch (338:16): [True: 208, False: 154]
  |  Branch (338:37): [True: 208, False: 0]
  ------------------
  339|    208|                                                           aiProcess_GenNormals | aiProcess_JoinIdenticalVertices));
  340|    362|    }
_ZN6Assimp25ComputeSpatialSortProcess7ExecuteEP7aiScene:
  342|    208|    void Execute(aiScene *pScene) {
  343|    208|        typedef std::pair<SpatialSort, ai_real> _Type;
  344|    208|        ASSIMP_LOG_DEBUG("Generate spatially-sorted vertex cache");
  345|       |
  346|    208|        std::vector<_Type> *p = new std::vector<_Type>(pScene->mNumMeshes);
  347|    208|        std::vector<_Type>::iterator it = p->begin();
  348|       |
  349|  3.78k|        for (unsigned int i = 0; i < pScene->mNumMeshes; ++i, ++it) {
  ------------------
  |  Branch (349:34): [True: 3.57k, False: 208]
  ------------------
  350|  3.57k|            aiMesh *mesh = pScene->mMeshes[i];
  351|  3.57k|            _Type &blubb = *it;
  352|  3.57k|            blubb.first.Fill(mesh->mVertices, mesh->mNumVertices, sizeof(aiVector3D));
  353|  3.57k|            blubb.second = ComputePositionEpsilon(mesh);
  354|  3.57k|        }
  355|       |
  356|    208|        shared->AddProperty(AI_SPP_SPATIAL_SORT, p);
  ------------------
  |  |  166|    208|#define AI_SPP_SPATIAL_SORT "$Spat"
  ------------------
  357|    208|    }
_ZNK6Assimp25DestroySpatialSortProcess8IsActiveEj:
  363|    362|    bool IsActive(unsigned int pFlags) const {
  364|    362|        return nullptr != shared && 0 != (pFlags & (aiProcess_CalcTangentSpace |
  ------------------
  |  Branch (364:16): [True: 208, False: 154]
  |  Branch (364:37): [True: 208, False: 0]
  ------------------
  365|    208|                                                        aiProcess_GenNormals | aiProcess_JoinIdenticalVertices));
  366|    362|    }
_ZN6Assimp25DestroySpatialSortProcess7ExecuteEP7aiScene:
  368|    208|    void Execute(aiScene * /*pScene*/) {
  369|    208|        shared->RemoveProperty(AI_SPP_SPATIAL_SORT);
  ------------------
  |  |  166|    208|#define AI_SPP_SPATIAL_SORT "$Spat"
  ------------------
  370|    208|    }
_ZN6Assimp18GetColorDifferenceERK9aiColor4tIfES3_:
  250|  18.1M|inline ai_real GetColorDifference(const aiColor4D &pColor1, const aiColor4D &pColor2) {
  251|  18.1M|    const aiColor4D c(pColor1.r - pColor2.r, pColor1.g - pColor2.g, pColor1.b - pColor2.b, pColor1.a - pColor2.a);
  252|  18.1M|    return c.r * c.r + c.g * c.g + c.b * c.b + c.a * c.a;
  253|  18.1M|}
_ZSt3minIfE10aiVector3tIT_ERKS2_S4_:
   67|  3.32M|inline ::aiVector3t<TReal> min(const ::aiVector3t<TReal> &a, const ::aiVector3t<TReal> &b) {
   68|  3.32M|    return ::aiVector3t<TReal>(min(a.x, b.x), min(a.y, b.y), min(a.z, b.z));
   69|  3.32M|}
_ZSt3maxIfE10aiVector3tIT_ERKS2_S4_:
   73|  3.32M|inline ::aiVector3t<TReal> max(const ::aiVector3t<TReal> &a, const ::aiVector3t<TReal> &b) {
   74|  3.32M|    return ::aiVector3t<TReal>(max(a.x, b.x), max(a.y, b.y), max(a.z, b.z));
   75|  3.32M|}
_ZN6Assimp13MinMaxChooserI10aiVector3tIfEEclERS2_S4_:
  177|  3.62k|    void operator()(aiVector3t<T> &min, aiVector3t<T> &max) {
  178|  3.62k|        max = aiVector3t<T>(-1e10f, -1e10f, -1e10f);
  179|  3.62k|        min = aiVector3t<T>(1e10f, 1e10f, 1e10f);
  180|  3.62k|    }
_ZN6Assimp11ArrayBoundsI10aiVector3tIfEEEvPKT_jRS3_S6_:
  236|  3.60k|inline void ArrayBounds(const T *in, unsigned int size, T &min, T &max) {
  237|  3.60k|    MinMaxChooser<T>()(min, max);
  238|  3.32M|    for (unsigned int i = 0; i < size; ++i) {
  ------------------
  |  Branch (238:30): [True: 3.32M, False: 3.60k]
  ------------------
  239|  3.32M|        min = std::min(in[i], min);
  240|  3.32M|        max = std::max(in[i], max);
  241|  3.32M|    }
  242|  3.60k|}

_ZN6Assimp26RemoveRedundantMatsProcessC2Ev:
   57|    832|RemoveRedundantMatsProcess::RemoveRedundantMatsProcess() : mConfigFixedMaterials() {}
_ZNK6Assimp26RemoveRedundantMatsProcess8IsActiveEj:
   61|    371|bool RemoveRedundantMatsProcess::IsActive( unsigned int pFlags) const {
   62|    371|    return (pFlags & aiProcess_RemoveRedundantMaterials) != 0;
   63|    371|}
_ZN6Assimp26RemoveRedundantMatsProcess15SetupPropertiesEPKNS_8ImporterE:
   67|    217|void RemoveRedundantMatsProcess::SetupProperties(const Importer* pImp) {
   68|       |    // Get value of AI_CONFIG_PP_RRM_EXCLUDE_LIST
   69|       |    mConfigFixedMaterials = pImp->GetPropertyString(AI_CONFIG_PP_RRM_EXCLUDE_LIST,"");
   70|    217|}
_ZN6Assimp26RemoveRedundantMatsProcess7ExecuteEP7aiScene:
   74|    217|void RemoveRedundantMatsProcess::Execute( aiScene* pScene) {
   75|    217|    ASSIMP_LOG_DEBUG("RemoveRedundantMatsProcess begin");
   76|       |
   77|    217|    unsigned int redundantRemoved = 0, unreferencedRemoved = 0;
   78|    217|    if (pScene->mNumMaterials == 0) {
  ------------------
  |  Branch (78:9): [True: 34, False: 183]
  ------------------
   79|     34|        return;
   80|     34|    }
   81|       |
   82|       |    // Find out which materials are referenced by meshes
   83|    183|    std::vector<bool> abReferenced(pScene->mNumMaterials,false);
   84|  3.43k|    for (unsigned int i = 0;i < pScene->mNumMeshes;++i) {
  ------------------
  |  Branch (84:29): [True: 3.24k, False: 183]
  ------------------
   85|  3.24k|        abReferenced[pScene->mMeshes[i]->mMaterialIndex] = true;
   86|  3.24k|    }
   87|       |
   88|       |    // If a list of materials to be excluded was given, match the list with
   89|       |    // our imported materials and 'salt' all positive matches to ensure that
   90|       |    // we get unique hashes later.
   91|    183|    if (mConfigFixedMaterials.length()) {
  ------------------
  |  Branch (91:9): [True: 0, False: 183]
  ------------------
   92|      0|        std::list<std::string> strings;
   93|      0|        ConvertListToStrings(mConfigFixedMaterials,strings);
   94|       |
   95|      0|        for (unsigned int i = 0; i < pScene->mNumMaterials;++i) {
  ------------------
  |  Branch (95:34): [True: 0, False: 0]
  ------------------
   96|      0|            aiMaterial* mat = pScene->mMaterials[i];
   97|      0|            ai_assert(mat != nullptr);
   98|      0|            aiString name;
   99|      0|            mat->Get(AI_MATKEY_NAME,name);
  100|       |
  101|      0|            if (name.length != 0) {
  ------------------
  |  Branch (101:17): [True: 0, False: 0]
  ------------------
  102|      0|                std::list<std::string>::const_iterator it = std::find(strings.begin(), strings.end(), name.data);
  103|      0|                if (it != strings.end()) {
  ------------------
  |  Branch (103:21): [True: 0, False: 0]
  ------------------
  104|       |                    // Our brilliant 'salt': A single material property with ~ as first
  105|       |                    // character to mark it as internal and temporary.
  106|      0|                    const int dummy = 1;
  107|      0|                    ((aiMaterial*)mat)->AddProperty(&dummy,1,"~RRM.UniqueMaterial",0,0);
  108|       |
  109|       |                    // Keep this material even if no mesh references it
  110|      0|                    abReferenced[i] = true;
  111|      0|                    ASSIMP_LOG_VERBOSE_DEBUG( "Found positive match in exclusion list: \'", name.data, "\'");
  112|      0|                }
  113|      0|            }
  114|      0|        }
  115|      0|    }
  116|       |
  117|       |    // TODO: re-implement this algorithm to work in-place
  118|    183|    unsigned int *aiMappingTable = new unsigned int[pScene->mNumMaterials];
  119|  2.33k|    for ( unsigned int i=0; i<pScene->mNumMaterials; i++ ) {
  ------------------
  |  Branch (119:29): [True: 2.14k, False: 183]
  ------------------
  120|  2.14k|        aiMappingTable[ i ] = 0;
  121|  2.14k|    }
  122|    183|    unsigned int iNewNum = 0;
  123|       |
  124|       |    // Iterate through all materials and calculate a hash for them
  125|       |    // store all hashes in a list and so a quick search whether
  126|       |    // we do already have a specific hash. This allows us to
  127|       |    // determine which materials are identical.
  128|    183|    uint32_t *aiHashes = new uint32_t[ pScene->mNumMaterials ];
  129|  2.33k|    for (unsigned int i = 0; i < pScene->mNumMaterials;++i) {
  ------------------
  |  Branch (129:30): [True: 2.14k, False: 183]
  ------------------
  130|       |        // No mesh is referencing this material, remove it.
  131|  2.14k|        if (!abReferenced[i]) {
  ------------------
  |  Branch (131:13): [True: 194, False: 1.95k]
  ------------------
  132|    194|            ++unreferencedRemoved;
  133|    194|            delete pScene->mMaterials[i];
  134|    194|            pScene->mMaterials[i] = nullptr;
  135|    194|            continue;
  136|    194|        }
  137|       |
  138|       |        // Check all previously mapped materials for a matching hash.
  139|       |        // On a match we can delete this material and just make it ref to the same index.
  140|  1.95k|        uint32_t me = aiHashes[i] = ComputeMaterialHash(pScene->mMaterials[i]);
  141|  2.50k|        for (unsigned int a = 0; a < i;++a) {
  ------------------
  |  Branch (141:34): [True: 2.25k, False: 255]
  ------------------
  142|  2.25k|            if (abReferenced[a] && me == aiHashes[a]) {
  ------------------
  |  Branch (142:17): [True: 1.89k, False: 359]
  |  Branch (142:17): [True: 1.69k, False: 556]
  |  Branch (142:36): [True: 1.69k, False: 197]
  ------------------
  143|  1.69k|                ++redundantRemoved;
  144|  1.69k|                me = 0;
  145|  1.69k|                aiMappingTable[i] = aiMappingTable[a];
  146|  1.69k|                delete pScene->mMaterials[i];
  147|  1.69k|                pScene->mMaterials[i] = nullptr;
  148|  1.69k|                break;
  149|  1.69k|            }
  150|  2.25k|        }
  151|       |        // This is a new material that is referenced, add to the map.
  152|  1.95k|        if (me) {
  ------------------
  |  Branch (152:13): [True: 255, False: 1.69k]
  ------------------
  153|    255|            aiMappingTable[i] = iNewNum++;
  154|    255|        }
  155|  1.95k|    }
  156|       |    // If the new material count differs from the original,
  157|       |    // we need to rebuild the material list and remap mesh material indexes.
  158|    183|    if (iNewNum < 1) {
  ------------------
  |  Branch (158:9): [True: 0, False: 183]
  ------------------
  159|      0|        delete [] aiMappingTable;
  160|      0|        delete [] aiHashes;
  161|      0|        pScene->mNumMaterials = 0;
  162|      0|        return;
  163|      0|    }
  164|    183|    if (iNewNum != pScene->mNumMaterials) {
  ------------------
  |  Branch (164:9): [True: 41, False: 142]
  ------------------
  165|     41|        ai_assert(iNewNum > 0);
  166|     41|        aiMaterial** ppcMaterials = new aiMaterial*[iNewNum];
  167|     41|        ::memset(ppcMaterials,0,sizeof(void*)*iNewNum);
  168|  1.99k|        for (unsigned int p = 0; p < pScene->mNumMaterials;++p) {
  ------------------
  |  Branch (168:34): [True: 1.95k, False: 41]
  ------------------
  169|       |            // if the material is not referenced ... remove it
  170|  1.95k|            if (!abReferenced[p]) {
  ------------------
  |  Branch (170:17): [True: 194, False: 1.75k]
  ------------------
  171|    194|                continue;
  172|    194|            }
  173|       |
  174|       |            // generate new names for modified materials that had no names
  175|  1.75k|            const unsigned int idx = aiMappingTable[p];
  176|  1.75k|            if (ppcMaterials[idx]) {
  ------------------
  |  Branch (176:17): [True: 1.69k, False: 58]
  ------------------
  177|  1.69k|                aiString sz;
  178|  1.69k|                if( ppcMaterials[idx]->Get(AI_MATKEY_NAME, sz) != AI_SUCCESS ) {
  ------------------
  |  Branch (178:21): [True: 5, False: 1.69k]
  ------------------
  179|      5|                    sz.length = ::ai_snprintf(sz.data, AI_MAXLEN,"JoinedMaterial_#%u",p);
  180|      5|                    ((aiMaterial*)ppcMaterials[idx])->AddProperty(&sz,AI_MATKEY_NAME);
  181|      5|                }
  182|  1.69k|            } else {
  183|     58|                ppcMaterials[idx] = pScene->mMaterials[p];
  184|     58|            }
  185|  1.75k|        }
  186|       |        // update all material indices
  187|  2.99k|        for (unsigned int p = 0; p < pScene->mNumMeshes;++p) {
  ------------------
  |  Branch (187:34): [True: 2.95k, False: 41]
  ------------------
  188|  2.95k|            aiMesh* mesh = pScene->mMeshes[p];
  189|  2.95k|            ai_assert(nullptr != mesh);
  190|  2.95k|            mesh->mMaterialIndex = aiMappingTable[mesh->mMaterialIndex];
  191|  2.95k|        }
  192|       |        // delete the old material list
  193|     41|        delete[] pScene->mMaterials;
  194|     41|        pScene->mMaterials = ppcMaterials;
  195|     41|        pScene->mNumMaterials = iNewNum;
  196|     41|    }
  197|       |    // delete temporary storage
  198|    183|    delete[] aiHashes;
  199|    183|    delete[] aiMappingTable;
  200|       |
  201|    183|    if (redundantRemoved == 0 && unreferencedRemoved == 0) {
  ------------------
  |  Branch (201:9): [True: 152, False: 31]
  |  Branch (201:34): [True: 142, False: 10]
  ------------------
  202|    142|        ASSIMP_LOG_DEBUG("RemoveRedundantMatsProcess finished ");
  203|    142|    } else {
  204|       |        ASSIMP_LOG_INFO("RemoveRedundantMatsProcess finished. Removed ", redundantRemoved, " redundant and ",
  205|     41|            unreferencedRemoved, " unused materials.");
  206|     41|    }
  207|    183|}

_ZN6Assimp26RemoveRedundantMatsProcessD2Ev:
   64|    832|    ~RemoveRedundantMatsProcess() override = default;

_ZN6Assimp15RemoveVCProcessC2Ev:
   55|    832|        configDeleteFlags(), mScene() {}
_ZNK6Assimp15RemoveVCProcess8IsActiveEj:
   59|    371|bool RemoveVCProcess::IsActive(unsigned int pFlags) const {
   60|    371|    return (pFlags & aiProcess_RemoveComponent) != 0;
   61|    371|}

_ZN6Assimp12ScaleProcessC2Ev:
   50|    832|ScaleProcess::ScaleProcess() : BaseProcess(), mScale( AI_CONFIG_GLOBAL_SCALE_FACTOR_DEFAULT ) {
   51|       |    // empty
   52|    832|}
_ZNK6Assimp12ScaleProcess8IsActiveEj:
   65|    371|bool ScaleProcess::IsActive( unsigned int pFlags ) const {
   66|    371|    return ( pFlags & aiProcess_GlobalScale ) != 0;
   67|    371|}

_ZN6Assimp18SortByPTypeProcessC2Ev:
   55|    832|SortByPTypeProcess::SortByPTypeProcess() : mConfigRemoveMeshes(0) {}
_ZNK6Assimp18SortByPTypeProcess8IsActiveEj:
   59|    371|bool SortByPTypeProcess::IsActive(unsigned int pFlags) const {
   60|    371|    return (pFlags & aiProcess_SortByPType) != 0;
   61|    371|}
_ZN6Assimp18SortByPTypeProcess15SetupPropertiesEPKNS_8ImporterE:
   64|    217|void SortByPTypeProcess::SetupProperties(const Importer *pImp) {
   65|       |    mConfigRemoveMeshes = pImp->GetPropertyInteger(AI_CONFIG_PP_SBP_REMOVE, 0);
   66|    217|}
_Z11UpdateNodesRKNSt3__16vectorIjNS_9allocatorIjEEEEP6aiNode:
   77|  8.75k|void UpdateNodes(const std::vector<unsigned int> &replaceMeshIndex, aiNode *node) {
   78|  8.75k|    ai_assert(node != nullptr);
   79|       |
   80|  8.75k|    if (node->mNumMeshes) {
  ------------------
  |  Branch (80:9): [True: 544, False: 8.21k]
  ------------------
   81|    544|        unsigned int newSize = 0;
   82|  1.44k|        for (unsigned int m = 0; m < node->mNumMeshes; ++m) {
  ------------------
  |  Branch (82:34): [True: 905, False: 544]
  ------------------
   83|    905|            unsigned int add = node->mMeshes[m] << 2;
   84|  4.52k|            for (unsigned int i = 0; i < 4; ++i) {
  ------------------
  |  Branch (84:38): [True: 3.62k, False: 905]
  ------------------
   85|  3.62k|                if (UINT_MAX != replaceMeshIndex[add + i]) {
  ------------------
  |  Branch (85:21): [True: 1.58k, False: 2.03k]
  ------------------
   86|  1.58k|                    ++newSize;
   87|  1.58k|                }
   88|  3.62k|            }
   89|    905|        }
   90|    544|        if (newSize == 0) {
  ------------------
  |  Branch (90:13): [True: 0, False: 544]
  ------------------
   91|      0|            clearMeshesInNode(node);
   92|      0|            return;
   93|      0|        }
   94|       |
   95|       |        // Try to reuse the old array if possible
   96|    544|        unsigned int *newMeshes = (newSize > node->mNumMeshes ? new unsigned int[newSize] : node->mMeshes);
  ------------------
  |  Branch (96:36): [True: 419, False: 125]
  ------------------
   97|  1.44k|        for (unsigned int m = 0; m < node->mNumMeshes; ++m) {
  ------------------
  |  Branch (97:34): [True: 905, False: 544]
  ------------------
   98|    905|            unsigned int add = node->mMeshes[m] << 2;
   99|  4.52k|            for (unsigned int i = 0; i < 4; ++i) {
  ------------------
  |  Branch (99:38): [True: 3.62k, False: 905]
  ------------------
  100|  3.62k|                if (UINT_MAX != replaceMeshIndex[add + i]) {
  ------------------
  |  Branch (100:21): [True: 1.58k, False: 2.03k]
  ------------------
  101|  1.58k|                    *newMeshes++ = replaceMeshIndex[add + i];
  102|  1.58k|                }
  103|  3.62k|            }
  104|    905|        }
  105|    544|        if (newSize > node->mNumMeshes) {
  ------------------
  |  Branch (105:13): [True: 419, False: 125]
  ------------------
  106|    419|            clearMeshesInNode(node);
  107|    419|        }
  108|    544|        node->mMeshes = newMeshes - (node->mNumMeshes = newSize);
  109|    544|    }
  110|       |
  111|       |    // call all subnodes recursively
  112|  17.4k|    for (unsigned int m = 0; m < node->mNumChildren; ++m) {
  ------------------
  |  Branch (112:30): [True: 8.70k, False: 8.75k]
  ------------------
  113|  8.70k|        UpdateNodes(replaceMeshIndex, node->mChildren[m]);
  114|  8.70k|    }
  115|  8.75k|}
_ZN6Assimp18SortByPTypeProcess7ExecuteEP7aiScene:
  119|    217|void SortByPTypeProcess::Execute(aiScene *pScene) {
  120|    217|    if (0 == pScene->mNumMeshes) {
  ------------------
  |  Branch (120:9): [True: 34, False: 183]
  ------------------
  121|     34|        ASSIMP_LOG_DEBUG("SortByPTypeProcess skipped, there are no meshes");
  122|     34|        return;
  123|     34|    }
  124|       |
  125|    217|    ASSIMP_LOG_DEBUG("SortByPTypeProcess begin");
  126|       |
  127|    183|    unsigned int aiNumMeshesPerPType[4] = { 0, 0, 0, 0 };
  128|       |
  129|    183|    std::vector<aiMesh *> outMeshes;
  130|    183|    outMeshes.reserve(static_cast<size_t>(pScene->mNumMeshes) << 1u);
  131|       |
  132|    183|    bool bAnyChanges = false;
  133|       |
  134|    183|    std::vector<unsigned int> replaceMeshIndex(pScene->mNumMeshes * 4, UINT_MAX);
  135|    183|    std::vector<unsigned int>::iterator meshIdx = replaceMeshIndex.begin();
  136|  3.36k|    for (unsigned int i = 0; i < pScene->mNumMeshes; ++i) {
  ------------------
  |  Branch (136:30): [True: 3.18k, False: 180]
  ------------------
  137|  3.18k|        aiMesh *const mesh = pScene->mMeshes[i];
  138|  3.18k|        if (mesh->mPrimitiveTypes == 0) {
  ------------------
  |  Branch (138:13): [True: 3, False: 3.18k]
  ------------------
  139|     57|            for (size_t idx = 0; idx < outMeshes.size(); ++idx) {
  ------------------
  |  Branch (139:34): [True: 54, False: 3]
  ------------------
  140|     54|                delete outMeshes[idx];
  141|     54|            }
  142|      3|            throw DeadlyImportError("Mesh with invalid primitive type: ", mesh->mName.C_Str());
  143|      3|        }
  144|       |
  145|       |        // if there's just one primitive type in the mesh there's nothing to do for us
  146|  3.18k|        unsigned int num = 0;
  147|  3.18k|        if (mesh->mPrimitiveTypes & aiPrimitiveType_POINT) {
  ------------------
  |  Branch (147:13): [True: 605, False: 2.57k]
  ------------------
  148|    605|            ++aiNumMeshesPerPType[0];
  149|    605|            ++num;
  150|    605|        }
  151|  3.18k|        if (mesh->mPrimitiveTypes & aiPrimitiveType_LINE) {
  ------------------
  |  Branch (151:13): [True: 672, False: 2.51k]
  ------------------
  152|    672|            ++aiNumMeshesPerPType[1];
  153|    672|            ++num;
  154|    672|        }
  155|  3.18k|        if (mesh->mPrimitiveTypes & aiPrimitiveType_TRIANGLE) {
  ------------------
  |  Branch (155:13): [True: 2.58k, False: 597]
  ------------------
  156|  2.58k|            ++aiNumMeshesPerPType[2];
  157|  2.58k|            ++num;
  158|  2.58k|        }
  159|  3.18k|        if (mesh->mPrimitiveTypes & aiPrimitiveType_POLYGON) {
  ------------------
  |  Branch (159:13): [True: 0, False: 3.18k]
  ------------------
  160|      0|            ++aiNumMeshesPerPType[3];
  161|      0|            ++num;
  162|      0|        }
  163|       |
  164|  3.18k|        if (1 == num) {
  ------------------
  |  Branch (164:13): [True: 2.51k, False: 664]
  ------------------
  165|  2.51k|            if (!(mConfigRemoveMeshes & mesh->mPrimitiveTypes)) {
  ------------------
  |  Branch (165:17): [True: 2.51k, False: 0]
  ------------------
  166|  2.51k|                *meshIdx = static_cast<unsigned int>(outMeshes.size());
  167|  2.51k|                outMeshes.emplace_back(mesh);
  168|  2.51k|                pScene->mMeshes[i] = nullptr; // Indicate ownership transfer
  169|  2.51k|            } else {
  170|      0|                delete mesh;
  171|      0|                pScene->mMeshes[i] = nullptr;
  172|      0|                bAnyChanges = true;
  173|      0|            }
  174|       |
  175|  2.51k|            meshIdx += 4;
  176|  2.51k|            continue;
  177|  2.51k|        }
  178|    664|        bAnyChanges = true;
  179|       |
  180|       |        // reuse our current mesh arrays for the submesh
  181|       |        // with the largest number of primitives
  182|    664|        unsigned int aiNumPerPType[4] = { 0, 0, 0, 0 };
  183|    664|        aiFace *pFirstFace = mesh->mFaces;
  184|    664|        if (pFirstFace == nullptr) {
  ------------------
  |  Branch (184:13): [True: 0, False: 664]
  ------------------
  185|      0|            continue;
  186|      0|        }
  187|       |
  188|    664|        aiFace *const pLastFace = pFirstFace + mesh->mNumFaces;
  189|       |
  190|    664|        unsigned int numPolyVerts = 0;
  191|  77.7k|        for (; pFirstFace != pLastFace; ++pFirstFace) {
  ------------------
  |  Branch (191:16): [True: 77.1k, False: 664]
  ------------------
  192|  77.1k|            if (pFirstFace->mNumIndices >= 1 && pFirstFace->mNumIndices <= 3)
  ------------------
  |  Branch (192:17): [True: 77.1k, False: 0]
  |  Branch (192:49): [True: 77.1k, False: 0]
  ------------------
  193|  77.1k|                ++aiNumPerPType[pFirstFace->mNumIndices - 1];
  194|      0|            else {
  195|      0|                ++aiNumPerPType[3];
  196|      0|                numPolyVerts += pFirstFace->mNumIndices;
  197|      0|            }
  198|  77.1k|            if (pFirstFace->mNumIndices == 0) {
  ------------------
  |  Branch (198:17): [True: 0, False: 77.1k]
  ------------------
  199|      0|                ASSIMP_LOG_WARN("Face with 0 indices treated as polygon");
  200|      0|            }
  201|  77.1k|        }
  202|       |
  203|    664|        VertexWeightTable *avw = ComputeVertexBoneWeightTable(mesh);
  204|  3.32k|        for (unsigned int real = 0; real < 4; ++real, ++meshIdx) {
  ------------------
  |  Branch (204:37): [True: 2.65k, False: 664]
  ------------------
  205|  2.65k|            if (!aiNumPerPType[real] || mConfigRemoveMeshes & (1u << real)) {
  ------------------
  |  Branch (205:17): [True: 1.31k, False: 1.34k]
  |  Branch (205:41): [True: 0, False: 1.34k]
  ------------------
  206|  1.31k|                continue;
  207|  1.31k|            }
  208|       |
  209|  1.34k|            *meshIdx = (unsigned int)outMeshes.size();
  210|  1.34k|            outMeshes.push_back(new aiMesh());
  211|  1.34k|            aiMesh *out = outMeshes.back();
  212|       |
  213|       |            // the name carries the adjacency information between the meshes
  214|  1.34k|            out->mName = mesh->mName;
  215|       |
  216|       |            // copy data members
  217|  1.34k|            out->mPrimitiveTypes = 1u << real;
  218|  1.34k|            out->mMaterialIndex = mesh->mMaterialIndex;
  219|       |
  220|       |            // allocate output storage
  221|  1.34k|            out->mNumFaces = aiNumPerPType[real];
  222|  1.34k|            aiFace *outFaces = out->mFaces = new aiFace[out->mNumFaces];
  223|       |
  224|  1.34k|            out->mNumVertices = (3 == real ? numPolyVerts : out->mNumFaces * (real + 1));
  ------------------
  |  Branch (224:34): [True: 0, False: 1.34k]
  ------------------
  225|       |
  226|  1.34k|            aiVector3D *vert(nullptr), *nor(nullptr), *tan(nullptr), *bit(nullptr);
  227|  1.34k|            aiVector3D *uv[AI_MAX_NUMBER_OF_TEXTURECOORDS];
  228|  1.34k|            aiColor4D *cols[AI_MAX_NUMBER_OF_COLOR_SETS];
  229|       |
  230|  1.34k|            if (mesh->mVertices) {
  ------------------
  |  Branch (230:17): [True: 1.34k, False: 0]
  ------------------
  231|  1.34k|                vert = out->mVertices = new aiVector3D[out->mNumVertices];
  232|  1.34k|            }
  233|       |
  234|  1.34k|            if (mesh->mNormals) {
  ------------------
  |  Branch (234:17): [True: 71, False: 1.27k]
  ------------------
  235|     71|                nor = out->mNormals = new aiVector3D[out->mNumVertices];
  236|     71|            }
  237|       |
  238|  1.34k|            if (mesh->mTangents) {
  ------------------
  |  Branch (238:17): [True: 0, False: 1.34k]
  ------------------
  239|      0|                tan = out->mTangents = new aiVector3D[out->mNumVertices];
  240|      0|                bit = out->mBitangents = new aiVector3D[out->mNumVertices];
  241|      0|            }
  242|       |
  243|  12.0k|            for (unsigned int j = 0; j < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++j) {
  ------------------
  |  Branch (243:38): [True: 10.7k, False: 1.34k]
  ------------------
  244|  10.7k|                uv[j] = nullptr;
  245|  10.7k|                if (mesh->mTextureCoords[j]) {
  ------------------
  |  Branch (245:21): [True: 37, False: 10.7k]
  ------------------
  246|     37|                    uv[j] = out->mTextureCoords[j] = new aiVector3D[out->mNumVertices];
  247|     37|                }
  248|       |
  249|  10.7k|                out->mNumUVComponents[j] = mesh->mNumUVComponents[j];
  250|  10.7k|            }
  251|       |
  252|  12.0k|            for (unsigned int j = 0; j < AI_MAX_NUMBER_OF_COLOR_SETS; ++j) {
  ------------------
  |  Branch (252:38): [True: 10.7k, False: 1.34k]
  ------------------
  253|  10.7k|                cols[j] = nullptr;
  254|  10.7k|                if (mesh->mColors[j]) {
  ------------------
  |  Branch (254:21): [True: 333, False: 10.4k]
  ------------------
  255|    333|                    cols[j] = out->mColors[j] = new aiColor4D[out->mNumVertices];
  256|    333|                }
  257|  10.7k|            }
  258|       |
  259|  1.34k|            if (mesh->mNumAnimMeshes > 0 && mesh->mAnimMeshes) {
  ------------------
  |  Branch (259:17): [True: 0, False: 1.34k]
  |  Branch (259:45): [True: 0, False: 0]
  ------------------
  260|      0|                out->mNumAnimMeshes = mesh->mNumAnimMeshes;
  261|      0|                out->mAnimMeshes = new aiAnimMesh *[out->mNumAnimMeshes];
  262|      0|            }
  263|       |
  264|  1.34k|            for (unsigned int j = 0; j < mesh->mNumAnimMeshes; ++j) {
  ------------------
  |  Branch (264:38): [True: 0, False: 1.34k]
  ------------------
  265|      0|                aiAnimMesh *animMesh = mesh->mAnimMeshes[j];
  266|      0|                aiAnimMesh *outAnimMesh = out->mAnimMeshes[j] = new aiAnimMesh;
  267|      0|                outAnimMesh->mNumVertices = out->mNumVertices;
  268|      0|                if (animMesh->mVertices)
  ------------------
  |  Branch (268:21): [True: 0, False: 0]
  ------------------
  269|      0|                    outAnimMesh->mVertices = new aiVector3D[out->mNumVertices];
  270|      0|                else
  271|      0|                    outAnimMesh->mVertices = nullptr;
  272|      0|                if (animMesh->mNormals)
  ------------------
  |  Branch (272:21): [True: 0, False: 0]
  ------------------
  273|      0|                    outAnimMesh->mNormals = new aiVector3D[out->mNumVertices];
  274|      0|                else
  275|      0|                    outAnimMesh->mNormals = nullptr;
  276|      0|                if (animMesh->mTangents)
  ------------------
  |  Branch (276:21): [True: 0, False: 0]
  ------------------
  277|      0|                    outAnimMesh->mTangents = new aiVector3D[out->mNumVertices];
  278|      0|                else
  279|      0|                    outAnimMesh->mTangents = nullptr;
  280|      0|                if (animMesh->mBitangents)
  ------------------
  |  Branch (280:21): [True: 0, False: 0]
  ------------------
  281|      0|                    outAnimMesh->mBitangents = new aiVector3D[out->mNumVertices];
  282|      0|                else
  283|      0|                    outAnimMesh->mBitangents = nullptr;
  284|      0|                for (int jj = 0; jj < AI_MAX_NUMBER_OF_COLOR_SETS; ++jj) {
  ------------------
  |  Branch (284:34): [True: 0, False: 0]
  ------------------
  285|      0|                    if (animMesh->mColors[jj])
  ------------------
  |  Branch (285:25): [True: 0, False: 0]
  ------------------
  286|      0|                        outAnimMesh->mColors[jj] = new aiColor4D[out->mNumVertices];
  287|      0|                    else
  288|      0|                        outAnimMesh->mColors[jj] = nullptr;
  289|      0|                }
  290|      0|                for (int jj = 0; jj < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++jj) {
  ------------------
  |  Branch (290:34): [True: 0, False: 0]
  ------------------
  291|      0|                    if (animMesh->mTextureCoords[jj])
  ------------------
  |  Branch (291:25): [True: 0, False: 0]
  ------------------
  292|      0|                        outAnimMesh->mTextureCoords[jj] = new aiVector3D[out->mNumVertices];
  293|      0|                    else
  294|      0|                        outAnimMesh->mTextureCoords[jj] = nullptr;
  295|      0|                }
  296|      0|            }
  297|       |
  298|  1.34k|            typedef std::vector<aiVertexWeight> TempBoneInfo;
  299|  1.34k|            std::vector<TempBoneInfo> tempBones(mesh->mNumBones);
  300|       |
  301|       |            // try to guess how much storage we'll need
  302|  7.17k|            for (unsigned int q = 0; q < mesh->mNumBones; ++q) {
  ------------------
  |  Branch (302:38): [True: 5.82k, False: 1.34k]
  ------------------
  303|  5.82k|                tempBones[q].reserve(mesh->mBones[q]->mNumWeights / (num - 1));
  304|  5.82k|            }
  305|       |
  306|  1.34k|            unsigned int outIdx = 0;
  307|  1.34k|            unsigned int amIdx = 0; // AnimMesh index
  308|   163k|            for (unsigned int m = 0; m < mesh->mNumFaces; ++m) {
  ------------------
  |  Branch (308:38): [True: 162k, False: 1.34k]
  ------------------
  309|   162k|                aiFace &in = mesh->mFaces[m];
  310|   162k|                if ((real == 3 && in.mNumIndices <= 3) || (real != 3 && in.mNumIndices != real + 1)) {
  ------------------
  |  Branch (310:22): [True: 0, False: 162k]
  |  Branch (310:35): [True: 0, False: 0]
  |  Branch (310:60): [True: 162k, False: 0]
  |  Branch (310:73): [True: 85.3k, False: 77.1k]
  ------------------
  311|  85.3k|                    continue;
  312|  85.3k|                }
  313|       |
  314|  77.1k|                outFaces->mNumIndices = in.mNumIndices;
  315|  77.1k|                outFaces->mIndices = in.mIndices;
  316|       |
  317|   257k|                for (unsigned int q = 0; q < in.mNumIndices; ++q) {
  ------------------
  |  Branch (317:42): [True: 179k, False: 77.1k]
  ------------------
  318|   179k|                    unsigned int idx = in.mIndices[q];
  319|       |
  320|       |                    // process all bones of this index
  321|   179k|                    if (avw) {
  ------------------
  |  Branch (321:25): [True: 26.5k, False: 153k]
  ------------------
  322|  26.5k|                        VertexWeightTable &tbl = avw[idx];
  323|  26.5k|                        for (VertexWeightTable::const_iterator it = tbl.begin(), end = tbl.end();
  324|  53.1k|                                it != end; ++it) {
  ------------------
  |  Branch (324:33): [True: 26.5k, False: 26.5k]
  ------------------
  325|  26.5k|                            tempBones[(*it).first].emplace_back(outIdx, (*it).second);
  326|  26.5k|                        }
  327|  26.5k|                    }
  328|       |
  329|   179k|                    if (vert) {
  ------------------
  |  Branch (329:25): [True: 179k, False: 0]
  ------------------
  330|   179k|                        *vert++ = mesh->mVertices[idx];
  331|   179k|                    }
  332|   179k|                    if (nor)
  ------------------
  |  Branch (332:25): [True: 61.6k, False: 118k]
  ------------------
  333|  61.6k|                        *nor++ = mesh->mNormals[idx];
  334|   179k|                    if (tan) {
  ------------------
  |  Branch (334:25): [True: 0, False: 179k]
  ------------------
  335|      0|                        *tan++ = mesh->mTangents[idx];
  336|      0|                        *bit++ = mesh->mBitangents[idx];
  337|      0|                    }
  338|       |
  339|   189k|                    for (unsigned int pp = 0; pp < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++pp) {
  ------------------
  |  Branch (339:47): [True: 189k, False: 0]
  ------------------
  340|   189k|                        if (!uv[pp])
  ------------------
  |  Branch (340:29): [True: 179k, False: 10.0k]
  ------------------
  341|   179k|                            break;
  342|  10.0k|                        *uv[pp]++ = mesh->mTextureCoords[pp][idx];
  343|  10.0k|                    }
  344|       |
  345|   256k|                    for (unsigned int pp = 0; pp < AI_MAX_NUMBER_OF_COLOR_SETS; ++pp) {
  ------------------
  |  Branch (345:47): [True: 256k, False: 0]
  ------------------
  346|   256k|                        if (!cols[pp])
  ------------------
  |  Branch (346:29): [True: 179k, False: 77.0k]
  ------------------
  347|   179k|                            break;
  348|  77.0k|                        *cols[pp]++ = mesh->mColors[pp][idx];
  349|  77.0k|                    }
  350|       |
  351|   179k|                    unsigned int pp = 0;
  352|   179k|                    for (; pp < mesh->mNumAnimMeshes; ++pp) {
  ------------------
  |  Branch (352:28): [True: 0, False: 179k]
  ------------------
  353|      0|                        aiAnimMesh *animMesh = mesh->mAnimMeshes[pp];
  354|      0|                        aiAnimMesh *outAnimMesh = out->mAnimMeshes[pp];
  355|      0|                        if (animMesh->mVertices)
  ------------------
  |  Branch (355:29): [True: 0, False: 0]
  ------------------
  356|      0|                            outAnimMesh->mVertices[amIdx] = animMesh->mVertices[idx];
  357|      0|                        if (animMesh->mNormals)
  ------------------
  |  Branch (357:29): [True: 0, False: 0]
  ------------------
  358|      0|                            outAnimMesh->mNormals[amIdx] = animMesh->mNormals[idx];
  359|      0|                        if (animMesh->mTangents)
  ------------------
  |  Branch (359:29): [True: 0, False: 0]
  ------------------
  360|      0|                            outAnimMesh->mTangents[amIdx] = animMesh->mTangents[idx];
  361|      0|                        if (animMesh->mBitangents)
  ------------------
  |  Branch (361:29): [True: 0, False: 0]
  ------------------
  362|      0|                            outAnimMesh->mBitangents[amIdx] = animMesh->mBitangents[idx];
  363|      0|                        for (int jj = 0; jj < AI_MAX_NUMBER_OF_COLOR_SETS; ++jj) {
  ------------------
  |  Branch (363:42): [True: 0, False: 0]
  ------------------
  364|      0|                            if (animMesh->mColors[jj])
  ------------------
  |  Branch (364:33): [True: 0, False: 0]
  ------------------
  365|      0|                                outAnimMesh->mColors[jj][amIdx] = animMesh->mColors[jj][idx];
  366|      0|                        }
  367|      0|                        for (int jj = 0; jj < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++jj) {
  ------------------
  |  Branch (367:42): [True: 0, False: 0]
  ------------------
  368|      0|                            if (animMesh->mTextureCoords[jj])
  ------------------
  |  Branch (368:33): [True: 0, False: 0]
  ------------------
  369|      0|                                outAnimMesh->mTextureCoords[jj][amIdx] = animMesh->mTextureCoords[jj][idx];
  370|      0|                        }
  371|      0|                    }
  372|   179k|                    if (pp == mesh->mNumAnimMeshes)
  ------------------
  |  Branch (372:25): [True: 179k, False: 0]
  ------------------
  373|   179k|                        ++amIdx;
  374|       |
  375|   179k|                    in.mIndices[q] = outIdx++;
  376|   179k|                }
  377|       |
  378|  77.1k|                in.mIndices = nullptr;
  379|  77.1k|                ++outFaces;
  380|  77.1k|            }
  381|  1.34k|            ai_assert(outFaces == out->mFaces + out->mNumFaces);
  382|       |
  383|       |            // now generate output bones
  384|  7.17k|            for (unsigned int q = 0; q < mesh->mNumBones; ++q) {
  ------------------
  |  Branch (384:38): [True: 5.82k, False: 1.34k]
  ------------------
  385|  5.82k|                if (!tempBones[q].empty()) {
  ------------------
  |  Branch (385:21): [True: 2.91k, False: 2.91k]
  ------------------
  386|  2.91k|                    ++out->mNumBones;
  387|  2.91k|                }
  388|  5.82k|            }
  389|       |
  390|  1.34k|            if (out->mNumBones) {
  ------------------
  |  Branch (390:17): [True: 10, False: 1.33k]
  ------------------
  391|     10|                out->mBones = new aiBone *[out->mNumBones];
  392|  5.83k|                for (unsigned int q = 0, boneIdx = 0; q < mesh->mNumBones; ++q) {
  ------------------
  |  Branch (392:55): [True: 5.82k, False: 10]
  ------------------
  393|  5.82k|                    TempBoneInfo &in = tempBones[q];
  394|  5.82k|                    if (in.empty()) {
  ------------------
  |  Branch (394:25): [True: 2.91k, False: 2.91k]
  ------------------
  395|  2.91k|                        continue;
  396|  2.91k|                    }
  397|       |
  398|  2.91k|                    aiBone *srcBone = mesh->mBones[q];
  399|  2.91k|                    aiBone *bone = out->mBones[boneIdx] = new aiBone();
  400|       |
  401|  2.91k|                    bone->mName = srcBone->mName;
  402|  2.91k|                    bone->mOffsetMatrix = srcBone->mOffsetMatrix;
  403|       |
  404|  2.91k|                    bone->mNumWeights = (unsigned int)in.size();
  405|  2.91k|                    bone->mWeights = new aiVertexWeight[bone->mNumWeights];
  406|       |
  407|  2.91k|                    ::memcpy(bone->mWeights, &in[0], bone->mNumWeights * sizeof(aiVertexWeight));
  408|       |
  409|  2.91k|                    ++boneIdx;
  410|  2.91k|                }
  411|     10|            }
  412|  1.34k|        }
  413|       |
  414|       |        // delete the per-vertex bone weights table
  415|    664|        delete[] avw;
  416|       |
  417|       |        // delete the input mesh
  418|    664|        delete mesh;
  419|       |
  420|       |        // avoid invalid pointer
  421|    664|        pScene->mMeshes[i] = nullptr;
  422|    664|    }
  423|       |
  424|    180|    if (outMeshes.empty()) {
  ------------------
  |  Branch (424:9): [True: 0, False: 180]
  ------------------
  425|       |        // This should not occur
  426|      0|        throw DeadlyImportError("No meshes remaining");
  427|      0|    }
  428|       |
  429|       |    // If we added at least one mesh process all nodes in the node
  430|       |    // graph and update their respective mesh indices.
  431|    180|    if (bAnyChanges) {
  ------------------
  |  Branch (431:9): [True: 48, False: 132]
  ------------------
  432|     48|        UpdateNodes(replaceMeshIndex, pScene->mRootNode);
  433|     48|    }
  434|       |
  435|    180|    if (outMeshes.size() != pScene->mNumMeshes) {
  ------------------
  |  Branch (435:9): [True: 48, False: 132]
  ------------------
  436|     48|        delete[] pScene->mMeshes;
  437|     48|        pScene->mNumMeshes = (unsigned int)outMeshes.size();
  438|     48|        pScene->mMeshes = new aiMesh *[pScene->mNumMeshes];
  439|     48|    }
  440|    180|    ::memcpy(pScene->mMeshes, &outMeshes[0], pScene->mNumMeshes * sizeof(void *));
  441|       |
  442|    180|    if (!DefaultLogger::isNullLogger()) {
  ------------------
  |  Branch (442:9): [True: 0, False: 180]
  ------------------
  443|      0|        char buffer[1024];
  444|      0|        ::ai_snprintf(buffer, 1024, "Points: %u%s, Lines: %u%s, Triangles: %u%s, Polygons: %u%s (Meshes, X = removed)",
  445|      0|                aiNumMeshesPerPType[0], ((mConfigRemoveMeshes & aiPrimitiveType_POINT) ? "X" : ""),
  ------------------
  |  Branch (445:42): [True: 0, False: 0]
  ------------------
  446|      0|                aiNumMeshesPerPType[1], ((mConfigRemoveMeshes & aiPrimitiveType_LINE) ? "X" : ""),
  ------------------
  |  Branch (446:42): [True: 0, False: 0]
  ------------------
  447|      0|                aiNumMeshesPerPType[2], ((mConfigRemoveMeshes & aiPrimitiveType_TRIANGLE) ? "X" : ""),
  ------------------
  |  Branch (447:42): [True: 0, False: 0]
  ------------------
  448|      0|                aiNumMeshesPerPType[3], ((mConfigRemoveMeshes & aiPrimitiveType_POLYGON) ? "X" : ""));
  ------------------
  |  Branch (448:42): [True: 0, False: 0]
  ------------------
  449|      0|        ASSIMP_LOG_INFO(buffer);
  450|       |        ASSIMP_LOG_DEBUG("SortByPTypeProcess finished");
  451|      0|    }
  452|    180|}
SortByPTypeProcess.cpp:_ZL17clearMeshesInNodeP6aiNode:
   69|    419|static void clearMeshesInNode(aiNode *node) {
   70|    419|    delete[] node->mMeshes;
   71|    419|    node->mNumMeshes = 0;
   72|    419|    node->mMeshes = nullptr;
   73|    419|}

_ZN6Assimp23SplitByBoneCountProcessC2Ev:
   60|    832|SplitByBoneCountProcess::SplitByBoneCountProcess() : mMaxBoneCount(AI_SBBC_DEFAULT_MAX_BONES) {}
_ZNK6Assimp23SplitByBoneCountProcess8IsActiveEj:
   64|    362|bool SplitByBoneCountProcess::IsActive( unsigned int pFlags) const {
   65|    362|    return !!(pFlags & aiProcess_SplitByBoneCount);
   66|    362|}

_ZN6Assimp23SplitByBoneCountProcessD2Ev:
   66|    832|    ~SplitByBoneCountProcess() override = default;

_ZN6Assimp32SplitLargeMeshesProcess_TriangleC2Ev:
   51|    832|SplitLargeMeshesProcess_Triangle::SplitLargeMeshesProcess_Triangle() {
   52|       |    LIMIT = AI_SLM_DEFAULT_MAX_TRIANGLES;
   53|    832|}
_ZNK6Assimp32SplitLargeMeshesProcess_Triangle8IsActiveEj:
   57|    362|bool SplitLargeMeshesProcess_Triangle::IsActive( unsigned int pFlags) const {
   58|    362|    return (pFlags & aiProcess_SplitLargeMeshes) != 0;
   59|    362|}
_ZN6Assimp32SplitLargeMeshesProcess_Triangle7ExecuteEP7aiScene:
   63|    208|void SplitLargeMeshesProcess_Triangle::Execute( aiScene* pScene) {
   64|    208|    if (0xffffffff == this->LIMIT || nullptr == pScene ) {
  ------------------
  |  Branch (64:9): [True: 0, False: 208]
  |  Branch (64:38): [True: 0, False: 208]
  ------------------
   65|      0|        return;
   66|      0|    }
   67|       |
   68|    208|    ASSIMP_LOG_DEBUG("SplitLargeMeshesProcess_Triangle begin");
   69|    208|    std::vector<std::pair<aiMesh*, unsigned int> > avList;
   70|       |
   71|  3.78k|    for( unsigned int a = 0; a < pScene->mNumMeshes; ++a) {
  ------------------
  |  Branch (71:30): [True: 3.57k, False: 208]
  ------------------
   72|  3.57k|        this->SplitMesh(a, pScene->mMeshes[a],avList);
   73|  3.57k|    }
   74|       |
   75|    208|    if (avList.size() == pScene->mNumMeshes) {
  ------------------
  |  Branch (75:9): [True: 208, False: 0]
  ------------------
   76|    208|        ASSIMP_LOG_DEBUG("SplitLargeMeshesProcess_Triangle finished. There was nothing to do");
   77|    208|    }
   78|       |
   79|       |    // it seems something has been split. rebuild the mesh list
   80|    208|    delete[] pScene->mMeshes;
   81|    208|    pScene->mNumMeshes = (unsigned int)avList.size();
   82|    208|    pScene->mMeshes = new aiMesh*[avList.size()];
   83|       |
   84|  3.78k|    for (unsigned int i = 0; i < avList.size();++i) {
  ------------------
  |  Branch (84:30): [True: 3.57k, False: 208]
  ------------------
   85|  3.57k|        pScene->mMeshes[i] = avList[i].first;
   86|  3.57k|    }
   87|       |
   88|       |    // now we need to update all nodes
   89|    208|    this->UpdateNode(pScene->mRootNode,avList);
   90|       |    ASSIMP_LOG_INFO("SplitLargeMeshesProcess_Triangle finished. Meshes have been split");
   91|    208|}
_ZN6Assimp32SplitLargeMeshesProcess_Triangle15SetupPropertiesEPKNS_8ImporterE:
   95|    208|void SplitLargeMeshesProcess_Triangle::SetupProperties( const Importer* pImp) {
   96|       |    // get the current value of the split property
   97|    208|    this->LIMIT = pImp->GetPropertyInteger(AI_CONFIG_PP_SLM_TRIANGLE_LIMIT,AI_SLM_DEFAULT_MAX_TRIANGLES);
   98|    208|}
_ZN6Assimp32SplitLargeMeshesProcess_Triangle10UpdateNodeEP6aiNodeRKNSt3__16vectorINS3_4pairIP6aiMeshjEENS3_9allocatorIS8_EEEE:
  102|  37.2k|void SplitLargeMeshesProcess_Triangle::UpdateNode(aiNode* pcNode, const std::vector<std::pair<aiMesh*, unsigned int> >& avList) {
  103|  37.2k|    if (pcNode == nullptr) {
  ------------------
  |  Branch (103:9): [True: 0, False: 37.2k]
  ------------------
  104|      0|        ASSIMP_LOG_WARN("UpdateNode skipped, nullptr detected.");
  105|      0|        return;
  106|      0|    }
  107|       |
  108|       |    // for every index in out list build a new entry
  109|  37.2k|    std::vector<unsigned int> aiEntries;
  110|  37.2k|    aiEntries.reserve(pcNode->mNumMeshes + 1);
  111|  50.9k|    for (unsigned int i = 0; i < pcNode->mNumMeshes;++i) {
  ------------------
  |  Branch (111:30): [True: 13.6k, False: 37.2k]
  ------------------
  112|  18.7M|        for (unsigned int a = 0; a < avList.size();++a) {
  ------------------
  |  Branch (112:34): [True: 18.7M, False: 13.6k]
  ------------------
  113|  18.7M|            if (avList[a].second == pcNode->mMeshes[i]) {
  ------------------
  |  Branch (113:17): [True: 13.6k, False: 18.7M]
  ------------------
  114|  13.6k|                aiEntries.push_back(a);
  115|  13.6k|            }
  116|  18.7M|        }
  117|  13.6k|    }
  118|       |
  119|       |    // now build the new list
  120|  37.2k|    delete[] pcNode->mMeshes;
  121|  37.2k|    pcNode->mNumMeshes = (unsigned int)aiEntries.size();
  122|  37.2k|    pcNode->mMeshes = new unsigned int[pcNode->mNumMeshes];
  123|       |
  124|  50.9k|    for (unsigned int b = 0; b < pcNode->mNumMeshes;++b) {
  ------------------
  |  Branch (124:30): [True: 13.6k, False: 37.2k]
  ------------------
  125|  13.6k|        pcNode->mMeshes[b] = aiEntries[b];
  126|  13.6k|    }
  127|       |
  128|       |    // recursively update all other nodes
  129|  74.3k|    for (unsigned int i = 0; i < pcNode->mNumChildren;++i) {
  ------------------
  |  Branch (129:30): [True: 37.0k, False: 37.2k]
  ------------------
  130|  37.0k|        UpdateNode ( pcNode->mChildren[i], avList );
  131|  37.0k|    }
  132|  37.2k|}
_ZN6Assimp32SplitLargeMeshesProcess_Triangle9SplitMeshEjP6aiMeshRNSt3__16vectorINS3_4pairIS2_jEENS3_9allocatorIS6_EEEE:
  139|  3.57k|        std::vector<std::pair<aiMesh*, unsigned int> >& avList) {
  140|  3.57k|    if (pMesh->mNumFaces > SplitLargeMeshesProcess_Triangle::LIMIT) {
  ------------------
  |  Branch (140:9): [True: 0, False: 3.57k]
  ------------------
  141|      0|        ASSIMP_LOG_INFO("Mesh exceeds the triangle limit. It will be split ...");
  142|       |
  143|       |        // we need to split this mesh into sub meshes
  144|       |        // determine the size of a submesh
  145|      0|        const unsigned int iSubMeshes = (pMesh->mNumFaces / LIMIT) + 1;
  146|       |
  147|      0|        const unsigned int iOutFaceNum = pMesh->mNumFaces / iSubMeshes;
  148|      0|        const unsigned int iOutVertexNum = iOutFaceNum * 3;
  149|       |
  150|       |        // now generate all submeshes
  151|      0|        for (unsigned int i = 0; i < iSubMeshes;++i) {
  ------------------
  |  Branch (151:34): [True: 0, False: 0]
  ------------------
  152|      0|            aiMesh* pcMesh          = new aiMesh;
  153|      0|            pcMesh->mNumFaces       = iOutFaceNum;
  154|      0|            pcMesh->mMaterialIndex  = pMesh->mMaterialIndex;
  155|       |
  156|       |            // the name carries the adjacency information between the meshes
  157|      0|            pcMesh->mName = pMesh->mName;
  158|       |
  159|      0|            if (i == iSubMeshes-1) {
  ------------------
  |  Branch (159:17): [True: 0, False: 0]
  ------------------
  160|      0|                pcMesh->mNumFaces = iOutFaceNum + (
  161|      0|                    pMesh->mNumFaces - iOutFaceNum * iSubMeshes);
  162|      0|            }
  163|       |            // copy the list of faces
  164|      0|            pcMesh->mFaces = new aiFace[pcMesh->mNumFaces];
  165|       |
  166|      0|            const unsigned int iBase = iOutFaceNum * i;
  167|       |
  168|       |            // get the total number of indices
  169|      0|            unsigned int iCnt = 0;
  170|      0|            for (unsigned int p = iBase; p < pcMesh->mNumFaces + iBase;++p) {
  ------------------
  |  Branch (170:42): [True: 0, False: 0]
  ------------------
  171|      0|                iCnt += pMesh->mFaces[p].mNumIndices;
  172|      0|            }
  173|      0|            pcMesh->mNumVertices = iCnt;
  174|       |
  175|       |            // allocate storage
  176|      0|            if (pMesh->mVertices != nullptr) {
  ------------------
  |  Branch (176:17): [True: 0, False: 0]
  ------------------
  177|      0|                pcMesh->mVertices = new aiVector3D[iCnt];
  178|      0|            }
  179|       |
  180|      0|            if (pMesh->HasNormals()) {
  ------------------
  |  Branch (180:17): [True: 0, False: 0]
  ------------------
  181|      0|                pcMesh->mNormals = new aiVector3D[iCnt];
  182|      0|            }
  183|       |
  184|      0|            if (pMesh->HasTangentsAndBitangents()) {
  ------------------
  |  Branch (184:17): [True: 0, False: 0]
  ------------------
  185|      0|                pcMesh->mTangents = new aiVector3D[iCnt];
  186|      0|                pcMesh->mBitangents = new aiVector3D[iCnt];
  187|      0|            }
  188|       |
  189|       |            // texture coordinates
  190|      0|            for (unsigned int c = 0;  c < AI_MAX_NUMBER_OF_TEXTURECOORDS;++c) {
  ------------------
  |  Branch (190:39): [True: 0, False: 0]
  ------------------
  191|      0|                pcMesh->mNumUVComponents[c] = pMesh->mNumUVComponents[c];
  192|      0|                if (pMesh->HasTextureCoords( c)) {
  ------------------
  |  Branch (192:21): [True: 0, False: 0]
  ------------------
  193|      0|                    pcMesh->mTextureCoords[c] = new aiVector3D[iCnt];
  194|      0|                }
  195|      0|            }
  196|       |
  197|       |            // vertex colors
  198|      0|            for (unsigned int c = 0;  c < AI_MAX_NUMBER_OF_COLOR_SETS;++c) {
  ------------------
  |  Branch (198:39): [True: 0, False: 0]
  ------------------
  199|      0|                if (pMesh->HasVertexColors( c)) {
  ------------------
  |  Branch (199:21): [True: 0, False: 0]
  ------------------
  200|      0|                    pcMesh->mColors[c] = new aiColor4D[iCnt];
  201|      0|                }
  202|      0|            }
  203|       |
  204|      0|            if (pMesh->HasBones()) {
  ------------------
  |  Branch (204:17): [True: 0, False: 0]
  ------------------
  205|       |                // assume the number of bones won't change in most cases
  206|      0|                pcMesh->mBones = new aiBone*[pMesh->mNumBones];
  207|       |
  208|       |                // iterate through all bones of the mesh and find those which
  209|       |                // need to be copied to the split mesh
  210|      0|                std::vector<aiVertexWeight> avTempWeights;
  211|      0|                for (unsigned int p = 0; p < pcMesh->mNumBones;++p) {
  ------------------
  |  Branch (211:42): [True: 0, False: 0]
  ------------------
  212|      0|                    aiBone* const bone = pcMesh->mBones[p];
  213|      0|                    avTempWeights.clear();
  214|      0|                    avTempWeights.reserve(bone->mNumWeights / iSubMeshes);
  215|       |
  216|      0|                    for (unsigned int q = 0; q < bone->mNumWeights;++q) {
  ------------------
  |  Branch (216:46): [True: 0, False: 0]
  ------------------
  217|      0|                        aiVertexWeight& weight = bone->mWeights[q];
  218|      0|                        if(weight.mVertexId >= iBase && weight.mVertexId < iBase + iOutVertexNum) {
  ------------------
  |  Branch (218:28): [True: 0, False: 0]
  |  Branch (218:57): [True: 0, False: 0]
  ------------------
  219|      0|                            avTempWeights.push_back(weight);
  220|      0|                            weight = avTempWeights.back();
  221|      0|                            weight.mVertexId -= iBase;
  222|      0|                        }
  223|      0|                    }
  224|       |
  225|      0|                    if (!avTempWeights.empty()) {
  ------------------
  |  Branch (225:25): [True: 0, False: 0]
  ------------------
  226|       |                        // we'll need this bone. Copy it ...
  227|      0|                        aiBone* pc = new aiBone();
  228|      0|                        pcMesh->mBones[pcMesh->mNumBones++] = pc;
  229|      0|                        pc->mName = aiString(bone->mName);
  230|      0|                        pc->mNumWeights = (unsigned int)avTempWeights.size();
  231|      0|                        pc->mOffsetMatrix = bone->mOffsetMatrix;
  232|       |
  233|       |                        // no need to reallocate the array for the last submesh.
  234|       |                        // Here we can reuse the (large) source array, although
  235|       |                        // we'll waste some memory
  236|      0|                        if (iSubMeshes-1 == i) {
  ------------------
  |  Branch (236:29): [True: 0, False: 0]
  ------------------
  237|      0|                            pc->mWeights = bone->mWeights;
  238|      0|                            bone->mWeights = nullptr;
  239|      0|                        } else {
  240|      0|                            pc->mWeights = new aiVertexWeight[pc->mNumWeights];
  241|      0|                        }
  242|       |
  243|       |                        // copy the weights
  244|      0|                        ::memcpy(pc->mWeights,&avTempWeights[0],sizeof(aiVertexWeight)*pc->mNumWeights);
  245|      0|                    }
  246|      0|                }
  247|      0|            }
  248|       |
  249|       |            // (we will also need to copy the array of indices)
  250|      0|            unsigned int iCurrent = 0;
  251|      0|            for (unsigned int p = 0; p < pcMesh->mNumFaces;++p) {
  ------------------
  |  Branch (251:38): [True: 0, False: 0]
  ------------------
  252|      0|                pcMesh->mFaces[p].mNumIndices = 3;
  253|       |                // allocate a new array
  254|      0|                const unsigned int iTemp = p + iBase;
  255|      0|                const unsigned int iNumIndices = pMesh->mFaces[iTemp].mNumIndices;
  256|       |
  257|       |                // setup face type and number of indices
  258|      0|                pcMesh->mFaces[p].mNumIndices = iNumIndices;
  259|      0|                unsigned int* pi = pMesh->mFaces[iTemp].mIndices;
  260|      0|                unsigned int* piOut = pcMesh->mFaces[p].mIndices = new unsigned int[iNumIndices];
  261|       |
  262|       |                // need to update the output primitive types
  263|      0|                switch (iNumIndices) {
  264|      0|                case 1:
  ------------------
  |  Branch (264:17): [True: 0, False: 0]
  ------------------
  265|      0|                    pcMesh->mPrimitiveTypes |= aiPrimitiveType_POINT;
  266|      0|                    break;
  267|      0|                case 2:
  ------------------
  |  Branch (267:17): [True: 0, False: 0]
  ------------------
  268|      0|                    pcMesh->mPrimitiveTypes |= aiPrimitiveType_LINE;
  269|      0|                    break;
  270|      0|                case 3:
  ------------------
  |  Branch (270:17): [True: 0, False: 0]
  ------------------
  271|      0|                    pcMesh->mPrimitiveTypes |= aiPrimitiveType_TRIANGLE;
  272|      0|                    break;
  273|      0|                default:
  ------------------
  |  Branch (273:17): [True: 0, False: 0]
  ------------------
  274|      0|                    pcMesh->mPrimitiveTypes |= aiPrimitiveType_POLYGON;
  275|      0|                }
  276|       |
  277|       |                // and copy the contents of the old array, offset by current base
  278|      0|                for (unsigned int v = 0; v < iNumIndices;++v) {
  ------------------
  |  Branch (278:42): [True: 0, False: 0]
  ------------------
  279|      0|                    unsigned int iIndex = pi[v];
  280|      0|                    unsigned int iIndexOut = iCurrent++;
  281|      0|                    piOut[v] = iIndexOut;
  282|       |
  283|       |                    // copy positions
  284|      0|                    if (pMesh->mVertices != nullptr) {
  ------------------
  |  Branch (284:25): [True: 0, False: 0]
  ------------------
  285|      0|                        pcMesh->mVertices[iIndexOut] = pMesh->mVertices[iIndex];
  286|      0|                    }
  287|       |
  288|       |                    // copy normals
  289|      0|                    if (pMesh->HasNormals()) {
  ------------------
  |  Branch (289:25): [True: 0, False: 0]
  ------------------
  290|      0|                        pcMesh->mNormals[iIndexOut] = pMesh->mNormals[iIndex];
  291|      0|                    }
  292|       |
  293|       |                    // copy tangents/bitangents
  294|      0|                    if (pMesh->HasTangentsAndBitangents()) {
  ------------------
  |  Branch (294:25): [True: 0, False: 0]
  ------------------
  295|      0|                        pcMesh->mTangents[iIndexOut] = pMesh->mTangents[iIndex];
  296|      0|                        pcMesh->mBitangents[iIndexOut] = pMesh->mBitangents[iIndex];
  297|      0|                    }
  298|       |
  299|       |                    // texture coordinates
  300|      0|                    for (unsigned int c = 0;  c < AI_MAX_NUMBER_OF_TEXTURECOORDS;++c) {
  ------------------
  |  Branch (300:47): [True: 0, False: 0]
  ------------------
  301|      0|                        if (pMesh->HasTextureCoords( c ) ) {
  ------------------
  |  Branch (301:29): [True: 0, False: 0]
  ------------------
  302|      0|                            pcMesh->mTextureCoords[c][iIndexOut] = pMesh->mTextureCoords[c][iIndex];
  303|      0|                        }
  304|      0|                    }
  305|       |                    // vertex colors
  306|      0|                    for (unsigned int c = 0;  c < AI_MAX_NUMBER_OF_COLOR_SETS;++c) {
  ------------------
  |  Branch (306:47): [True: 0, False: 0]
  ------------------
  307|      0|                        if (pMesh->HasVertexColors( c)) {
  ------------------
  |  Branch (307:29): [True: 0, False: 0]
  ------------------
  308|      0|                            pcMesh->mColors[c][iIndexOut] = pMesh->mColors[c][iIndex];
  309|      0|                        }
  310|      0|                    }
  311|      0|                }
  312|      0|            }
  313|       |
  314|       |            // add the newly created mesh to the list
  315|      0|            avList.emplace_back(pcMesh,a);
  316|      0|        }
  317|       |
  318|       |        // now delete the old mesh data
  319|      0|        delete pMesh;
  320|  3.57k|    } else {
  321|  3.57k|        avList.emplace_back(pMesh,a);
  322|  3.57k|    }
  323|  3.57k|}
_ZN6Assimp30SplitLargeMeshesProcess_VertexC2Ev:
  326|    832|SplitLargeMeshesProcess_Vertex::SplitLargeMeshesProcess_Vertex() {
  327|       |    LIMIT = AI_SLM_DEFAULT_MAX_VERTICES;
  328|    832|}
_ZNK6Assimp30SplitLargeMeshesProcess_Vertex8IsActiveEj:
  332|    362|bool SplitLargeMeshesProcess_Vertex::IsActive( unsigned int pFlags) const {
  333|    362|    return (pFlags & aiProcess_SplitLargeMeshes) != 0;
  334|    362|}
_ZN6Assimp30SplitLargeMeshesProcess_Vertex7ExecuteEP7aiScene:
  338|    208|void SplitLargeMeshesProcess_Vertex::Execute( aiScene* pScene) {
  339|    208|    if (0xffffffff == this->LIMIT || nullptr == pScene ) {
  ------------------
  |  Branch (339:9): [True: 0, False: 208]
  |  Branch (339:38): [True: 0, False: 208]
  ------------------
  340|      0|        return;
  341|      0|    }
  342|       |
  343|    208|    ASSIMP_LOG_DEBUG("SplitLargeMeshesProcess_Vertex begin");
  344|       |
  345|    208|    std::vector<std::pair<aiMesh*, unsigned int> > avList;
  346|       |
  347|       |    //Check for point cloud first,
  348|       |    //Do not process point cloud, splitMesh works only with faces data
  349|  3.12k|    for (unsigned int a = 0; a < pScene->mNumMeshes; a++) {
  ------------------
  |  Branch (349:30): [True: 2.94k, False: 179]
  ------------------
  350|  2.94k|        if ( pScene->mMeshes[a]->mPrimitiveTypes == aiPrimitiveType_POINT ) {
  ------------------
  |  Branch (350:14): [True: 29, False: 2.91k]
  ------------------
  351|     29|            return;
  352|     29|        }
  353|  2.94k|    }
  354|       |
  355|  3.03k|    for( unsigned int a = 0; a < pScene->mNumMeshes; ++a ) {
  ------------------
  |  Branch (355:30): [True: 2.85k, False: 179]
  ------------------
  356|  2.85k|        this->SplitMesh(a, pScene->mMeshes[a], avList);
  357|  2.85k|    }
  358|       |
  359|    179|    if (avList.size() != pScene->mNumMeshes) {
  ------------------
  |  Branch (359:9): [True: 0, False: 179]
  ------------------
  360|       |        // it seems something has been split. rebuild the mesh list
  361|      0|        delete[] pScene->mMeshes;
  362|      0|        pScene->mNumMeshes = (unsigned int)avList.size();
  363|      0|        pScene->mMeshes = new aiMesh*[avList.size()];
  364|       |
  365|      0|        for (unsigned int i = 0; i < avList.size();++i) {
  ------------------
  |  Branch (365:34): [True: 0, False: 0]
  ------------------
  366|      0|            pScene->mMeshes[i] = avList[i].first;
  367|      0|        }
  368|       |
  369|       |        // now we need to update all nodes
  370|      0|        SplitLargeMeshesProcess_Triangle::UpdateNode(pScene->mRootNode,avList);
  371|      0|        ASSIMP_LOG_INFO("SplitLargeMeshesProcess_Vertex finished. Meshes have been split");
  372|    179|    } else {
  373|       |        ASSIMP_LOG_DEBUG("SplitLargeMeshesProcess_Vertex finished. There was nothing to do");
  374|    179|    }
  375|    179|}
_ZN6Assimp30SplitLargeMeshesProcess_Vertex15SetupPropertiesEPKNS_8ImporterE:
  379|    208|void SplitLargeMeshesProcess_Vertex::SetupProperties( const Importer* pImp) {
  380|    208|    this->LIMIT = pImp->GetPropertyInteger(AI_CONFIG_PP_SLM_VERTEX_LIMIT,AI_SLM_DEFAULT_MAX_VERTICES);
  381|    208|}
_ZN6Assimp30SplitLargeMeshesProcess_Vertex9SplitMeshEjP6aiMeshRNSt3__16vectorINS3_4pairIS2_jEENS3_9allocatorIS6_EEEE:
  388|  2.85k|        std::vector<std::pair<aiMesh*, unsigned int> >& avList) {
  389|  2.85k|    if (pMesh->mNumVertices > SplitLargeMeshesProcess_Vertex::LIMIT) {
  ------------------
  |  Branch (389:9): [True: 0, False: 2.85k]
  ------------------
  390|      0|        typedef std::vector< std::pair<unsigned int,float> > VertexWeightTable;
  391|       |
  392|       |        // build a per-vertex weight list if necessary
  393|      0|        VertexWeightTable* avPerVertexWeights = ComputeVertexBoneWeightTable(pMesh);
  394|       |
  395|       |        // we need to split this mesh into sub meshes
  396|       |        // determine the estimated size of a submesh
  397|       |        // (this could be too large. Max waste is a single digit percentage)
  398|      0|        const unsigned int iSubMeshes = (pMesh->mNumVertices / SplitLargeMeshesProcess_Vertex::LIMIT) + 1;
  399|       |
  400|       |        // create a std::vector<unsigned int> to indicate which vertices
  401|       |        // have already been copied
  402|      0|        std::vector<unsigned int> avWasCopied;
  403|      0|        avWasCopied.resize(pMesh->mNumVertices,0xFFFFFFFF);
  404|       |
  405|       |        // try to find a good estimate for the number of output faces
  406|       |        // per mesh. Add 12.5% as buffer
  407|      0|        unsigned int iEstimatedSize = pMesh->mNumFaces / iSubMeshes;
  408|      0|        iEstimatedSize += iEstimatedSize >> 3;
  409|       |
  410|       |        // now generate all submeshes
  411|      0|        unsigned int iBase( 0 );
  412|      0|        while (true) {
  ------------------
  |  Branch (412:16): [True: 0, Folded]
  ------------------
  413|      0|            const unsigned int iOutVertexNum = SplitLargeMeshesProcess_Vertex::LIMIT;
  414|      0|            aiMesh* pcMesh          = new aiMesh;
  415|      0|            pcMesh->mNumVertices    = 0;
  416|      0|            pcMesh->mMaterialIndex  = pMesh->mMaterialIndex;
  417|       |
  418|       |            // the name carries the adjacency information between the meshes
  419|      0|            pcMesh->mName = pMesh->mName;
  420|       |
  421|      0|            typedef std::vector<aiVertexWeight> BoneWeightList;
  422|      0|            if (pMesh->HasBones()) {
  ------------------
  |  Branch (422:17): [True: 0, False: 0]
  ------------------
  423|      0|                pcMesh->mBones = new aiBone*[pMesh->mNumBones];
  424|      0|                ::memset(pcMesh->mBones,0,sizeof(void*)*pMesh->mNumBones);
  425|      0|            }
  426|       |
  427|       |            // clear the temporary helper array
  428|      0|            if (iBase) {
  ------------------
  |  Branch (428:17): [True: 0, False: 0]
  ------------------
  429|       |                // we can't use memset here we unsigned int needn' be 32 bits
  430|      0|                for (auto &elem : avWasCopied) {
  ------------------
  |  Branch (430:33): [True: 0, False: 0]
  ------------------
  431|      0|                    elem = 0xffffffff;
  432|      0|                }
  433|      0|            }
  434|       |
  435|       |            // output vectors
  436|      0|            std::vector<aiFace> vFaces;
  437|       |
  438|       |            // reserve enough storage for most cases
  439|      0|            if (pMesh->HasPositions()) {
  ------------------
  |  Branch (439:17): [True: 0, False: 0]
  ------------------
  440|      0|                pcMesh->mVertices = new aiVector3D[iOutVertexNum];
  441|      0|            }
  442|      0|            if (pMesh->HasNormals()) {
  ------------------
  |  Branch (442:17): [True: 0, False: 0]
  ------------------
  443|      0|                pcMesh->mNormals = new aiVector3D[iOutVertexNum];
  444|      0|            }
  445|      0|            if (pMesh->HasTangentsAndBitangents()) {
  ------------------
  |  Branch (445:17): [True: 0, False: 0]
  ------------------
  446|      0|                pcMesh->mTangents = new aiVector3D[iOutVertexNum];
  447|      0|                pcMesh->mBitangents = new aiVector3D[iOutVertexNum];
  448|      0|            }
  449|      0|            for (unsigned int c = 0; pMesh->HasVertexColors(c);++c) {
  ------------------
  |  Branch (449:38): [True: 0, False: 0]
  ------------------
  450|      0|                pcMesh->mColors[c] = new aiColor4D[iOutVertexNum];
  451|      0|            }
  452|      0|            for (unsigned int c = 0; pMesh->HasTextureCoords(c);++c) {
  ------------------
  |  Branch (452:38): [True: 0, False: 0]
  ------------------
  453|      0|                pcMesh->mNumUVComponents[c] = pMesh->mNumUVComponents[c];
  454|      0|                pcMesh->mTextureCoords[c] = new aiVector3D[iOutVertexNum];
  455|      0|            }
  456|      0|            vFaces.reserve(iEstimatedSize);
  457|       |
  458|       |            // (we will also need to copy the array of indices)
  459|      0|            while (iBase < pMesh->mNumFaces) {
  ------------------
  |  Branch (459:20): [True: 0, False: 0]
  ------------------
  460|       |                // allocate a new array
  461|      0|                const unsigned int iNumIndices = pMesh->mFaces[iBase].mNumIndices;
  462|       |
  463|       |                // doesn't catch degenerates but is quite fast
  464|      0|                unsigned int iNeed = 0;
  465|      0|                for (unsigned int v = 0; v < iNumIndices;++v) {
  ------------------
  |  Branch (465:42): [True: 0, False: 0]
  ------------------
  466|      0|                    unsigned int iIndex = pMesh->mFaces[iBase].mIndices[v];
  467|       |
  468|       |                    // check whether we do already have this vertex
  469|      0|                    if (0xFFFFFFFF == avWasCopied[iIndex]) {
  ------------------
  |  Branch (469:25): [True: 0, False: 0]
  ------------------
  470|      0|                        iNeed++;
  471|      0|                    }
  472|      0|                }
  473|      0|                if (pcMesh->mNumVertices + iNeed > iOutVertexNum) {
  ------------------
  |  Branch (473:21): [True: 0, False: 0]
  ------------------
  474|       |                    // don't use this face
  475|      0|                    break;
  476|      0|                }
  477|       |
  478|      0|                vFaces.emplace_back();
  479|      0|                aiFace& rFace = vFaces.back();
  480|       |
  481|       |                // setup face type and number of indices
  482|      0|                rFace.mNumIndices = iNumIndices;
  483|      0|                rFace.mIndices = new unsigned int[iNumIndices];
  484|       |
  485|       |                // need to update the output primitive types
  486|      0|                switch (rFace.mNumIndices) {
  487|      0|                case 1:
  ------------------
  |  Branch (487:17): [True: 0, False: 0]
  ------------------
  488|      0|                    pcMesh->mPrimitiveTypes |= aiPrimitiveType_POINT;
  489|      0|                    break;
  490|      0|                case 2:
  ------------------
  |  Branch (490:17): [True: 0, False: 0]
  ------------------
  491|      0|                    pcMesh->mPrimitiveTypes |= aiPrimitiveType_LINE;
  492|      0|                    break;
  493|      0|                case 3:
  ------------------
  |  Branch (493:17): [True: 0, False: 0]
  ------------------
  494|      0|                    pcMesh->mPrimitiveTypes |= aiPrimitiveType_TRIANGLE;
  495|      0|                    break;
  496|      0|                default:
  ------------------
  |  Branch (496:17): [True: 0, False: 0]
  ------------------
  497|      0|                    pcMesh->mPrimitiveTypes |= aiPrimitiveType_POLYGON;
  498|      0|                }
  499|       |
  500|       |                // and copy the contents of the old array, offset by current base
  501|      0|                for (unsigned int v = 0; v < iNumIndices;++v) {
  ------------------
  |  Branch (501:42): [True: 0, False: 0]
  ------------------
  502|      0|                    unsigned int iIndex = pMesh->mFaces[iBase].mIndices[v];
  503|       |
  504|       |                    // check whether we do already have this vertex
  505|      0|                    if (0xFFFFFFFF != avWasCopied[iIndex]) {
  ------------------
  |  Branch (505:25): [True: 0, False: 0]
  ------------------
  506|      0|                        rFace.mIndices[v] = avWasCopied[iIndex];
  507|      0|                        continue;
  508|      0|                    }
  509|       |
  510|       |                    // copy positions
  511|      0|                    pcMesh->mVertices[pcMesh->mNumVertices] = (pMesh->mVertices[iIndex]);
  512|       |
  513|       |                    // copy normals
  514|      0|                    if (pMesh->HasNormals()) {
  ------------------
  |  Branch (514:25): [True: 0, False: 0]
  ------------------
  515|      0|                        pcMesh->mNormals[pcMesh->mNumVertices] = (pMesh->mNormals[iIndex]);
  516|      0|                    }
  517|       |
  518|       |                    // copy tangents/bitangents
  519|      0|                    if (pMesh->HasTangentsAndBitangents()) {
  ------------------
  |  Branch (519:25): [True: 0, False: 0]
  ------------------
  520|      0|                        pcMesh->mTangents[pcMesh->mNumVertices] = (pMesh->mTangents[iIndex]);
  521|      0|                        pcMesh->mBitangents[pcMesh->mNumVertices] = (pMesh->mBitangents[iIndex]);
  522|      0|                    }
  523|       |
  524|       |                    // texture coordinates
  525|      0|                    for (unsigned int c = 0;  c < AI_MAX_NUMBER_OF_TEXTURECOORDS;++c) {
  ------------------
  |  Branch (525:47): [True: 0, False: 0]
  ------------------
  526|      0|                        if (pMesh->HasTextureCoords( c)) {
  ------------------
  |  Branch (526:29): [True: 0, False: 0]
  ------------------
  527|      0|                            pcMesh->mTextureCoords[c][pcMesh->mNumVertices] = pMesh->mTextureCoords[c][iIndex];
  528|      0|                        }
  529|      0|                    }
  530|       |                    // vertex colors
  531|      0|                    for (unsigned int c = 0;  c < AI_MAX_NUMBER_OF_COLOR_SETS;++c) {
  ------------------
  |  Branch (531:47): [True: 0, False: 0]
  ------------------
  532|      0|                        if (pMesh->HasVertexColors( c)) {
  ------------------
  |  Branch (532:29): [True: 0, False: 0]
  ------------------
  533|      0|                            pcMesh->mColors[c][pcMesh->mNumVertices] = pMesh->mColors[c][iIndex];
  534|      0|                        }
  535|      0|                    }
  536|       |                    // check whether we have bone weights assigned to this vertex
  537|      0|                    rFace.mIndices[v] = pcMesh->mNumVertices;
  538|      0|                    if (avPerVertexWeights) {
  ------------------
  |  Branch (538:25): [True: 0, False: 0]
  ------------------
  539|      0|                        VertexWeightTable& table = avPerVertexWeights[ pcMesh->mNumVertices ];
  540|      0|                        if( !table.empty() ) {
  ------------------
  |  Branch (540:29): [True: 0, False: 0]
  ------------------
  541|      0|                            for (VertexWeightTable::const_iterator iter =  table.begin();
  542|      0|                                    iter != table.end();++iter) {
  ------------------
  |  Branch (542:37): [True: 0, False: 0]
  ------------------
  543|       |                                // allocate the bone weight array if necessary
  544|      0|                                BoneWeightList* pcWeightList = (BoneWeightList*)pcMesh->mBones[(*iter).first];
  545|      0|                                if (nullptr == pcWeightList) {
  ------------------
  |  Branch (545:37): [True: 0, False: 0]
  ------------------
  546|      0|                                    pcMesh->mBones[(*iter).first] = (aiBone*)(pcWeightList = new BoneWeightList());
  547|      0|                                }
  548|      0|                                pcWeightList->push_back(aiVertexWeight(pcMesh->mNumVertices,(*iter).second));
  549|      0|                            }
  550|      0|                        }
  551|      0|                    }
  552|       |
  553|      0|                    avWasCopied[iIndex] = pcMesh->mNumVertices;
  554|      0|                    pcMesh->mNumVertices++;
  555|      0|                }
  556|      0|                ++iBase;
  557|      0|                if(pcMesh->mNumVertices == iOutVertexNum) {
  ------------------
  |  Branch (557:20): [True: 0, False: 0]
  ------------------
  558|       |                    // break here. The face is only added if it was complete
  559|      0|                    break;
  560|      0|                }
  561|      0|            }
  562|       |
  563|       |            // check which bones we'll need to create for this submesh
  564|      0|            if (pMesh->HasBones()) {
  ------------------
  |  Branch (564:17): [True: 0, False: 0]
  ------------------
  565|      0|                aiBone** ppCurrent = pcMesh->mBones;
  566|      0|                for (unsigned int k = 0; k < pMesh->mNumBones;++k) {
  ------------------
  |  Branch (566:42): [True: 0, False: 0]
  ------------------
  567|       |                    // check whether the bone is existing
  568|      0|                    BoneWeightList* pcWeightList;
  569|      0|                    pcWeightList = (BoneWeightList *)pcMesh->mBones[k];
  570|      0|                    if (nullptr != pcWeightList) {
  ------------------
  |  Branch (570:25): [True: 0, False: 0]
  ------------------
  571|      0|                        aiBone *pcOldBone = pMesh->mBones[k];
  572|      0|                        aiBone* pcOut( nullptr );
  573|      0|                        *ppCurrent++ = pcOut = new aiBone();
  574|      0|                        pcOut->mName = aiString(pcOldBone->mName);
  575|      0|                        pcOut->mOffsetMatrix = pcOldBone->mOffsetMatrix;
  576|      0|                        pcOut->mNumWeights = (unsigned int)pcWeightList->size();
  577|      0|                        pcOut->mWeights = new aiVertexWeight[pcOut->mNumWeights];
  578|       |
  579|       |                        // copy the vertex weights
  580|      0|                        ::memcpy(pcOut->mWeights,&pcWeightList->operator[](0),
  581|      0|                            pcOut->mNumWeights * sizeof(aiVertexWeight));
  582|       |
  583|       |                        // delete the temporary bone weight list
  584|      0|                        delete pcWeightList;
  585|      0|                        pcMesh->mNumBones++;
  586|      0|                    }
  587|      0|                }
  588|      0|            }
  589|       |
  590|       |            // copy the face list to the mesh
  591|      0|            pcMesh->mFaces = new aiFace[vFaces.size()];
  592|      0|            pcMesh->mNumFaces = (unsigned int)vFaces.size();
  593|       |
  594|      0|            for (unsigned int p = 0; p < pcMesh->mNumFaces;++p) {
  ------------------
  |  Branch (594:38): [True: 0, False: 0]
  ------------------
  595|      0|                pcMesh->mFaces[p] = vFaces[p];
  596|      0|            }
  597|       |
  598|       |            // add the newly created mesh to the list
  599|      0|            avList.emplace_back(pcMesh,a);
  600|       |
  601|      0|            if (iBase == pMesh->mNumFaces) {
  ------------------
  |  Branch (601:17): [True: 0, False: 0]
  ------------------
  602|       |                // have all faces ... finish the outer loop, too
  603|      0|                break;
  604|      0|            }
  605|      0|        }
  606|       |
  607|       |        // delete the per-vertex weight list again
  608|      0|        delete[] avPerVertexWeights;
  609|       |
  610|       |        // now delete the old mesh data
  611|      0|        delete pMesh;
  612|      0|        return;
  613|      0|    }
  614|  2.85k|    avList.emplace_back(pMesh,a);
  615|  2.85k|}

_ZNK6Assimp20TextureTransformStep8IsActiveEj:
   54|    371|bool TextureTransformStep::IsActive( unsigned int pFlags) const {
   55|    371|    return  (pFlags & aiProcess_TransformUVCoords) != 0;
   56|    371|}

_ZN6Assimp20TextureTransformStepC2Ev:
  172|    832|    TextureTransformStep() = default;

_ZNK6Assimp18TriangulateProcess8IsActiveEj:
  179|    371|bool TriangulateProcess::IsActive( unsigned int pFlags) const {
  180|    371|    return (pFlags & aiProcess_Triangulate) != 0;
  181|    371|}
_ZN6Assimp18TriangulateProcess7ExecuteEP7aiScene:
  185|    217|void TriangulateProcess::Execute( aiScene* pScene) {
  186|    217|    ASSIMP_LOG_DEBUG("TriangulateProcess begin");
  187|       |
  188|    217|    bool bHas = false;
  189|  3.46k|    for( unsigned int a = 0; a < pScene->mNumMeshes; a++)
  ------------------
  |  Branch (189:30): [True: 3.24k, False: 217]
  ------------------
  190|  3.24k|    {
  191|  3.24k|        if (pScene->mMeshes[ a ]) {
  ------------------
  |  Branch (191:13): [True: 3.24k, False: 0]
  ------------------
  192|  3.24k|            if ( TriangulateMesh( pScene->mMeshes[ a ] ) ) {
  ------------------
  |  Branch (192:18): [True: 747, False: 2.50k]
  ------------------
  193|    747|                bHas = true;
  194|    747|            }
  195|  3.24k|        }
  196|  3.24k|    }
  197|    217|    if ( bHas ) {
  ------------------
  |  Branch (197:10): [True: 80, False: 137]
  ------------------
  198|     80|        ASSIMP_LOG_INFO( "TriangulateProcess finished. All polygons have been triangulated." );
  199|    137|    } else {
  200|       |        ASSIMP_LOG_DEBUG( "TriangulateProcess finished. There was nothing to be done." );
  201|    137|    }
  202|    217|}
_ZN6Assimp18TriangulateProcess15TriangulateMeshEP6aiMesh:
  206|  3.24k|bool TriangulateProcess::TriangulateMesh( aiMesh* pMesh) {
  207|       |    // Now we have aiMesh::mPrimitiveTypes, so this is only here for test cases
  208|  3.24k|    if (!pMesh->mPrimitiveTypes)    {
  ------------------
  |  Branch (208:9): [True: 0, False: 3.24k]
  ------------------
  209|      0|        bool bNeed = false;
  210|       |
  211|      0|        for( unsigned int a = 0; a < pMesh->mNumFaces; a++) {
  ------------------
  |  Branch (211:34): [True: 0, False: 0]
  ------------------
  212|      0|            const aiFace& face = pMesh->mFaces[a];
  213|      0|            if( face.mNumIndices != 3)  {
  ------------------
  |  Branch (213:17): [True: 0, False: 0]
  ------------------
  214|      0|                bNeed = true;
  215|      0|            }
  216|      0|        }
  217|      0|        if (!bNeed) {
  ------------------
  |  Branch (217:13): [True: 0, False: 0]
  ------------------
  218|      0|            return false;
  219|      0|        }
  220|      0|    }
  221|  3.24k|    else if (!(pMesh->mPrimitiveTypes & aiPrimitiveType_POLYGON)) {
  ------------------
  |  Branch (221:14): [True: 2.50k, False: 747]
  ------------------
  222|  2.50k|        return false;
  223|  2.50k|    }
  224|       |
  225|       |    // Find out how many output faces we'll get
  226|    747|    uint32_t numOut = 0, max_out = 0;
  227|    747|    bool get_normals = true;
  228|   604k|    for( unsigned int a = 0; a < pMesh->mNumFaces; a++) {
  ------------------
  |  Branch (228:30): [True: 603k, False: 747]
  ------------------
  229|   603k|        aiFace& face = pMesh->mFaces[a];
  230|   603k|        if (face.mNumIndices <= 4) {
  ------------------
  |  Branch (230:13): [True: 602k, False: 817]
  ------------------
  231|   602k|            get_normals = false;
  232|   602k|        }
  233|   603k|        if( face.mNumIndices <= 3) {
  ------------------
  |  Branch (233:13): [True: 15.4k, False: 587k]
  ------------------
  234|  15.4k|            ++numOut;
  235|   587k|        } else {
  236|   587k|            numOut += face.mNumIndices-2;
  237|   587k|            max_out = std::max<uint32_t>(max_out,face.mNumIndices);
  238|   587k|        }
  239|   603k|    }
  240|       |
  241|       |    // Just another check whether aiMesh::mPrimitiveTypes is correct
  242|    747|    if (numOut == pMesh->mNumFaces) {
  ------------------
  |  Branch (242:9): [True: 0, False: 747]
  ------------------
  243|      0|        ASSIMP_LOG_ERROR( "Invalidation detected in the number of indices: does not fit to the primitive type." );
  244|      0|        return false;
  245|      0|    }
  246|       |
  247|    747|    aiVector3D *nor_out = nullptr;
  248|       |
  249|       |    // if we don't have normals yet, but expect them to be a cheap side
  250|       |    // product of triangulation anyway, allocate storage for them.
  251|    747|    if (!pMesh->mNormals && get_normals) {
  ------------------
  |  Branch (251:9): [True: 448, False: 299]
  |  Branch (251:29): [True: 131, False: 317]
  ------------------
  252|       |        // XXX need a mechanism to inform the GenVertexNormals process to treat these normals as preprocessed per-face normals
  253|       |    //  nor_out = pMesh->mNormals = new aiVector3D[pMesh->mNumVertices];
  254|    131|    }
  255|       |
  256|       |    // the output mesh will contain triangles, but no polys anymore
  257|    747|    pMesh->mPrimitiveTypes |= aiPrimitiveType_TRIANGLE;
  258|    747|    pMesh->mPrimitiveTypes &= ~aiPrimitiveType_POLYGON;
  259|       |
  260|       |    // The mesh becomes NGON encoded now, during the triangulation process.
  261|    747|    pMesh->mPrimitiveTypes |= aiPrimitiveType_NGONEncodingFlag;
  262|       |
  263|    747|    aiFace* out = new aiFace[numOut](), *curOut = out;
  264|    747|    std::vector<aiVector3D> temp_verts3d(max_out+2); /* temporary storage for vertices */
  265|    747|    std::vector<std::vector<aiVector2D>> temp_poly(1); /* temporary storage for earcut.hpp */
  266|    747|    std::vector<aiVector2D>& temp_verts = temp_poly[0];
  267|    747|    temp_verts.reserve(max_out + 2);
  268|       |
  269|    747|    NGONEncoder ngonEncoder;
  270|       |
  271|       |    // Apply vertex colors to represent the face winding?
  272|       |#ifdef AI_BUILD_TRIANGULATE_COLOR_FACE_WINDING
  273|       |    if (!pMesh->mColors[0])
  274|       |        pMesh->mColors[0] = new aiColor4D[pMesh->mNumVertices];
  275|       |    else
  276|       |        new(pMesh->mColors[0]) aiColor4D[pMesh->mNumVertices];
  277|       |
  278|       |    aiColor4D* clr = pMesh->mColors[0];
  279|       |#endif
  280|       |
  281|       |#ifdef AI_BUILD_TRIANGULATE_DEBUG_POLYS
  282|       |    FILE* fout = fopen(POLY_OUTPUT_FILE,"a");
  283|       |#endif
  284|       |
  285|    747|    const aiVector3D* verts = pMesh->mVertices;
  286|       |
  287|   604k|    for( unsigned int a = 0; a < pMesh->mNumFaces; a++) {
  ------------------
  |  Branch (287:30): [True: 603k, False: 747]
  ------------------
  288|   603k|        aiFace& face = pMesh->mFaces[a];
  289|       |
  290|   603k|        unsigned int* idx = face.mIndices;
  291|   603k|        unsigned int num = face.mNumIndices;
  292|       |
  293|       |        // Apply vertex colors to represent the face winding?
  294|       |#ifdef AI_BUILD_TRIANGULATE_COLOR_FACE_WINDING
  295|       |        for (unsigned int i = 0; i < face.mNumIndices; ++i) {
  296|       |            aiColor4D& c = clr[idx[i]];
  297|       |            c.r = (i+1) / (float)max;
  298|       |            c.b = 1.f - c.r;
  299|       |        }
  300|       |#endif
  301|       |
  302|   603k|        aiFace* const last_face = curOut;
  303|       |
  304|       |        // if it's a simple point,line or triangle: just copy it
  305|   603k|        if( face.mNumIndices <= 3)
  ------------------
  |  Branch (305:13): [True: 15.4k, False: 587k]
  ------------------
  306|  15.4k|        {
  307|  15.4k|            aiFace& nface = *curOut++;
  308|  15.4k|            nface.mNumIndices = face.mNumIndices;
  309|  15.4k|            nface.mIndices    = face.mIndices;
  310|  15.4k|            face.mIndices = nullptr;
  311|       |
  312|       |            // points and lines don't require ngon encoding (and are not supported either!)
  313|  15.4k|            if (nface.mNumIndices == 3) ngonEncoder.ngonEncodeTriangle(&nface);
  ------------------
  |  Branch (313:17): [True: 15.0k, False: 392]
  ------------------
  314|       |
  315|  15.4k|            continue;
  316|  15.4k|        }
  317|       |        // optimized code for quadrilaterals
  318|   587k|        else if ( face.mNumIndices == 4) {
  ------------------
  |  Branch (318:19): [True: 587k, False: 817]
  ------------------
  319|       |
  320|       |            // quads can have at maximum one concave vertex. Determine
  321|       |            // this vertex (if it exists) and start tri-fanning from
  322|       |            // it.
  323|   587k|            unsigned int start_vertex = 0;
  324|  2.90M|            for (unsigned int i = 0; i < 4; ++i) {
  ------------------
  |  Branch (324:38): [True: 2.32M, False: 576k]
  ------------------
  325|  2.32M|                const aiVector3D& v0 = verts[face.mIndices[(i+3) % 4]];
  326|  2.32M|                const aiVector3D& v1 = verts[face.mIndices[(i+2) % 4]];
  327|  2.32M|                const aiVector3D& v2 = verts[face.mIndices[(i+1) % 4]];
  328|       |
  329|  2.32M|                const aiVector3D& v = verts[face.mIndices[i]];
  330|       |
  331|  2.32M|                aiVector3D left = (v0-v);
  332|  2.32M|                aiVector3D diag = (v1-v);
  333|  2.32M|                aiVector3D right = (v2-v);
  334|       |
  335|  2.32M|                left.Normalize();
  336|  2.32M|                diag.Normalize();
  337|  2.32M|                right.Normalize();
  338|       |
  339|  2.32M|                const float angle = std::acos(left*diag) + std::acos(right*diag);
  340|  2.32M|                if (angle > AI_MATH_PI_F) {
  ------------------
  |  Branch (340:21): [True: 10.0k, False: 2.31M]
  ------------------
  341|       |                    // this is the concave point
  342|  10.0k|                    start_vertex = i;
  343|  10.0k|                    break;
  344|  10.0k|                }
  345|  2.32M|            }
  346|       |
  347|   587k|            const unsigned int temp[] = {face.mIndices[0], face.mIndices[1], face.mIndices[2], face.mIndices[3]};
  348|       |
  349|   587k|            aiFace& nface = *curOut++;
  350|   587k|            nface.mNumIndices = 3;
  351|   587k|            nface.mIndices = face.mIndices;
  352|       |
  353|   587k|            nface.mIndices[0] = temp[start_vertex];
  354|   587k|            nface.mIndices[1] = temp[(start_vertex + 1) % 4];
  355|   587k|            nface.mIndices[2] = temp[(start_vertex + 2) % 4];
  356|       |
  357|   587k|            aiFace& sface = *curOut++;
  358|   587k|            sface.mNumIndices = 3;
  359|   587k|            sface.mIndices = new unsigned int[3];
  360|       |
  361|   587k|            sface.mIndices[0] = temp[start_vertex];
  362|   587k|            sface.mIndices[1] = temp[(start_vertex + 2) % 4];
  363|   587k|            sface.mIndices[2] = temp[(start_vertex + 3) % 4];
  364|       |
  365|       |            // prevent double deletion of the indices field
  366|   587k|            face.mIndices = nullptr;
  367|       |
  368|   587k|            ngonEncoder.ngonEncodeQuad(&nface, &sface);
  369|       |
  370|   587k|            continue;
  371|   587k|        }
  372|    817|        else
  373|    817|        {
  374|       |            // A polygon with more than 3 vertices can be either concave or convex.
  375|       |            // Usually everything we're getting is convex and we could easily
  376|       |            // triangulate by tri-fanning. However, LightWave is probably the only
  377|       |            // modeling suite to make extensive use of highly concave, monster polygons ...
  378|       |            // so we need to apply the full 'ear cutting' algorithm to get it right.
  379|       |
  380|       |            // REQUIREMENT: polygon is expected to be simple and *nearly* planar.
  381|       |            // We project it onto a plane to get a 2d triangle.
  382|       |
  383|       |            // Collect all vertices of of the polygon.
  384|  8.79k|            for (unsigned int tmp = 0; tmp < num; ++tmp) {
  ------------------
  |  Branch (384:40): [True: 7.97k, False: 817]
  ------------------
  385|  7.97k|                temp_verts3d[tmp] = verts[idx[tmp]];
  386|  7.97k|            }
  387|       |
  388|       |            // Get newell normal of the polygon. Store it for future use if it's a polygon-only mesh
  389|    817|            aiVector3D n;
  390|    817|            NewellNormal<3, 3, 3>(n, num, &temp_verts3d.front().x, &temp_verts3d.front().y, &temp_verts3d.front().z);
  391|    817|            if (nor_out) {
  ------------------
  |  Branch (391:17): [True: 0, False: 817]
  ------------------
  392|      0|                for (unsigned int tmp = 0; tmp < num; ++tmp)
  ------------------
  |  Branch (392:44): [True: 0, False: 0]
  ------------------
  393|      0|                    nor_out[idx[tmp]] = n;
  394|      0|            }
  395|       |
  396|       |            // Select largest normal coordinate to ignore for projection
  397|    817|            const float ax = (n.x>0 ? n.x : -n.x);
  ------------------
  |  Branch (397:31): [True: 375, False: 442]
  ------------------
  398|    817|            const float ay = (n.y>0 ? n.y : -n.y);
  ------------------
  |  Branch (398:31): [True: 238, False: 579]
  ------------------
  399|    817|            const float az = (n.z>0 ? n.z : -n.z);
  ------------------
  |  Branch (399:31): [True: 466, False: 351]
  ------------------
  400|       |
  401|    817|            unsigned int ac = 0, bc = 1; /* no z coord. projection to xy */
  402|    817|            float inv = n.z;
  403|    817|            if (ax > ay) {
  ------------------
  |  Branch (403:17): [True: 271, False: 546]
  ------------------
  404|    271|                if (ax > az) { /* no x coord. projection to yz */
  ------------------
  |  Branch (404:21): [True: 123, False: 148]
  ------------------
  405|    123|                    ac = 1; bc = 2;
  406|    123|                    inv = n.x;
  407|    123|                }
  408|    271|            }
  409|    546|            else if (ay > az) { /* no y coord. projection to zy */
  ------------------
  |  Branch (409:22): [True: 230, False: 316]
  ------------------
  410|    230|                ac = 2; bc = 0;
  411|    230|                inv = n.y;
  412|    230|            }
  413|       |
  414|       |            // Swap projection axes to take the negated projection vector into account
  415|    817|            if (inv < 0.f) {
  ------------------
  |  Branch (415:17): [True: 318, False: 499]
  ------------------
  416|    318|                std::swap(ac,bc);
  417|    318|            }
  418|       |
  419|    817|            temp_verts.resize(num);
  420|  8.79k|            for (unsigned int tmp = 0; tmp < num; ++tmp) {
  ------------------
  |  Branch (420:40): [True: 7.97k, False: 817]
  ------------------
  421|  7.97k|                temp_verts[tmp].x = verts[idx[tmp]][ac];
  422|  7.97k|                temp_verts[tmp].y = verts[idx[tmp]][bc];
  423|  7.97k|            }
  424|       |
  425|    817|            auto indices = mapbox::earcut(temp_poly);
  426|  3.27k|            for (size_t i = 0; i < indices.size(); i += 3) {
  ------------------
  |  Branch (426:32): [True: 2.45k, False: 817]
  ------------------
  427|  2.45k|                aiFace& nface = *curOut++;
  428|  2.45k|                nface.mIndices = new unsigned int[3];
  429|  2.45k|                nface.mNumIndices = 3;
  430|  2.45k|                nface.mIndices[0] = indices[i];
  431|  2.45k|                nface.mIndices[1] = indices[i + 1];
  432|  2.45k|                nface.mIndices[2] = indices[i + 2];
  433|  2.45k|            }
  434|       |
  435|       |#ifdef AI_BUILD_TRIANGULATE_DEBUG_POLYS
  436|       |            // plot the plane onto which we mapped the polygon to a 2D ASCII pic
  437|       |            aiVector2D bmin,bmax;
  438|       |            ArrayBounds(&temp_verts[0],max,bmin,bmax);
  439|       |
  440|       |            char grid[POLY_GRID_Y][POLY_GRID_X+POLY_GRID_XPAD];
  441|       |            std::fill_n((char*)grid,POLY_GRID_Y*(POLY_GRID_X+POLY_GRID_XPAD),' ');
  442|       |
  443|       |            for (int i =0; i < max; ++i) {
  444|       |                const aiVector2D& v = (temp_verts[i] - bmin) / (bmax-bmin);
  445|       |                const size_t x = static_cast<size_t>(v.x*(POLY_GRID_X-1)), y = static_cast<size_t>(v.y*(POLY_GRID_Y-1));
  446|       |                char* loc = grid[y]+x;
  447|       |                if (grid[y][x] != ' ') {
  448|       |                    for(;*loc != ' '; ++loc);
  449|       |                    *loc++ = '_';
  450|       |                }
  451|       |                *(loc+::ai_snprintf(loc, POLY_GRID_XPAD,"%i",i)) = ' ';
  452|       |            }
  453|       |
  454|       |
  455|       |            for(size_t y = 0; y < POLY_GRID_Y; ++y) {
  456|       |                grid[y][POLY_GRID_X+POLY_GRID_XPAD-1] = '\0';
  457|       |                fprintf(fout,"%s\n",grid[y]);
  458|       |            }
  459|       |
  460|       |            fprintf(fout,"\ntriangulation sequence: ");
  461|       |#endif
  462|    817|        }
  463|       |
  464|       |#ifdef AI_BUILD_TRIANGULATE_DEBUG_POLYS
  465|       |
  466|       |        for(aiFace* f = last_face; f != curOut; ++f) {
  467|       |            unsigned int* i = f->mIndices;
  468|       |            fprintf(fout," (%i %i %i)",i[0],i[1],i[2]);
  469|       |        }
  470|       |
  471|       |        fprintf(fout,"\n*********************************************************************\n");
  472|       |        fflush(fout);
  473|       |
  474|       |#endif
  475|       |
  476|  3.27k|        for(aiFace* f = last_face; f != curOut; ) {
  ------------------
  |  Branch (476:36): [True: 2.45k, False: 817]
  ------------------
  477|  2.45k|            unsigned int* i = f->mIndices;
  478|       |
  479|  2.45k|            i[0] = idx[i[0]];
  480|  2.45k|            i[1] = idx[i[1]];
  481|  2.45k|            i[2] = idx[i[2]];
  482|       |
  483|       |            // IMPROVEMENT: Polygons are not supported yet by this ngon encoding + triangulation step.
  484|       |            //              So we encode polygons as regular triangles. No way to reconstruct the original
  485|       |            //              polygon in this case.
  486|  2.45k|            ngonEncoder.ngonEncodeTriangle(f);
  487|  2.45k|            ++f;
  488|  2.45k|        }
  489|       |
  490|    817|        delete[] face.mIndices;
  491|    817|        face.mIndices = nullptr;
  492|    817|    }
  493|       |
  494|       |#ifdef AI_BUILD_TRIANGULATE_DEBUG_POLYS
  495|       |    fclose(fout);
  496|       |#endif
  497|       |
  498|       |    // kill the old faces
  499|    747|    delete [] pMesh->mFaces;
  500|       |
  501|       |    // ... and store the new ones
  502|    747|    pMesh->mFaces    = out;
  503|    747|    pMesh->mNumFaces = (unsigned int)(curOut-out); /* not necessarily equal to numOut */
  504|    747|    return true;
  505|    747|}
TriangulateProcess.cpp:_ZN12_GLOBAL__N_111NGONEncoderC2Ev:
  103|    747|        NGONEncoder() : mLastNGONFirstIndex((unsigned int)-1) {}
TriangulateProcess.cpp:_ZN12_GLOBAL__N_111NGONEncoder18ngonEncodeTriangleEP6aiFace:
  114|  17.5k|        void ngonEncodeTriangle(aiFace * tri) {
  115|  17.5k|            ai_assert(tri->mNumIndices == 3);
  116|       |
  117|       |            // Rotate indices in new triangle to avoid ngon encoding false ngons
  118|       |            // Otherwise, the new triangle would be considered part of the previous NGON.
  119|  17.5k|            if (isConsideredSameAsLastNgon(tri)) {
  ------------------
  |  Branch (119:17): [True: 24, False: 17.5k]
  ------------------
  120|     24|                std::swap(tri->mIndices[0], tri->mIndices[2]);
  121|     24|                std::swap(tri->mIndices[1], tri->mIndices[2]);
  122|     24|            }
  123|       |
  124|  17.5k|            mLastNGONFirstIndex = tri->mIndices[0];
  125|  17.5k|        }
TriangulateProcess.cpp:_ZNK12_GLOBAL__N_111NGONEncoder26isConsideredSameAsLastNgonEPK6aiFace:
  166|   604k|        bool isConsideredSameAsLastNgon(const aiFace * tri) const {
  167|       |            ai_assert(tri->mNumIndices == 3);
  168|   604k|            return tri->mIndices[0] == mLastNGONFirstIndex;
  169|   604k|        }
TriangulateProcess.cpp:_ZN12_GLOBAL__N_111NGONEncoder14ngonEncodeQuadEP6aiFaceS2_:
  135|   587k|        void ngonEncodeQuad(aiFace *tri1, aiFace *tri2) {
  136|   587k|            ai_assert(tri1->mNumIndices == 3);
  137|   587k|            ai_assert(tri2->mNumIndices == 3);
  138|   587k|            ai_assert(tri1->mIndices[0] == tri2->mIndices[0]);
  139|       |
  140|       |            // If the selected fanning vertex is the same as the previously
  141|       |            // emitted ngon, we use the opposite vertex which also happens to work
  142|       |            // for tri-fanning a concave quad.
  143|       |            // ref: https://github.com/assimp/assimp/pull/3695#issuecomment-805999760
  144|   587k|            if (isConsideredSameAsLastNgon(tri1)) {
  ------------------
  |  Branch (144:17): [True: 0, False: 587k]
  ------------------
  145|       |                // Right-rotate indices for tri1 (index 2 becomes the new fanning vertex)
  146|      0|                std::swap(tri1->mIndices[0], tri1->mIndices[2]);
  147|      0|                std::swap(tri1->mIndices[1], tri1->mIndices[2]);
  148|       |
  149|       |                // Left-rotate indices for tri2 (index 2 becomes the new fanning vertex)
  150|      0|                std::swap(tri2->mIndices[1], tri2->mIndices[2]);
  151|      0|                std::swap(tri2->mIndices[0], tri2->mIndices[2]);
  152|       |
  153|      0|                ai_assert(tri1->mIndices[0] == tri2->mIndices[0]);
  154|      0|            }
  155|       |
  156|   587k|            mLastNGONFirstIndex = tri1->mIndices[0];
  157|   587k|        }
_ZN6mapbox4util3nthILm0E10aiVector2tIfEE3getERKS3_:
   82|  23.9k|    inline static auto get(const aiVector2D& t) {
   83|  23.9k|        return t.x;
   84|  23.9k|    }
_ZN6mapbox4util3nthILm1E10aiVector2tIfEE3getERKS3_:
   88|  23.9k|    inline static auto get(const aiVector2D& t) {
   89|  23.9k|        return t.y;
   90|  23.9k|    }

_ZN6Assimp18TriangulateProcessC2Ev:
   65|    832|    TriangulateProcess() = default;

_ZN6Assimp17ValidateDSProcessC2Ev:
   61|    266|ValidateDSProcess::ValidateDSProcess() : mScene(nullptr) {}
_ZN6Assimp17ValidateDSProcess11ReportErrorEPKcz:
   69|     49|AI_WONT_RETURN void ValidateDSProcess::ReportError(const char *msg, ...) {
   70|     49|    ai_assert(nullptr != msg);
   71|       |
   72|     49|    va_list args;
   73|     49|    va_start(args, msg);
   74|       |
   75|     49|    char szBuffer[3000];
   76|     49|    const int iLen = vsnprintf(szBuffer, sizeof(szBuffer), msg, args);
   77|     49|    ai_assert(iLen > 0);
   78|       |
   79|     49|    va_end(args);
   80|       |
   81|     49|    throw DeadlyImportError("Validation failed: ", std::string(szBuffer, iLen));
   82|     49|}
_ZN6Assimp17ValidateDSProcess13ReportWarningEPKcz:
   84|     62|void ValidateDSProcess::ReportWarning(const char *msg, ...) {
   85|     62|    ai_assert(nullptr != msg);
   86|       |
   87|     62|    va_list args;
   88|     62|    va_start(args, msg);
   89|       |
   90|     62|    char szBuffer[3000];
   91|     62|    const int iLen = vsnprintf(szBuffer, sizeof(szBuffer), msg, args);
   92|     62|    ai_assert(iLen > 0);
   93|       |
   94|     62|    va_end(args);
   95|       |    ASSIMP_LOG_WARN("Validation warning: ", std::string(szBuffer, iLen));
   96|     62|}
_ZN6Assimp17ValidateDSProcess7ExecuteEP7aiScene:
  183|    266|void ValidateDSProcess::Execute(aiScene *pScene) {
  184|    266|    mScene = pScene;
  185|    266|    ASSIMP_LOG_DEBUG("ValidateDataStructureProcess begin");
  186|       |
  187|       |    // validate the node graph of the scene
  188|    266|    Validate(pScene->mRootNode);
  189|       |
  190|       |    // validate all meshes
  191|    266|    if (pScene->mNumMeshes) {
  ------------------
  |  Branch (191:9): [True: 190, False: 76]
  ------------------
  192|    190|        DoValidation(pScene->mMeshes, pScene->mNumMeshes, "mMeshes", "mNumMeshes");
  193|    190|    } else if (!(mScene->mFlags & AI_SCENE_FLAGS_INCOMPLETE)) {
  ------------------
  |  Branch (193:16): [True: 28, False: 48]
  ------------------
  194|     28|        ReportError("aiScene::mNumMeshes is 0. At least one mesh must be there");
  195|     48|    } else if (pScene->mMeshes) {
  ------------------
  |  Branch (195:16): [True: 0, False: 48]
  ------------------
  196|      0|        ReportError("aiScene::mMeshes is non-null although there are no meshes");
  197|      0|    }
  198|       |
  199|       |    // validate all animations
  200|    266|    if (pScene->mNumAnimations) {
  ------------------
  |  Branch (200:9): [True: 33, False: 233]
  ------------------
  201|     33|        DoValidation(pScene->mAnimations, pScene->mNumAnimations,
  202|     33|                "mAnimations", "mNumAnimations");
  203|    233|    } else if (pScene->mAnimations) {
  ------------------
  |  Branch (203:16): [True: 0, False: 233]
  ------------------
  204|      0|        ReportError("aiScene::mAnimations is non-null although there are no animations");
  205|      0|    }
  206|       |
  207|       |    // validate all cameras
  208|    266|    if (pScene->mNumCameras) {
  ------------------
  |  Branch (208:9): [True: 40, False: 226]
  ------------------
  209|     40|        DoValidationWithNameCheck(pScene->mCameras, pScene->mNumCameras,
  210|     40|                "mCameras", "mNumCameras");
  211|    226|    } else if (pScene->mCameras) {
  ------------------
  |  Branch (211:16): [True: 0, False: 226]
  ------------------
  212|      0|        ReportError("aiScene::mCameras is non-null although there are no cameras");
  213|      0|    }
  214|       |
  215|       |    // validate all lights
  216|    266|    if (pScene->mNumLights) {
  ------------------
  |  Branch (216:9): [True: 40, False: 226]
  ------------------
  217|     40|        DoValidationWithNameCheck(pScene->mLights, pScene->mNumLights,
  218|     40|                "mLights", "mNumLights");
  219|    226|    } else if (pScene->mLights) {
  ------------------
  |  Branch (219:16): [True: 0, False: 226]
  ------------------
  220|      0|        ReportError("aiScene::mLights is non-null although there are no lights");
  221|      0|    }
  222|       |
  223|       |    // validate all textures
  224|    266|    if (pScene->mNumTextures) {
  ------------------
  |  Branch (224:9): [True: 7, False: 259]
  ------------------
  225|      7|        DoValidation(pScene->mTextures, pScene->mNumTextures,
  226|      7|                "mTextures", "mNumTextures");
  227|    259|    } else if (pScene->mTextures) {
  ------------------
  |  Branch (227:16): [True: 0, False: 259]
  ------------------
  228|      0|        ReportError("aiScene::mTextures is non-null although there are no textures");
  229|      0|    }
  230|       |
  231|       |    // validate all materials
  232|    266|    if (pScene->mNumMaterials) {
  ------------------
  |  Branch (232:9): [True: 176, False: 90]
  ------------------
  233|    176|        DoValidation(pScene->mMaterials, pScene->mNumMaterials, "mMaterials", "mNumMaterials");
  234|    176|    }
  235|     90|    else if (pScene->mMaterials) {
  ------------------
  |  Branch (235:14): [True: 0, False: 90]
  ------------------
  236|      0|        ReportError("aiScene::mMaterials is non-null although there are no materials");
  237|      0|    }
  238|       |
  239|       |    //  if (!has)ReportError("The aiScene data structure is empty");
  240|       |    ASSIMP_LOG_DEBUG("ValidateDataStructureProcess end");
  241|    266|}
_ZN6Assimp17ValidateDSProcess8ValidateEPK7aiLight:
  244|     57|void ValidateDSProcess::Validate(const aiLight *pLight) {
  245|     57|    if (pLight->mType == aiLightSource_UNDEFINED)
  ------------------
  |  Branch (245:9): [True: 0, False: 57]
  ------------------
  246|      0|        ReportWarning("aiLight::mType is aiLightSource_UNDEFINED");
  247|       |
  248|     57|    if (!pLight->mAttenuationConstant &&
  ------------------
  |  Branch (248:9): [True: 38, False: 19]
  ------------------
  249|     38|            !pLight->mAttenuationLinear &&
  ------------------
  |  Branch (249:13): [True: 31, False: 7]
  ------------------
  250|     31|            !pLight->mAttenuationQuadratic) {
  ------------------
  |  Branch (250:13): [True: 31, False: 0]
  ------------------
  251|     31|        ReportWarning("aiLight::mAttenuationXXX - all are zero");
  252|     31|    }
  253|       |
  254|     57|    if (pLight->mAngleInnerCone > pLight->mAngleOuterCone)
  ------------------
  |  Branch (254:9): [True: 0, False: 57]
  ------------------
  255|      0|        ReportError("aiLight::mAngleInnerCone is larger than aiLight::mAngleOuterCone");
  256|       |
  257|     57|    if (pLight->mColorDiffuse.IsBlack() && pLight->mColorAmbient.IsBlack() && pLight->mColorSpecular.IsBlack()) {
  ------------------
  |  Branch (257:9): [True: 4, False: 53]
  |  Branch (257:44): [True: 3, False: 1]
  |  Branch (257:79): [True: 3, False: 0]
  ------------------
  258|      3|        ReportWarning("aiLight::mColorXXX - all are black and won't have any influence");
  259|      3|    }
  260|     57|}
_ZN6Assimp17ValidateDSProcess8ValidateEPK8aiCamera:
  263|     46|void ValidateDSProcess::Validate(const aiCamera *pCamera) {
  264|     46|    if (pCamera->mClipPlaneFar <= pCamera->mClipPlaneNear)
  ------------------
  |  Branch (264:9): [True: 0, False: 46]
  ------------------
  265|      0|        ReportError("aiCamera::mClipPlaneFar must be >= aiCamera::mClipPlaneNear");
  266|       |
  267|       |    // There are many 3ds files with invalid FOVs. No reason to reject them at all ... a warning is appropriate.
  268|     46|    if (!pCamera->mHorizontalFOV || pCamera->mHorizontalFOV >= (float)AI_MATH_PI)
  ------------------
  |  Branch (268:9): [True: 0, False: 46]
  |  Branch (268:37): [True: 0, False: 46]
  ------------------
  269|      0|        ReportWarning("%f is not a valid value for aiCamera::mHorizontalFOV", pCamera->mHorizontalFOV);
  270|     46|}
_ZN6Assimp17ValidateDSProcess8ValidateEPK6aiMesh:
  273|  3.27k|void ValidateDSProcess::Validate(const aiMesh *pMesh) {
  274|       |    // validate the material index of the mesh
  275|  3.27k|    if (mScene->mNumMaterials && pMesh->mMaterialIndex >= mScene->mNumMaterials) {
  ------------------
  |  Branch (275:9): [True: 3.19k, False: 74]
  |  Branch (275:34): [True: 0, False: 3.19k]
  ------------------
  276|      0|        ReportError("aiMesh::mMaterialIndex is invalid (value: %i maximum: %i)",
  277|      0|                pMesh->mMaterialIndex, mScene->mNumMaterials - 1);
  278|      0|    }
  279|       |
  280|  3.27k|    Validate(&pMesh->mName);
  281|       |
  282|   833k|    for (unsigned int i = 0; i < pMesh->mNumFaces; ++i) {
  ------------------
  |  Branch (282:30): [True: 830k, False: 3.27k]
  ------------------
  283|   830k|        aiFace &face = pMesh->mFaces[i];
  284|       |
  285|   830k|        if (pMesh->mPrimitiveTypes) {
  ------------------
  |  Branch (285:13): [True: 366k, False: 463k]
  ------------------
  286|   366k|            switch (face.mNumIndices) {
  287|      0|            case 0:
  ------------------
  |  Branch (287:13): [True: 0, False: 366k]
  ------------------
  288|      0|                ReportError("aiMesh::mFaces[%i].mNumIndices is 0", i);
  289|    491|            case 1:
  ------------------
  |  Branch (289:13): [True: 491, False: 366k]
  ------------------
  290|    491|                if (0 == (pMesh->mPrimitiveTypes & aiPrimitiveType_POINT)) {
  ------------------
  |  Branch (290:21): [True: 0, False: 491]
  ------------------
  291|      0|                    ReportError("aiMesh::mFaces[%i] is a POINT but aiMesh::mPrimitiveTypes "
  292|      0|                                "does not report the POINT flag",
  293|      0|                            i);
  294|      0|                }
  295|    491|                break;
  296|  1.53k|            case 2:
  ------------------
  |  Branch (296:13): [True: 1.53k, False: 365k]
  ------------------
  297|  1.53k|                if (0 == (pMesh->mPrimitiveTypes & aiPrimitiveType_LINE)) {
  ------------------
  |  Branch (297:21): [True: 0, False: 1.53k]
  ------------------
  298|      0|                    ReportError("aiMesh::mFaces[%i] is a LINE but aiMesh::mPrimitiveTypes "
  299|      0|                                "does not report the LINE flag",
  300|      0|                            i);
  301|      0|                }
  302|  1.53k|                break;
  303|   114k|            case 3:
  ------------------
  |  Branch (303:13): [True: 114k, False: 252k]
  ------------------
  304|   114k|                if (0 == (pMesh->mPrimitiveTypes & aiPrimitiveType_TRIANGLE)) {
  ------------------
  |  Branch (304:21): [True: 0, False: 114k]
  ------------------
  305|      0|                    ReportError("aiMesh::mFaces[%i] is a TRIANGLE but aiMesh::mPrimitiveTypes "
  306|      0|                                "does not report the TRIANGLE flag",
  307|      0|                            i);
  308|      0|                }
  309|   114k|                break;
  310|   250k|            default:
  ------------------
  |  Branch (310:13): [True: 250k, False: 116k]
  ------------------
  311|   250k|                if (0 == (pMesh->mPrimitiveTypes & aiPrimitiveType_POLYGON)) {
  ------------------
  |  Branch (311:21): [True: 0, False: 250k]
  ------------------
  312|      0|                    this->ReportError("aiMesh::mFaces[%i] is a POLYGON but aiMesh::mPrimitiveTypes "
  313|      0|                                      "does not report the POLYGON flag",
  314|      0|                            i);
  315|      0|                }
  316|   250k|                break;
  317|   366k|            };
  318|   366k|        }
  319|       |
  320|   830k|        if (!face.mIndices)
  ------------------
  |  Branch (320:13): [True: 0, False: 830k]
  ------------------
  321|      0|            ReportError("aiMesh::mFaces[%i].mIndices is nullptr", i);
  322|   830k|    }
  323|       |
  324|       |    // positions must always be there ...
  325|  3.27k|    if (!pMesh->mNumVertices || (!pMesh->mVertices && !mScene->mFlags)) {
  ------------------
  |  Branch (325:9): [True: 1, False: 3.26k]
  |  Branch (325:34): [True: 0, False: 3.26k]
  |  Branch (325:55): [True: 0, False: 0]
  ------------------
  326|      1|        ReportError("The mesh %s contains no vertices", pMesh->mName.C_Str());
  327|      1|    }
  328|       |
  329|  3.27k|    if (pMesh->mNumVertices > AI_MAX_VERTICES) {
  ------------------
  |  Branch (329:9): [True: 0, False: 3.27k]
  ------------------
  330|      0|        ReportError("Mesh has too many vertices: %u, but the limit is %u", pMesh->mNumVertices, AI_MAX_VERTICES);
  331|      0|    }
  332|  3.27k|    if (pMesh->mNumFaces > AI_MAX_FACES) {
  ------------------
  |  Branch (332:9): [True: 0, False: 3.27k]
  ------------------
  333|      0|        ReportError("Mesh has too many faces: %u, but the limit is %u", pMesh->mNumFaces, AI_MAX_FACES);
  334|      0|    }
  335|       |
  336|       |    // if tangents are there there must also be bitangent vectors ...
  337|  3.27k|    if ((pMesh->mTangents != nullptr) != (pMesh->mBitangents != nullptr)) {
  ------------------
  |  Branch (337:9): [True: 0, False: 3.27k]
  ------------------
  338|      0|        ReportError("If there are tangents, bitangent vectors must be present as well");
  339|      0|    }
  340|       |
  341|       |    // faces, too
  342|  3.27k|    if (!pMesh->mNumFaces || (!pMesh->mFaces && !mScene->mFlags)) {
  ------------------
  |  Branch (342:9): [True: 1, False: 3.26k]
  |  Branch (342:31): [True: 0, False: 3.26k]
  |  Branch (342:49): [True: 0, False: 0]
  ------------------
  343|      0|        ReportError("Mesh %s contains no faces", pMesh->mName.C_Str());
  344|      0|    }
  345|       |
  346|       |    // now check whether the face indexing layout is correct:
  347|       |    // unique vertices, pseudo-indexed.
  348|  3.27k|    std::vector<bool> abRefList;
  349|  3.27k|    abRefList.resize(pMesh->mNumVertices, false);
  350|   833k|    for (unsigned int i = 0; i < pMesh->mNumFaces; ++i) {
  ------------------
  |  Branch (350:30): [True: 830k, False: 3.27k]
  ------------------
  351|   830k|        aiFace &face = pMesh->mFaces[i];
  352|   830k|        if (face.mNumIndices > AI_MAX_FACE_INDICES) {
  ------------------
  |  Branch (352:13): [True: 0, False: 830k]
  ------------------
  353|      0|            ReportError("Face %u has too many faces: %u, but the limit is %u", i, face.mNumIndices, AI_MAX_FACE_INDICES);
  354|      0|        }
  355|       |
  356|  3.91M|        for (unsigned int a = 0; a < face.mNumIndices; ++a) {
  ------------------
  |  Branch (356:34): [True: 3.08M, False: 830k]
  ------------------
  357|  3.08M|            if (face.mIndices[a] >= pMesh->mNumVertices) {
  ------------------
  |  Branch (357:17): [True: 0, False: 3.08M]
  ------------------
  358|      0|                ReportError("aiMesh::mFaces[%i]::mIndices[%i] is out of range", i, a);
  359|      0|            }
  360|  3.08M|            abRefList[face.mIndices[a]] = true;
  361|  3.08M|        }
  362|   830k|    }
  363|       |
  364|       |    // check whether there are vertices that aren't referenced by a face
  365|  3.27k|    bool b = false;
  366|  3.06M|    for (unsigned int i = 0; i < pMesh->mNumVertices; ++i) {
  ------------------
  |  Branch (366:30): [True: 3.06M, False: 3.27k]
  ------------------
  367|  3.06M|        if (!abRefList[i]) b = true;
  ------------------
  |  Branch (367:13): [True: 0, False: 3.06M]
  ------------------
  368|  3.06M|    }
  369|  3.27k|    abRefList.clear();
  370|  3.27k|    if (b) {
  ------------------
  |  Branch (370:9): [True: 0, False: 3.27k]
  ------------------
  371|      0|        ReportWarning("There are unreferenced vertices");
  372|      0|    }
  373|       |
  374|       |    // vertex color channel 2 may not be set if channel 1 is zero ...
  375|  3.27k|    {
  376|  3.27k|        unsigned int i = 0;
  377|  3.53k|        for (; i < AI_MAX_NUMBER_OF_COLOR_SETS; ++i) {
  ------------------
  |  Branch (377:16): [True: 3.53k, False: 1]
  ------------------
  378|  3.53k|            if (!pMesh->HasVertexColors(i)) break;
  ------------------
  |  Branch (378:17): [True: 3.26k, False: 262]
  ------------------
  379|  3.53k|        }
  380|  29.1k|        for (; i < AI_MAX_NUMBER_OF_COLOR_SETS; ++i)
  ------------------
  |  Branch (380:16): [True: 25.8k, False: 3.27k]
  ------------------
  381|  25.8k|            if (pMesh->HasVertexColors(i)) {
  ------------------
  |  Branch (381:17): [True: 0, False: 25.8k]
  ------------------
  382|      0|                ReportError("Vertex color channel %i is exists "
  383|      0|                            "although the previous channel was nullptr.",
  384|      0|                        i);
  385|      0|            }
  386|  3.27k|    }
  387|       |
  388|       |    // now validate all bones
  389|  3.27k|    if (pMesh->mNumBones) {
  ------------------
  |  Branch (389:9): [True: 29, False: 3.24k]
  ------------------
  390|     29|        if (!pMesh->mBones) {
  ------------------
  |  Branch (390:13): [True: 0, False: 29]
  ------------------
  391|      0|            ReportError("aiMesh::mBones is nullptr (aiMesh::mNumBones is %i)",
  392|      0|                    pMesh->mNumBones);
  393|      0|        }
  394|     29|        std::unique_ptr<float[]> afSum(nullptr);
  395|     29|        if (pMesh->mNumVertices) {
  ------------------
  |  Branch (395:13): [True: 29, False: 0]
  ------------------
  396|     29|            afSum.reset(new float[pMesh->mNumVertices]);
  397|   109k|            for (unsigned int i = 0; i < pMesh->mNumVertices; ++i)
  ------------------
  |  Branch (397:38): [True: 109k, False: 29]
  ------------------
  398|   109k|                afSum[i] = 0.0f;
  399|     29|        }
  400|       |
  401|       |        // check whether there are duplicate bone names
  402|  3.14k|        for (unsigned int i = 0; i < pMesh->mNumBones; ++i) {
  ------------------
  |  Branch (402:34): [True: 3.11k, False: 29]
  ------------------
  403|  3.11k|            const aiBone *bone = pMesh->mBones[i];
  404|  3.11k|            if (bone->mNumWeights > AI_MAX_BONE_WEIGHTS) {
  ------------------
  |  Branch (404:17): [True: 0, False: 3.11k]
  ------------------
  405|      0|                ReportError("Bone %u has too many weights: %u, but the limit is %u", i, bone->mNumWeights, AI_MAX_BONE_WEIGHTS);
  406|      0|            }
  407|       |
  408|  3.11k|            if (!pMesh->mBones[i]) {
  ------------------
  |  Branch (408:17): [True: 0, False: 3.11k]
  ------------------
  409|      0|                ReportError("aiMesh::mBones[%i] is nullptr (aiMesh::mNumBones is %i)",
  410|      0|                        i, pMesh->mNumBones);
  411|      0|            }
  412|  3.11k|            Validate(pMesh, pMesh->mBones[i], afSum.get());
  413|       |
  414|   973k|            for (unsigned int a = i + 1; a < pMesh->mNumBones; ++a) {
  ------------------
  |  Branch (414:42): [True: 970k, False: 3.11k]
  ------------------
  415|   970k|                if (pMesh->mBones[i]->mName == pMesh->mBones[a]->mName) {
  ------------------
  |  Branch (415:21): [True: 0, False: 970k]
  ------------------
  416|      0|                    const char *name = "unknown";
  417|      0|                    if (nullptr != pMesh->mBones[i]->mName.C_Str()) {
  ------------------
  |  Branch (417:25): [True: 0, False: 0]
  ------------------
  418|      0|                        name = pMesh->mBones[i]->mName.C_Str();
  419|      0|                    }
  420|      0|                    ReportError("aiMesh::mBones[%i], name = \"%s\" has the same name as "
  421|      0|                                "aiMesh::mBones[%i]",
  422|      0|                            i, name, a);
  423|      0|                }
  424|   970k|            }
  425|  3.11k|        }
  426|       |        // check whether all bone weights for a vertex sum to 1.0 ...
  427|   109k|        for (unsigned int i = 0; i < pMesh->mNumVertices; ++i) {
  ------------------
  |  Branch (427:34): [True: 109k, False: 29]
  ------------------
  428|   109k|            if (afSum[i] && (afSum[i] <= 0.94 || afSum[i] >= 1.05)) {
  ------------------
  |  Branch (428:17): [True: 109k, False: 1]
  |  Branch (428:30): [True: 0, False: 109k]
  |  Branch (428:50): [True: 0, False: 109k]
  ------------------
  429|      0|                ReportWarning("aiMesh::mVertices[%i]: bone weight sum != 1.0 (sum is %f)", i, afSum[i]);
  430|      0|            }
  431|   109k|        }
  432|  3.24k|    } else if (pMesh->mBones) {
  ------------------
  |  Branch (432:16): [True: 0, False: 3.24k]
  ------------------
  433|      0|        ReportError("aiMesh::mBones is non-null although there are no bones");
  434|      0|    }
  435|  3.27k|}
_ZN6Assimp17ValidateDSProcess8ValidateEPK6aiMeshPK6aiBonePf:
  438|  3.11k|void ValidateDSProcess::Validate(const aiMesh *pMesh, const aiBone *pBone, float *afSum) {
  439|  3.11k|    this->Validate(&pBone->mName);
  440|       |
  441|  3.11k|    if (!pBone->mNumWeights) {
  ------------------
  |  Branch (441:9): [True: 0, False: 3.11k]
  ------------------
  442|      0|        ReportWarning("aiBone::mNumWeights is zero");
  443|      0|    }
  444|       |
  445|       |    // check whether all vertices affected by this bone are valid
  446|   135k|    for (unsigned int i = 0; i < pBone->mNumWeights; ++i) {
  ------------------
  |  Branch (446:30): [True: 132k, False: 3.11k]
  ------------------
  447|   132k|        if (pBone->mWeights[i].mVertexId >= pMesh->mNumVertices) {
  ------------------
  |  Branch (447:13): [True: 0, False: 132k]
  ------------------
  448|      0|            ReportError("aiBone::mWeights[%i].mVertexId is out of range", i);
  449|   132k|        } else if (!pBone->mWeights[i].mWeight || pBone->mWeights[i].mWeight > 1.0f) {
  ------------------
  |  Branch (449:20): [True: 0, False: 132k]
  |  Branch (449:51): [True: 0, False: 132k]
  ------------------
  450|      0|                ReportWarning("aiBone::mWeights[%i].mWeight has an invalid value %i. Value must be greater than zero and less than 1.", i, pBone->mWeights[i].mWeight);
  451|      0|        }
  452|   132k|        afSum[pBone->mWeights[i].mVertexId] += pBone->mWeights[i].mWeight;
  453|   132k|    }
  454|  3.11k|}
_ZN6Assimp17ValidateDSProcess8ValidateEPK11aiAnimation:
  457|     48|void ValidateDSProcess::Validate(const aiAnimation *pAnimation) {
  458|     48|    Validate(&pAnimation->mName);
  459|       |
  460|       |    // validate all animations
  461|     48|    if (pAnimation->mNumChannels || pAnimation->mNumMorphMeshChannels) {
  ------------------
  |  Branch (461:9): [True: 47, False: 1]
  |  Branch (461:37): [True: 0, False: 1]
  ------------------
  462|     47|        if (!pAnimation->mChannels && pAnimation->mNumChannels) {
  ------------------
  |  Branch (462:13): [True: 0, False: 47]
  |  Branch (462:39): [True: 0, False: 0]
  ------------------
  463|      0|            ReportError("aiAnimation::mChannels is nullptr (aiAnimation::mNumChannels is %i)",
  464|      0|                    pAnimation->mNumChannels);
  465|      0|        }
  466|     47|        if (!pAnimation->mMorphMeshChannels && pAnimation->mNumMorphMeshChannels) {
  ------------------
  |  Branch (466:13): [True: 47, False: 0]
  |  Branch (466:48): [True: 0, False: 47]
  ------------------
  467|      0|            ReportError("aiAnimation::mMorphMeshChannels is nullptr (aiAnimation::mNumMorphMeshChannels is %i)",
  468|      0|                    pAnimation->mNumMorphMeshChannels);
  469|      0|        }
  470|    678|        for (unsigned int i = 0; i < pAnimation->mNumChannels; ++i) {
  ------------------
  |  Branch (470:34): [True: 631, False: 47]
  ------------------
  471|    631|            if (!pAnimation->mChannels[i]) {
  ------------------
  |  Branch (471:17): [True: 0, False: 631]
  ------------------
  472|      0|                ReportError("aiAnimation::mChannels[%i] is nullptr (aiAnimation::mNumChannels is %i)",
  473|      0|                        i, pAnimation->mNumChannels);
  474|      0|            }
  475|    631|            Validate(pAnimation, pAnimation->mChannels[i]);
  476|    631|        }
  477|     47|        for (unsigned int i = 0; i < pAnimation->mNumMorphMeshChannels; ++i) {
  ------------------
  |  Branch (477:34): [True: 0, False: 47]
  ------------------
  478|      0|            if (!pAnimation->mMorphMeshChannels[i]) {
  ------------------
  |  Branch (478:17): [True: 0, False: 0]
  ------------------
  479|      0|                ReportError("aiAnimation::mMorphMeshChannels[%i] is nullptr (aiAnimation::mNumMorphMeshChannels is %i)",
  480|      0|                        i, pAnimation->mNumMorphMeshChannels);
  481|      0|            }
  482|      0|            Validate(pAnimation, pAnimation->mMorphMeshChannels[i]);
  483|      0|        }
  484|     47|    } else {
  485|      1|        ReportError("aiAnimation::mNumChannels is 0. At least one node animation channel must be there.");
  486|      1|    }
  487|     48|}
_ZN6Assimp17ValidateDSProcess24SearchForInvalidTexturesEPK10aiMaterial13aiTextureType:
  491|  36.3k|        aiTextureType type) {
  492|  36.3k|    const char *szType = aiTextureTypeToString(type);
  493|       |
  494|       |    // ****************************************************************************
  495|       |    // Search all keys of the material ...
  496|       |    // textures must be specified with ascending indices
  497|       |    // (e.g. diffuse #2 may not be specified if diffuse #1 is not there ...)
  498|       |    // ****************************************************************************
  499|       |
  500|  36.3k|    int iNumIndices = 0;
  501|  36.3k|    int iIndex = -1;
  502|   348k|    for (unsigned int i = 0; i < pMaterial->mNumProperties; ++i) {
  ------------------
  |  Branch (502:30): [True: 311k, False: 36.3k]
  ------------------
  503|   311k|        aiMaterialProperty *prop = pMaterial->mProperties[i];
  504|   311k|        ai_assert(nullptr != prop);
  505|   311k|        if (!::strcmp(prop->mKey.data, "$tex.file") && prop->mSemantic == static_cast<unsigned int>(type)) {
  ------------------
  |  Branch (505:13): [True: 5.20k, False: 306k]
  |  Branch (505:56): [True: 306, False: 4.89k]
  ------------------
  506|    306|            iIndex = std::max(iIndex, (int)prop->mIndex);
  507|    306|            ++iNumIndices;
  508|       |
  509|    306|            if (aiPTI_String != prop->mType) {
  ------------------
  |  Branch (509:17): [True: 0, False: 306]
  ------------------
  510|      0|                ReportError("Material property %s is expected to be a string", prop->mKey.data);
  511|      0|            }
  512|    306|        }
  513|   311k|    }
  514|  36.3k|    if (iIndex + 1 != iNumIndices) {
  ------------------
  |  Branch (514:9): [True: 0, False: 36.3k]
  ------------------
  515|      0|        ReportError("%s #%i is set, but there are only %i %s textures",
  516|      0|                szType, iIndex, iNumIndices, szType);
  517|      0|    }
  518|  36.3k|    if (!iNumIndices) {
  ------------------
  |  Branch (518:9): [True: 36.1k, False: 190]
  ------------------
  519|  36.1k|        return;
  520|  36.1k|    }
  521|    190|    std::vector<aiTextureMapping> mappings(iNumIndices);
  522|       |
  523|       |    // Now check whether all UV indices are valid ...
  524|    190|    bool bNoSpecified = true;
  525|  3.78k|    for (unsigned int i = 0; i < pMaterial->mNumProperties; ++i) {
  ------------------
  |  Branch (525:30): [True: 3.59k, False: 190]
  ------------------
  526|  3.59k|        aiMaterialProperty *prop = pMaterial->mProperties[i];
  527|  3.59k|        if (static_cast<aiTextureType>(prop->mSemantic) != type) {
  ------------------
  |  Branch (527:13): [True: 2.93k, False: 665]
  ------------------
  528|  2.93k|            continue;
  529|  2.93k|        }
  530|       |
  531|    665|        if ((int)prop->mIndex >= iNumIndices) {
  ------------------
  |  Branch (531:13): [True: 0, False: 665]
  ------------------
  532|      0|            ReportError("Found texture property with index %i, although there "
  533|      0|                        "are only %i textures of type %s",
  534|      0|                    prop->mIndex, iNumIndices, szType);
  535|      0|        }
  536|       |
  537|    665|        if (!::strcmp(prop->mKey.data, "$tex.mapping")) {
  ------------------
  |  Branch (537:13): [True: 2, False: 663]
  ------------------
  538|      2|            if (aiPTI_Integer != prop->mType || prop->mDataLength < sizeof(aiTextureMapping)) {
  ------------------
  |  Branch (538:17): [True: 0, False: 2]
  |  Branch (538:49): [True: 0, False: 2]
  ------------------
  539|      0|                ReportError("Material property %s%i is expected to be an integer (size is %i)",
  540|      0|                        prop->mKey.data, prop->mIndex, prop->mDataLength);
  541|      0|            }
  542|      2|            mappings[prop->mIndex] = *((aiTextureMapping *)prop->mData);
  543|    663|        } else if (!::strcmp(prop->mKey.data, "$tex.uvtrafo")) {
  ------------------
  |  Branch (543:20): [True: 17, False: 646]
  ------------------
  544|     17|            if (aiPTI_Float != prop->mType || prop->mDataLength < sizeof(aiUVTransform)) {
  ------------------
  |  Branch (544:17): [True: 0, False: 17]
  |  Branch (544:47): [True: 0, False: 17]
  ------------------
  545|      0|                ReportError("Material property %s%i is expected to be 5 floats large (size is %i)",
  546|      0|                        prop->mKey.data, prop->mIndex, prop->mDataLength);
  547|      0|            }
  548|       |            //mappings[prop->mIndex] = ((aiUVTransform*)prop->mData);
  549|    646|        } else if (!::strcmp(prop->mKey.data, "$tex.uvwsrc")) {
  ------------------
  |  Branch (549:20): [True: 238, False: 408]
  ------------------
  550|    238|            if (aiPTI_Integer != prop->mType || sizeof(int) > prop->mDataLength) {
  ------------------
  |  Branch (550:17): [True: 0, False: 238]
  |  Branch (550:49): [True: 0, False: 238]
  ------------------
  551|      0|                ReportError("Material property %s%i is expected to be an integer (size is %i)",
  552|      0|                        prop->mKey.data, prop->mIndex, prop->mDataLength);
  553|      0|            }
  554|    238|            bNoSpecified = false;
  555|       |
  556|       |            // Ignore UV indices for texture channels that are not there ...
  557|       |
  558|       |            // Get the value
  559|    238|            iIndex = *((unsigned int *)prop->mData);
  560|       |
  561|       |            // Check whether there is a mesh using this material
  562|       |            // which has not enough UV channels ...
  563|  1.96k|            for (unsigned int a = 0; a < mScene->mNumMeshes; ++a) {
  ------------------
  |  Branch (563:38): [True: 1.72k, False: 238]
  ------------------
  564|  1.72k|                aiMesh *mesh = this->mScene->mMeshes[a];
  565|  1.72k|                if (mesh->mMaterialIndex == (unsigned int)i) {
  ------------------
  |  Branch (565:21): [True: 41, False: 1.68k]
  ------------------
  566|     41|                    int iChannels = 0;
  567|     82|                    while (mesh->HasTextureCoords(iChannels))
  ------------------
  |  Branch (567:28): [True: 41, False: 41]
  ------------------
  568|     41|                        ++iChannels;
  569|     41|                    if (iIndex >= iChannels) {
  ------------------
  |  Branch (569:25): [True: 0, False: 41]
  ------------------
  570|      0|                        ReportWarning("Invalid UV index: %i (key %s). Mesh %i has only %i UV channels",
  571|      0|                                iIndex, prop->mKey.data, a, iChannels);
  572|      0|                    }
  573|     41|                }
  574|  1.72k|            }
  575|    238|        }
  576|    665|    }
  577|    190|    if (bNoSpecified) {
  ------------------
  |  Branch (577:9): [True: 67, False: 123]
  ------------------
  578|       |        // Assume that all textures are using the first UV channel
  579|    563|        for (unsigned int a = 0; a < mScene->mNumMeshes; ++a) {
  ------------------
  |  Branch (579:34): [True: 496, False: 67]
  ------------------
  580|    496|            aiMesh *mesh = mScene->mMeshes[a];
  581|    496|            if (mesh->mMaterialIndex == (unsigned int)iIndex && mappings[0] == aiTextureMapping_UV) {
  ------------------
  |  Branch (581:17): [True: 72, False: 424]
  |  Branch (581:65): [True: 72, False: 0]
  ------------------
  582|     72|                if (!mesh->mTextureCoords[0]) {
  ------------------
  |  Branch (582:21): [True: 5, False: 67]
  ------------------
  583|       |                    // This is a special case ... it could be that the
  584|       |                    // original mesh format intended the use of a special
  585|       |                    // mapping here.
  586|      5|                    ReportWarning("UV-mapped texture, but there are no UV coords");
  587|      5|                }
  588|     72|            }
  589|    496|        }
  590|     67|    }
  591|    190|}
_ZN6Assimp17ValidateDSProcess8ValidateEPK10aiMaterial:
  593|  2.14k|void ValidateDSProcess::Validate(const aiMaterial *pMaterial) {
  594|       |    // check whether there are material keys that are obviously not legal
  595|  20.4k|    for (unsigned int i = 0; i < pMaterial->mNumProperties; ++i) {
  ------------------
  |  Branch (595:30): [True: 18.3k, False: 2.14k]
  ------------------
  596|  18.3k|        const aiMaterialProperty *prop = pMaterial->mProperties[i];
  597|  18.3k|        if (!prop) {
  ------------------
  |  Branch (597:13): [True: 0, False: 18.3k]
  ------------------
  598|      0|            ReportError("aiMaterial::mProperties[%i] is nullptr (aiMaterial::mNumProperties is %i)",
  599|      0|                    i, pMaterial->mNumProperties);
  600|      0|        }
  601|  18.3k|        if (!prop->mDataLength || !prop->mData) {
  ------------------
  |  Branch (601:13): [True: 0, False: 18.3k]
  |  Branch (601:35): [True: 0, False: 18.3k]
  ------------------
  602|      0|            ReportError("aiMaterial::mProperties[%i].mDataLength or "
  603|      0|                        "aiMaterial::mProperties[%i].mData is 0",
  604|      0|                    i, i);
  605|      0|        }
  606|       |        // check all predefined types
  607|  18.3k|        if (aiPTI_String == prop->mType) {
  ------------------
  |  Branch (607:13): [True: 2.39k, False: 15.9k]
  ------------------
  608|       |            // FIX: strings are now stored in a less expensive way, but we can't use the
  609|       |            // validation routine for 'normal' aiStrings
  610|  2.39k|            if (prop->mDataLength < 5 || prop->mDataLength < 4 + (*reinterpret_cast<uint32_t *>(prop->mData)) + 1) {
  ------------------
  |  Branch (610:17): [True: 0, False: 2.39k]
  |  Branch (610:42): [True: 0, False: 2.39k]
  ------------------
  611|      0|                ReportError("aiMaterial::mProperties[%i].mDataLength is "
  612|      0|                            "too small to contain a string (%i, needed: %i)",
  613|      0|                        i, prop->mDataLength, static_cast<int>(sizeof(aiString)));
  614|      0|            }
  615|  2.39k|            if (prop->mData[prop->mDataLength - 1]) {
  ------------------
  |  Branch (615:17): [True: 0, False: 2.39k]
  ------------------
  616|      0|                ReportError("Missing null-terminator in string material property");
  617|      0|            }
  618|       |            //  Validate((const aiString*)prop->mData);
  619|  15.9k|        } else if (aiPTI_Float == prop->mType) {
  ------------------
  |  Branch (619:20): [True: 12.6k, False: 3.25k]
  ------------------
  620|  12.6k|            if (prop->mDataLength < sizeof(float)) {
  ------------------
  |  Branch (620:17): [True: 0, False: 12.6k]
  ------------------
  621|      0|                ReportError("aiMaterial::mProperties[%i].mDataLength is "
  622|      0|                            "too small to contain a float (%i, needed: %i)",
  623|      0|                        i, prop->mDataLength, static_cast<int>(sizeof(float)));
  624|      0|            }
  625|  12.6k|        } else if (aiPTI_Integer == prop->mType) {
  ------------------
  |  Branch (625:20): [True: 3.25k, False: 3]
  ------------------
  626|  3.25k|            if (prop->mDataLength < sizeof(int)) {
  ------------------
  |  Branch (626:17): [True: 0, False: 3.25k]
  ------------------
  627|      0|                ReportError("aiMaterial::mProperties[%i].mDataLength is "
  628|      0|                            "too small to contain an integer (%i, needed: %i)",
  629|      0|                        i, prop->mDataLength, static_cast<int>(sizeof(int)));
  630|      0|            }
  631|  3.25k|        }
  632|       |        // TODO: check whether there is a key with an unknown name ...
  633|  18.3k|    }
  634|       |
  635|       |    // make some more specific tests
  636|  2.14k|    ai_real fTemp;
  637|  2.14k|    int iShading;
  638|  2.14k|    if (AI_SUCCESS == aiGetMaterialInteger(pMaterial, AI_MATKEY_SHADING_MODEL, &iShading)) {
  ------------------
  |  Branch (638:9): [True: 2.06k, False: 73]
  ------------------
  639|  2.06k|        switch ((aiShadingMode)iShading) {
  640|      6|        case aiShadingMode_Blinn:
  ------------------
  |  Branch (640:9): [True: 6, False: 2.06k]
  ------------------
  641|      6|        case aiShadingMode_CookTorrance:
  ------------------
  |  Branch (641:9): [True: 0, False: 2.06k]
  ------------------
  642|     50|        case aiShadingMode_Phong:
  ------------------
  |  Branch (642:9): [True: 44, False: 2.02k]
  ------------------
  643|       |
  644|     50|            if (AI_SUCCESS != aiGetMaterialFloat(pMaterial, AI_MATKEY_SHININESS, &fTemp)) {
  ------------------
  |  Branch (644:17): [True: 0, False: 50]
  ------------------
  645|      0|                ReportWarning("A specular shading model is specified but there is no "
  646|      0|                              "AI_MATKEY_SHININESS key");
  647|      0|            }
  648|     50|            if (AI_SUCCESS == aiGetMaterialFloat(pMaterial, AI_MATKEY_SHININESS_STRENGTH, &fTemp) && !fTemp) {
  ------------------
  |  Branch (648:17): [True: 7, False: 43]
  |  Branch (648:102): [True: 0, False: 7]
  ------------------
  649|      0|                ReportWarning("A specular shading model is specified but the value of the "
  650|      0|                              "AI_MATKEY_SHININESS_STRENGTH key is 0.0");
  651|      0|            }
  652|     50|            break;
  653|  2.01k|        default:
  ------------------
  |  Branch (653:9): [True: 2.01k, False: 50]
  ------------------
  654|  2.01k|            break;
  655|  2.06k|        }
  656|  2.06k|    }
  657|       |
  658|  2.14k|    if (AI_SUCCESS == aiGetMaterialFloat(pMaterial, AI_MATKEY_OPACITY, &fTemp) && (!fTemp || fTemp > 1.01)) {
  ------------------
  |  Branch (658:9): [True: 2.00k, False: 138]
  |  Branch (658:84): [True: 17, False: 1.98k]
  |  Branch (658:94): [True: 6, False: 1.97k]
  ------------------
  659|     23|        ReportWarning("Invalid opacity value (must be 0 < opacity < 1.0)");
  660|     23|    }
  661|       |
  662|       |    // Check whether there are invalid texture keys
  663|       |    // TODO: that's a relict of the past, where texture type and index were baked
  664|       |    // into the material string ... we could do that in one single pass.
  665|  2.14k|    SearchForInvalidTextures(pMaterial, aiTextureType_DIFFUSE);
  666|  2.14k|    SearchForInvalidTextures(pMaterial, aiTextureType_SPECULAR);
  667|  2.14k|    SearchForInvalidTextures(pMaterial, aiTextureType_AMBIENT);
  668|  2.14k|    SearchForInvalidTextures(pMaterial, aiTextureType_EMISSIVE);
  669|  2.14k|    SearchForInvalidTextures(pMaterial, aiTextureType_OPACITY);
  670|  2.14k|    SearchForInvalidTextures(pMaterial, aiTextureType_SHININESS);
  671|  2.14k|    SearchForInvalidTextures(pMaterial, aiTextureType_HEIGHT);
  672|  2.14k|    SearchForInvalidTextures(pMaterial, aiTextureType_NORMALS);
  673|  2.14k|    SearchForInvalidTextures(pMaterial, aiTextureType_DISPLACEMENT);
  674|  2.14k|    SearchForInvalidTextures(pMaterial, aiTextureType_LIGHTMAP);
  675|  2.14k|    SearchForInvalidTextures(pMaterial, aiTextureType_REFLECTION);
  676|  2.14k|    SearchForInvalidTextures(pMaterial, aiTextureType_BASE_COLOR);
  677|  2.14k|    SearchForInvalidTextures(pMaterial, aiTextureType_NORMAL_CAMERA);
  678|  2.14k|    SearchForInvalidTextures(pMaterial, aiTextureType_EMISSION_COLOR);
  679|  2.14k|    SearchForInvalidTextures(pMaterial, aiTextureType_METALNESS);
  680|  2.14k|    SearchForInvalidTextures(pMaterial, aiTextureType_DIFFUSE_ROUGHNESS);
  681|  2.14k|    SearchForInvalidTextures(pMaterial, aiTextureType_AMBIENT_OCCLUSION);
  682|  2.14k|}
_ZN6Assimp17ValidateDSProcess8ValidateEPK9aiTexture:
  685|      7|void ValidateDSProcess::Validate(const aiTexture *pTexture) {
  686|       |    // the data section may NEVER be nullptr
  687|      7|    if (nullptr == pTexture->pcData) {
  ------------------
  |  Branch (687:9): [True: 0, False: 7]
  ------------------
  688|      0|        ReportError("aiTexture::pcData is nullptr");
  689|      0|    }
  690|      7|    if (pTexture->mHeight) {
  ------------------
  |  Branch (690:9): [True: 3, False: 4]
  ------------------
  691|      3|        if (!pTexture->mWidth) {
  ------------------
  |  Branch (691:13): [True: 0, False: 3]
  ------------------
  692|      0|            ReportError("aiTexture::mWidth is zero (aiTexture::mHeight is %i, uncompressed texture)",
  693|      0|                    pTexture->mHeight);
  694|      0|        }
  695|      4|    } else {
  696|      4|        if (!pTexture->mWidth) {
  ------------------
  |  Branch (696:13): [True: 0, False: 4]
  ------------------
  697|      0|            ReportError("aiTexture::mWidth is zero (compressed texture)");
  698|      0|        }
  699|      4|        if ('\0' != pTexture->achFormatHint[HINTMAXTEXTURELEN - 1]) {
  ------------------
  |  Branch (699:13): [True: 0, False: 4]
  ------------------
  700|      0|            ReportWarning("aiTexture::achFormatHint must be zero-terminated");
  701|      4|        } else if ('.' == pTexture->achFormatHint[0]) {
  ------------------
  |  Branch (701:20): [True: 0, False: 4]
  ------------------
  702|      0|            ReportWarning("aiTexture::achFormatHint should contain a file extension "
  703|      0|                          "without a leading dot (format hint: %s).",
  704|      0|                    pTexture->achFormatHint);
  705|      0|        }
  706|      4|    }
  707|       |
  708|      7|    const char *sz = pTexture->achFormatHint;
  709|      7|    if ((sz[0] >= 'A' && sz[0] <= 'Z') ||
  ------------------
  |  Branch (709:10): [True: 7, False: 0]
  |  Branch (709:26): [True: 0, False: 7]
  ------------------
  710|      7|            (sz[1] >= 'A' && sz[1] <= 'Z') ||
  ------------------
  |  Branch (710:14): [True: 7, False: 0]
  |  Branch (710:30): [True: 0, False: 7]
  ------------------
  711|      7|            (sz[2] >= 'A' && sz[2] <= 'Z') ||
  ------------------
  |  Branch (711:14): [True: 7, False: 0]
  |  Branch (711:30): [True: 0, False: 7]
  ------------------
  712|      7|            (sz[3] >= 'A' && sz[3] <= 'Z')) {
  ------------------
  |  Branch (712:14): [True: 3, False: 4]
  |  Branch (712:30): [True: 0, False: 3]
  ------------------
  713|      0|        ReportError("aiTexture::achFormatHint contains non-lowercase letters");
  714|      0|    }
  715|      7|}
_ZN6Assimp17ValidateDSProcess8ValidateEPK11aiAnimationPK10aiNodeAnim:
  719|    631|        const aiNodeAnim *pNodeAnim) {
  720|    631|    Validate(&pNodeAnim->mNodeName);
  721|       |
  722|    631|    if (!pNodeAnim->mNumPositionKeys && !pNodeAnim->mScalingKeys && !pNodeAnim->mNumRotationKeys) {
  ------------------
  |  Branch (722:9): [True: 8, False: 623]
  |  Branch (722:41): [True: 6, False: 2]
  |  Branch (722:69): [True: 3, False: 3]
  ------------------
  723|      3|        ReportError("Empty node animation channel");
  724|      3|    }
  725|       |    // otherwise check whether one of the keys exceeds the total duration of the animation
  726|    631|    if (pNodeAnim->mNumPositionKeys) {
  ------------------
  |  Branch (726:9): [True: 623, False: 8]
  ------------------
  727|    623|        if (!pNodeAnim->mPositionKeys) {
  ------------------
  |  Branch (727:13): [True: 0, False: 623]
  ------------------
  728|      0|            ReportError("aiNodeAnim::mPositionKeys is nullptr (aiNodeAnim::mNumPositionKeys is %i)",
  729|      0|                    pNodeAnim->mNumPositionKeys);
  730|      0|        }
  731|    623|        double dLast = -10e10;
  732|  5.79k|        for (unsigned int i = 0; i < pNodeAnim->mNumPositionKeys; ++i) {
  ------------------
  |  Branch (732:34): [True: 5.17k, False: 623]
  ------------------
  733|       |            // ScenePreprocessor will compute the duration if still the default value
  734|       |            // (Aramis) Add small epsilon, comparison tended to fail if max_time == duration,
  735|       |            //  seems to be due the compilers register usage/width.
  736|  5.17k|            if (pAnimation->mDuration > 0. && pNodeAnim->mPositionKeys[i].mTime > pAnimation->mDuration + 0.001) {
  ------------------
  |  Branch (736:17): [True: 2.77k, False: 2.39k]
  |  Branch (736:47): [True: 0, False: 2.77k]
  ------------------
  737|      0|                ReportError("aiNodeAnim::mPositionKeys[%i].mTime (%.5f) is larger "
  738|      0|                            "than aiAnimation::mDuration (which is %.5f)",
  739|      0|                        i,
  740|      0|                        (float)pNodeAnim->mPositionKeys[i].mTime,
  741|      0|                        (float)pAnimation->mDuration);
  742|      0|            }
  743|  5.17k|            if (i && pNodeAnim->mPositionKeys[i].mTime <= dLast) {
  ------------------
  |  Branch (743:17): [True: 4.54k, False: 623]
  |  Branch (743:22): [True: 0, False: 4.54k]
  ------------------
  744|      0|                ReportWarning("aiNodeAnim::mPositionKeys[%i].mTime (%.5f) is smaller "
  745|      0|                              "than aiAnimation::mPositionKeys[%i] (which is %.5f)",
  746|      0|                        i,
  747|      0|                        (float)pNodeAnim->mPositionKeys[i].mTime,
  748|      0|                        i - 1, (float)dLast);
  749|      0|            }
  750|  5.17k|            dLast = pNodeAnim->mPositionKeys[i].mTime;
  751|  5.17k|        }
  752|    623|    }
  753|       |    // rotation keys
  754|    631|    if (pNodeAnim->mNumRotationKeys) {
  ------------------
  |  Branch (754:9): [True: 356, False: 275]
  ------------------
  755|    356|        if (!pNodeAnim->mRotationKeys) {
  ------------------
  |  Branch (755:13): [True: 0, False: 356]
  ------------------
  756|      0|            ReportError("aiNodeAnim::mRotationKeys is nullptr (aiNodeAnim::mNumRotationKeys is %i)",
  757|      0|                    pNodeAnim->mNumRotationKeys);
  758|      0|        }
  759|    356|        double dLast = -10e10;
  760|  9.24k|        for (unsigned int i = 0; i < pNodeAnim->mNumRotationKeys; ++i) {
  ------------------
  |  Branch (760:34): [True: 8.89k, False: 356]
  ------------------
  761|  8.89k|            if (pAnimation->mDuration > 0. && pNodeAnim->mRotationKeys[i].mTime > pAnimation->mDuration + 0.001) {
  ------------------
  |  Branch (761:17): [True: 7.84k, False: 1.04k]
  |  Branch (761:47): [True: 0, False: 7.84k]
  ------------------
  762|      0|                ReportError("aiNodeAnim::mRotationKeys[%i].mTime (%.5f) is larger "
  763|      0|                            "than aiAnimation::mDuration (which is %.5f)",
  764|      0|                        i,
  765|      0|                        (float)pNodeAnim->mRotationKeys[i].mTime,
  766|      0|                        (float)pAnimation->mDuration);
  767|      0|            }
  768|  8.89k|            if (i && pNodeAnim->mRotationKeys[i].mTime <= dLast) {
  ------------------
  |  Branch (768:17): [True: 8.53k, False: 356]
  |  Branch (768:22): [True: 0, False: 8.53k]
  ------------------
  769|      0|                ReportWarning("aiNodeAnim::mRotationKeys[%i].mTime (%.5f) is smaller "
  770|      0|                              "than aiAnimation::mRotationKeys[%i] (which is %.5f)",
  771|      0|                        i,
  772|      0|                        (float)pNodeAnim->mRotationKeys[i].mTime,
  773|      0|                        i - 1, (float)dLast);
  774|      0|            }
  775|  8.89k|            dLast = pNodeAnim->mRotationKeys[i].mTime;
  776|  8.89k|        }
  777|    356|    }
  778|       |    // scaling keys
  779|    631|    if (pNodeAnim->mNumScalingKeys) {
  ------------------
  |  Branch (779:9): [True: 270, False: 361]
  ------------------
  780|    270|        if (!pNodeAnim->mScalingKeys) {
  ------------------
  |  Branch (780:13): [True: 0, False: 270]
  ------------------
  781|      0|            ReportError("aiNodeAnim::mScalingKeys is nullptr (aiNodeAnim::mNumScalingKeys is %i)",
  782|      0|                    pNodeAnim->mNumScalingKeys);
  783|      0|        }
  784|    270|        double dLast = -10e10;
  785|  1.13k|        for (unsigned int i = 0; i < pNodeAnim->mNumScalingKeys; ++i) {
  ------------------
  |  Branch (785:34): [True: 868, False: 270]
  ------------------
  786|    868|            if (pAnimation->mDuration > 0. && pNodeAnim->mScalingKeys[i].mTime > pAnimation->mDuration + 0.001) {
  ------------------
  |  Branch (786:17): [True: 771, False: 97]
  |  Branch (786:47): [True: 2, False: 769]
  ------------------
  787|      2|                ReportError("aiNodeAnim::mScalingKeys[%i].mTime (%.5f) is larger "
  788|      2|                            "than aiAnimation::mDuration (which is %.5f)",
  789|      2|                        i,
  790|      2|                        (float)pNodeAnim->mScalingKeys[i].mTime,
  791|      2|                        (float)pAnimation->mDuration);
  792|      2|            }
  793|    868|            if (i && pNodeAnim->mScalingKeys[i].mTime <= dLast) {
  ------------------
  |  Branch (793:17): [True: 596, False: 272]
  |  Branch (793:22): [True: 0, False: 596]
  ------------------
  794|      0|                ReportWarning("aiNodeAnim::mScalingKeys[%i].mTime (%.5f) is smaller "
  795|      0|                              "than aiAnimation::mScalingKeys[%i] (which is %.5f)",
  796|      0|                        i,
  797|      0|                        (float)pNodeAnim->mScalingKeys[i].mTime,
  798|      0|                        i - 1, (float)dLast);
  799|      0|            }
  800|    868|            dLast = pNodeAnim->mScalingKeys[i].mTime;
  801|    868|        }
  802|    270|    }
  803|       |
  804|    631|    if (!pNodeAnim->mNumScalingKeys && !pNodeAnim->mNumRotationKeys &&
  ------------------
  |  Branch (804:9): [True: 358, False: 273]
  |  Branch (804:40): [True: 270, False: 88]
  ------------------
  805|    270|            !pNodeAnim->mNumPositionKeys) {
  ------------------
  |  Branch (805:13): [True: 0, False: 270]
  ------------------
  806|      0|        ReportError("A node animation channel must have at least one subtrack");
  807|      0|    }
  808|    631|}
_ZN6Assimp17ValidateDSProcess8ValidateEPK6aiNode:
  850|  46.2k|void ValidateDSProcess::Validate(const aiNode *pNode) {
  851|  46.2k|    if (!pNode) {
  ------------------
  |  Branch (851:9): [True: 11, False: 46.1k]
  ------------------
  852|     11|        ReportError("A node of the scene-graph is nullptr");
  853|     11|    }
  854|       |    // Validate node name string first so that it's safe to use in below expressions
  855|  46.2k|    this->Validate(&pNode->mName);
  856|  46.2k|    const char *nodeName = (&pNode->mName)->C_Str();
  857|  46.2k|    if (pNode != mScene->mRootNode && !pNode->mParent) {
  ------------------
  |  Branch (857:9): [True: 45.9k, False: 269]
  |  Branch (857:39): [True: 0, False: 45.9k]
  ------------------
  858|      0|        ReportError("Non-root node %s lacks a valid parent (aiNode::mParent is nullptr) ", nodeName);
  859|      0|    }
  860|       |
  861|       |    // validate all meshes
  862|  46.2k|    if (pNode->mNumMeshes) {
  ------------------
  |  Branch (862:9): [True: 13.1k, False: 33.0k]
  ------------------
  863|  13.1k|        if (!pNode->mMeshes) {
  ------------------
  |  Branch (863:13): [True: 0, False: 13.1k]
  ------------------
  864|      0|            ReportError("aiNode::mMeshes is nullptr for node %s (aiNode::mNumMeshes is %i)",
  865|      0|                    nodeName, pNode->mNumMeshes);
  866|      0|        }
  867|  13.1k|        std::vector<bool> abHadMesh;
  868|  13.1k|        abHadMesh.resize(mScene->mNumMeshes, false);
  869|  27.7k|        for (unsigned int i = 0; i < pNode->mNumMeshes; ++i) {
  ------------------
  |  Branch (869:34): [True: 14.5k, False: 13.1k]
  ------------------
  870|  14.5k|            if (pNode->mMeshes[i] >= mScene->mNumMeshes) {
  ------------------
  |  Branch (870:17): [True: 0, False: 14.5k]
  ------------------
  871|      0|                ReportError("aiNode::mMeshes[%i] is out of range for node %s (maximum is %i)",
  872|      0|                        pNode->mMeshes[i], nodeName, mScene->mNumMeshes - 1);
  873|      0|            }
  874|  14.5k|            if (abHadMesh[pNode->mMeshes[i]]) {
  ------------------
  |  Branch (874:17): [True: 0, False: 14.5k]
  ------------------
  875|      0|                ReportError("aiNode::mMeshes[%i] is already referenced by this node %s (value: %i)",
  876|      0|                        i, nodeName, pNode->mMeshes[i]);
  877|      0|            }
  878|  14.5k|            abHadMesh[pNode->mMeshes[i]] = true;
  879|  14.5k|        }
  880|  13.1k|    }
  881|  46.2k|    if (pNode->mNumChildren) {
  ------------------
  |  Branch (881:9): [True: 12.0k, False: 34.1k]
  ------------------
  882|  12.0k|        if (!pNode->mChildren) {
  ------------------
  |  Branch (882:13): [True: 0, False: 12.0k]
  ------------------
  883|      0|            ReportError("aiNode::mChildren is nullptr for node %s (aiNode::mNumChildren is %i)",
  884|      0|                    nodeName, pNode->mNumChildren);
  885|      0|        }
  886|  57.9k|        for (unsigned int i = 0; i < pNode->mNumChildren; ++i) {
  ------------------
  |  Branch (886:34): [True: 45.9k, False: 12.0k]
  ------------------
  887|  45.9k|            const aiNode *pChild = pNode->mChildren[i];
  888|  45.9k|            Validate(pChild);
  889|  45.9k|            if (pChild->mParent != pNode) {
  ------------------
  |  Branch (889:17): [True: 0, False: 45.9k]
  ------------------
  890|      0|                const char *parentName = (pChild->mParent != nullptr) ? pChild->mParent->mName.C_Str() : "null";
  ------------------
  |  Branch (890:42): [True: 0, False: 0]
  ------------------
  891|      0|                ReportError("aiNode \"%s\" child %i \"%s\" parent is someone else: \"%s\"", pNode->mName.C_Str(), i, pChild->mName.C_Str(), parentName);
  892|      0|            }
  893|  45.9k|        }
  894|  34.1k|    } else if (pNode->mChildren) {
  ------------------
  |  Branch (894:16): [True: 0, False: 34.1k]
  ------------------
  895|      0|        ReportError("aiNode::mChildren is not nullptr for empty node %s (aiNode::mNumChildren is %i)",
  896|      0|                nodeName, pNode->mNumChildren);
  897|      0|    }
  898|  46.2k|}
_ZN6Assimp17ValidateDSProcess8ValidateEPK8aiString:
  901|  53.2k|void ValidateDSProcess::Validate(const aiString *pString) {
  902|  53.2k|    if (pString->length > AI_MAXLEN) {
  ------------------
  |  Branch (902:9): [True: 0, False: 53.2k]
  ------------------
  903|      0|        ReportError("aiString::length is too large (%u, maximum is %lu)",
  904|      0|                pString->length, AI_MAXLEN);
  905|      0|    }
  906|  53.2k|    const char *sz = pString->data;
  907|  1.30M|    while (true) {
  ------------------
  |  Branch (907:12): [True: 1.30M, Folded]
  ------------------
  908|  1.30M|        if ('\0' == *sz) {
  ------------------
  |  Branch (908:13): [True: 53.2k, False: 1.25M]
  ------------------
  909|  53.2k|            if (pString->length != (unsigned int)(sz - pString->data)) {
  ------------------
  |  Branch (909:17): [True: 3, False: 53.2k]
  ------------------
  910|      3|                ReportError("aiString::data is invalid: the terminal zero is at a wrong offset");
  911|      3|            }
  912|  53.2k|            break;
  913|  1.25M|        } else if (sz >= &pString->data[AI_MAXLEN]) {
  ------------------
  |  Branch (913:20): [True: 0, False: 1.25M]
  ------------------
  914|      0|            ReportError("aiString::data is invalid. There is no terminal character");
  915|      0|        }
  916|  1.25M|        ++sz;
  917|  1.25M|    }
  918|  53.2k|}
_ZN6Assimp17ValidateDSProcess12DoValidationI6aiMeshEEvPPT_jPKcS7_:
  109|    190|inline void ValidateDSProcess::DoValidation(T **parray, unsigned int size, const char *firstName, const char *secondName) {
  110|       |    // validate all entries
  111|    190|    if (size == 0) {
  ------------------
  |  Branch (111:9): [True: 0, False: 190]
  ------------------
  112|      0|        return;
  113|      0|    }
  114|       |
  115|    190|    if (!parray) {
  ------------------
  |  Branch (115:9): [True: 0, False: 190]
  ------------------
  116|      0|        ReportError("aiScene::%s is nullptr (aiScene::%s is %i)",
  117|      0|                firstName, secondName, size);
  118|      0|    }
  119|       |
  120|  3.46k|    for (unsigned int i = 0; i < size; ++i) {
  ------------------
  |  Branch (120:30): [True: 3.27k, False: 190]
  ------------------
  121|  3.27k|        if (!parray[i]) {
  ------------------
  |  Branch (121:13): [True: 0, False: 3.27k]
  ------------------
  122|      0|            ReportError("aiScene::%s[%i] is nullptr (aiScene::%s is %i)",
  123|      0|                    firstName, i, secondName, size);
  124|      0|        }
  125|  3.27k|        Validate(parray[i]);
  126|  3.27k|    }
  127|    190|}
_ZN6Assimp17ValidateDSProcess12DoValidationI11aiAnimationEEvPPT_jPKcS7_:
  109|     33|inline void ValidateDSProcess::DoValidation(T **parray, unsigned int size, const char *firstName, const char *secondName) {
  110|       |    // validate all entries
  111|     33|    if (size == 0) {
  ------------------
  |  Branch (111:9): [True: 0, False: 33]
  ------------------
  112|      0|        return;
  113|      0|    }
  114|       |
  115|     33|    if (!parray) {
  ------------------
  |  Branch (115:9): [True: 0, False: 33]
  ------------------
  116|      0|        ReportError("aiScene::%s is nullptr (aiScene::%s is %i)",
  117|      0|                firstName, secondName, size);
  118|      0|    }
  119|       |
  120|     81|    for (unsigned int i = 0; i < size; ++i) {
  ------------------
  |  Branch (120:30): [True: 48, False: 33]
  ------------------
  121|     48|        if (!parray[i]) {
  ------------------
  |  Branch (121:13): [True: 0, False: 48]
  ------------------
  122|      0|            ReportError("aiScene::%s[%i] is nullptr (aiScene::%s is %i)",
  123|      0|                    firstName, i, secondName, size);
  124|      0|        }
  125|     48|        Validate(parray[i]);
  126|     48|    }
  127|     33|}
_ZN6Assimp17ValidateDSProcess25DoValidationWithNameCheckI8aiCameraEEvPPT_jPKcS7_:
  163|     40|        const char *secondName) {
  164|       |    // validate all entries
  165|     40|    DoValidationEx(array, size, firstName, secondName);
  166|       |
  167|     86|    for (unsigned int i = 0; i < size; ++i) {
  ------------------
  |  Branch (167:30): [True: 46, False: 40]
  ------------------
  168|     46|        int res = HasNameMatch(array[i]->mName, mScene->mRootNode);
  169|     46|        if (0 == res) {
  ------------------
  |  Branch (169:13): [True: 0, False: 46]
  ------------------
  170|      0|            const std::string name = static_cast<char *>(array[i]->mName.data);
  171|      0|            ReportError("aiScene::%s[%i] has no corresponding node in the scene graph (%s)",
  172|      0|                    firstName, i, name.c_str());
  173|     46|        } else if (1 != res) {
  ------------------
  |  Branch (173:20): [True: 0, False: 46]
  ------------------
  174|      0|            const std::string name = static_cast<char *>(array[i]->mName.data);
  175|      0|            ReportError("aiScene::%s[%i]: there are more than one nodes with %s as name",
  176|      0|                    firstName, i, name.c_str());
  177|      0|        }
  178|     46|    }
  179|     40|}
_ZN6Assimp17ValidateDSProcess14DoValidationExI8aiCameraEEvPPT_jPKcS7_:
  132|     40|        const char *firstName, const char *secondName) {
  133|       |    // validate all entries
  134|     40|    if (size == 0) {
  ------------------
  |  Branch (134:9): [True: 0, False: 40]
  ------------------
  135|      0|        return;
  136|      0|    }
  137|       |
  138|     40|    if (!parray) {
  ------------------
  |  Branch (138:9): [True: 0, False: 40]
  ------------------
  139|      0|        ReportError("aiScene::%s is nullptr (aiScene::%s is %i)",
  140|      0|                firstName, secondName, size);
  141|      0|    }
  142|     86|    for (unsigned int i = 0; i < size; ++i) {
  ------------------
  |  Branch (142:30): [True: 46, False: 40]
  ------------------
  143|     46|        if (!parray[i]) {
  ------------------
  |  Branch (143:13): [True: 0, False: 46]
  ------------------
  144|      0|            ReportError("aiScene::%s[%u] is nullptr (aiScene::%s is %u)",
  145|      0|                    firstName, i, secondName, size);
  146|      0|        }
  147|     46|        Validate(parray[i]);
  148|       |
  149|       |        // check whether there are duplicate names
  150|     53|        for (unsigned int a = i + 1; a < size; ++a) {
  ------------------
  |  Branch (150:38): [True: 7, False: 46]
  ------------------
  151|      7|            if (parray[i]->mName == parray[a]->mName) {
  ------------------
  |  Branch (151:17): [True: 0, False: 7]
  ------------------
  152|      0|                ReportError("aiScene::%s[%u] has the same name as "
  153|      0|                            "aiScene::%s[%u]",
  154|      0|                        firstName, i, secondName, a);
  155|      0|            }
  156|      7|        }
  157|     46|    }
  158|     40|}
_Z12HasNameMatchRK8aiStringP6aiNode:
   99|    748|inline int HasNameMatch(const aiString &in, aiNode *node) {
  100|    748|    int result = (node->mName == in ? 1 : 0);
  ------------------
  |  Branch (100:19): [True: 103, False: 645]
  ------------------
  101|  1.39k|    for (unsigned int i = 0; i < node->mNumChildren; ++i) {
  ------------------
  |  Branch (101:30): [True: 645, False: 748]
  ------------------
  102|    645|        result += HasNameMatch(in, node->mChildren[i]);
  103|    645|    }
  104|    748|    return result;
  105|    748|}
_ZN6Assimp17ValidateDSProcess25DoValidationWithNameCheckI7aiLightEEvPPT_jPKcS7_:
  163|     40|        const char *secondName) {
  164|       |    // validate all entries
  165|     40|    DoValidationEx(array, size, firstName, secondName);
  166|       |
  167|     97|    for (unsigned int i = 0; i < size; ++i) {
  ------------------
  |  Branch (167:30): [True: 57, False: 40]
  ------------------
  168|     57|        int res = HasNameMatch(array[i]->mName, mScene->mRootNode);
  169|     57|        if (0 == res) {
  ------------------
  |  Branch (169:13): [True: 0, False: 57]
  ------------------
  170|      0|            const std::string name = static_cast<char *>(array[i]->mName.data);
  171|      0|            ReportError("aiScene::%s[%i] has no corresponding node in the scene graph (%s)",
  172|      0|                    firstName, i, name.c_str());
  173|     57|        } else if (1 != res) {
  ------------------
  |  Branch (173:20): [True: 0, False: 57]
  ------------------
  174|      0|            const std::string name = static_cast<char *>(array[i]->mName.data);
  175|      0|            ReportError("aiScene::%s[%i]: there are more than one nodes with %s as name",
  176|      0|                    firstName, i, name.c_str());
  177|      0|        }
  178|     57|    }
  179|     40|}
_ZN6Assimp17ValidateDSProcess14DoValidationExI7aiLightEEvPPT_jPKcS7_:
  132|     40|        const char *firstName, const char *secondName) {
  133|       |    // validate all entries
  134|     40|    if (size == 0) {
  ------------------
  |  Branch (134:9): [True: 0, False: 40]
  ------------------
  135|      0|        return;
  136|      0|    }
  137|       |
  138|     40|    if (!parray) {
  ------------------
  |  Branch (138:9): [True: 0, False: 40]
  ------------------
  139|      0|        ReportError("aiScene::%s is nullptr (aiScene::%s is %i)",
  140|      0|                firstName, secondName, size);
  141|      0|    }
  142|     97|    for (unsigned int i = 0; i < size; ++i) {
  ------------------
  |  Branch (142:30): [True: 57, False: 40]
  ------------------
  143|     57|        if (!parray[i]) {
  ------------------
  |  Branch (143:13): [True: 0, False: 57]
  ------------------
  144|      0|            ReportError("aiScene::%s[%u] is nullptr (aiScene::%s is %u)",
  145|      0|                    firstName, i, secondName, size);
  146|      0|        }
  147|     57|        Validate(parray[i]);
  148|       |
  149|       |        // check whether there are duplicate names
  150|     88|        for (unsigned int a = i + 1; a < size; ++a) {
  ------------------
  |  Branch (150:38): [True: 31, False: 57]
  ------------------
  151|     31|            if (parray[i]->mName == parray[a]->mName) {
  ------------------
  |  Branch (151:17): [True: 0, False: 31]
  ------------------
  152|      0|                ReportError("aiScene::%s[%u] has the same name as "
  153|      0|                            "aiScene::%s[%u]",
  154|      0|                        firstName, i, secondName, a);
  155|      0|            }
  156|     31|        }
  157|     57|    }
  158|     40|}
_ZN6Assimp17ValidateDSProcess12DoValidationI9aiTextureEEvPPT_jPKcS7_:
  109|      7|inline void ValidateDSProcess::DoValidation(T **parray, unsigned int size, const char *firstName, const char *secondName) {
  110|       |    // validate all entries
  111|      7|    if (size == 0) {
  ------------------
  |  Branch (111:9): [True: 0, False: 7]
  ------------------
  112|      0|        return;
  113|      0|    }
  114|       |
  115|      7|    if (!parray) {
  ------------------
  |  Branch (115:9): [True: 0, False: 7]
  ------------------
  116|      0|        ReportError("aiScene::%s is nullptr (aiScene::%s is %i)",
  117|      0|                firstName, secondName, size);
  118|      0|    }
  119|       |
  120|     14|    for (unsigned int i = 0; i < size; ++i) {
  ------------------
  |  Branch (120:30): [True: 7, False: 7]
  ------------------
  121|      7|        if (!parray[i]) {
  ------------------
  |  Branch (121:13): [True: 0, False: 7]
  ------------------
  122|      0|            ReportError("aiScene::%s[%i] is nullptr (aiScene::%s is %i)",
  123|      0|                    firstName, i, secondName, size);
  124|      0|        }
  125|      7|        Validate(parray[i]);
  126|      7|    }
  127|      7|}
_ZN6Assimp17ValidateDSProcess12DoValidationI10aiMaterialEEvPPT_jPKcS7_:
  109|    176|inline void ValidateDSProcess::DoValidation(T **parray, unsigned int size, const char *firstName, const char *secondName) {
  110|       |    // validate all entries
  111|    176|    if (size == 0) {
  ------------------
  |  Branch (111:9): [True: 0, False: 176]
  ------------------
  112|      0|        return;
  113|      0|    }
  114|       |
  115|    176|    if (!parray) {
  ------------------
  |  Branch (115:9): [True: 0, False: 176]
  ------------------
  116|      0|        ReportError("aiScene::%s is nullptr (aiScene::%s is %i)",
  117|      0|                firstName, secondName, size);
  118|      0|    }
  119|       |
  120|  2.31k|    for (unsigned int i = 0; i < size; ++i) {
  ------------------
  |  Branch (120:30): [True: 2.14k, False: 176]
  ------------------
  121|  2.14k|        if (!parray[i]) {
  ------------------
  |  Branch (121:13): [True: 0, False: 2.14k]
  ------------------
  122|      0|            ReportError("aiScene::%s[%i] is nullptr (aiScene::%s is %i)",
  123|      0|                    firstName, i, secondName, size);
  124|      0|        }
  125|  2.14k|        Validate(parray[i]);
  126|  2.14k|    }
  127|    176|}

_ZN6mapbox6earcutIjNSt3__16vectorINS2_I10aiVector2tIfENS1_9allocatorIS4_EEEENS5_IS7_EEEEEENS2_IT_NS5_ISA_EEEERKT0_:
  809|    817|std::vector<N> earcut(const Polygon& poly) {
  810|    817|    mapbox::detail::Earcut<N> earcut;
  811|    817|    earcut(poly);
  812|    817|    return std::move(earcut.indices);
  813|    817|}
_ZN6mapbox6detail6EarcutIjE10ObjectPoolINS2_4NodeENSt3__19allocatorIS4_EEEC2Ev:
   99|    817|        ObjectPool() { }
_ZN6mapbox6detail6EarcutIjEclINSt3__16vectorINS5_I10aiVector2tIfENS4_9allocatorIS7_EEEENS8_ISA_EEEEEEvRKT_:
  139|    817|void Earcut<N>::operator()(const Polygon& points) {
  140|       |    // reset
  141|    817|    indices.clear();
  142|    817|    vertices = 0;
  143|       |
  144|    817|    if (points.empty()) return;
  ------------------
  |  Branch (144:9): [True: 0, False: 817]
  ------------------
  145|       |
  146|    817|    double x;
  147|    817|    double y;
  148|    817|    int threshold = 80;
  149|    817|    std::size_t len = 0;
  150|       |
  151|  1.63k|    for (size_t i = 0; threshold >= 0 && i < points.size(); i++) {
  ------------------
  |  Branch (151:24): [True: 1.63k, False: 0]
  |  Branch (151:42): [True: 817, False: 817]
  ------------------
  152|    817|        threshold -= static_cast<int>(points[i].size());
  153|    817|        len += points[i].size();
  154|    817|    }
  155|       |
  156|       |    //estimate size of nodes and indices
  157|    817|    nodes.reset(len * 3 / 2);
  158|    817|    indices.reserve(len + points[0].size());
  159|       |
  160|    817|    Node* outerNode = linkedList(points[0], true);
  161|    817|    if (!outerNode || outerNode->prev == outerNode->next) return;
  ------------------
  |  Branch (161:9): [True: 0, False: 817]
  |  Branch (161:23): [True: 0, False: 817]
  ------------------
  162|       |
  163|    817|    if (points.size() > 1) outerNode = eliminateHoles(points, outerNode);
  ------------------
  |  Branch (163:9): [True: 0, False: 817]
  ------------------
  164|       |
  165|       |    // if the shape is not too simple, we'll use z-order curve hash later; calculate polygon bbox
  166|    817|    hashing = threshold < 0;
  167|    817|    if (hashing) {
  ------------------
  |  Branch (167:9): [True: 0, False: 817]
  ------------------
  168|      0|        Node* p = outerNode->next;
  169|      0|        minX = maxX = outerNode->x;
  170|      0|        minY = maxY = outerNode->y;
  171|      0|        do {
  172|      0|            x = p->x;
  173|      0|            y = p->y;
  174|      0|            minX = std::min<double>(minX, x);
  175|      0|            minY = std::min<double>(minY, y);
  176|      0|            maxX = std::max<double>(maxX, x);
  177|      0|            maxY = std::max<double>(maxY, y);
  178|      0|            p = p->next;
  179|      0|        } while (p != outerNode);
  ------------------
  |  Branch (179:18): [True: 0, False: 0]
  ------------------
  180|       |
  181|       |        // minX, minY and inv_size are later used to transform coords into integers for z-order calculation
  182|      0|        inv_size = std::max<double>(maxX - minX, maxY - minY);
  183|      0|        inv_size = inv_size != .0 ? (32767. / inv_size) : .0;
  ------------------
  |  Branch (183:20): [True: 0, False: 0]
  ------------------
  184|      0|    }
  185|       |
  186|    817|    earcutLinked(outerNode);
  187|       |
  188|    817|    nodes.clear();
  189|    817|}
_ZN6mapbox6detail6EarcutIjE10ObjectPoolINS2_4NodeENSt3__19allocatorIS4_EEE5resetEm:
  117|  2.45k|        void reset(std::size_t newBlockSize) {
  118|  2.45k|            for (auto allocation : allocations) {
  ------------------
  |  Branch (118:34): [True: 817, False: 2.45k]
  ------------------
  119|    817|                alloc_traits::deallocate(alloc, allocation, blockSize);
  120|    817|            }
  121|  2.45k|            allocations.clear();
  122|  2.45k|            blockSize = std::max<std::size_t>(1, newBlockSize);
  123|  2.45k|            currentBlock = nullptr;
  124|  2.45k|            currentIndex = blockSize;
  125|  2.45k|        }
_ZN6mapbox6detail6EarcutIjE10linkedListINSt3__16vectorI10aiVector2tIfENS4_9allocatorIS7_EEEEEEPNS2_4NodeERKT_b:
  194|    817|Earcut<N>::linkedList(const Ring& points, const bool clockwise) {
  195|    817|    using Point = typename Ring::value_type;
  196|    817|    double sum = 0;
  197|    817|    const std::size_t len = points.size();
  198|    817|    std::size_t i, j;
  199|    817|    Node* last = nullptr;
  200|       |
  201|       |    // calculate original winding order of a polygon ring
  202|  8.79k|    for (i = 0, j = len > 0 ? len - 1 : 0; i < len; j = i++) {
  ------------------
  |  Branch (202:21): [True: 817, False: 0]
  |  Branch (202:44): [True: 7.97k, False: 817]
  ------------------
  203|  7.97k|        const auto& p1 = points[i];
  204|  7.97k|        const auto& p2 = points[j];
  205|  7.97k|        const double p20 = util::nth<0, Point>::get(p2);
  206|  7.97k|        const double p10 = util::nth<0, Point>::get(p1);
  207|  7.97k|        const double p11 = util::nth<1, Point>::get(p1);
  208|  7.97k|        const double p21 = util::nth<1, Point>::get(p2);
  209|  7.97k|        sum += (p20 - p10) * (p11 + p21);
  210|  7.97k|    }
  211|       |
  212|       |    // link points into circular doubly-linked list in the specified winding order
  213|    817|    if (clockwise == (sum > 0)) {
  ------------------
  |  Branch (213:9): [True: 773, False: 44]
  ------------------
  214|  8.51k|        for (i = 0; i < len; i++) last = insertNode(vertices + i, points[i], last);
  ------------------
  |  Branch (214:21): [True: 7.74k, False: 773]
  ------------------
  215|    773|    } else {
  216|    275|        for (i = len; i-- > 0;) last = insertNode(vertices + i, points[i], last);
  ------------------
  |  Branch (216:23): [True: 231, False: 44]
  ------------------
  217|     44|    }
  218|       |
  219|    817|    if (last && equals(last, last->next)) {
  ------------------
  |  Branch (219:9): [True: 817, False: 0]
  |  Branch (219:17): [True: 29, False: 788]
  ------------------
  220|     29|        removeNode(last);
  221|     29|        last = last->next;
  222|     29|    }
  223|       |
  224|    817|    vertices += len;
  225|       |
  226|    817|    return last;
  227|    817|}
_ZN6mapbox6detail6EarcutIjE10insertNodeI10aiVector2tIfEEEPNS2_4NodeEmRKT_S7_:
  781|  7.97k|Earcut<N>::insertNode(std::size_t i, const Point& pt, Node* last) {
  782|  7.97k|    Node* p = nodes.construct(static_cast<N>(i), util::nth<0, Point>::get(pt), util::nth<1, Point>::get(pt));
  783|       |
  784|  7.97k|    if (!last) {
  ------------------
  |  Branch (784:9): [True: 817, False: 7.15k]
  ------------------
  785|    817|        p->prev = p;
  786|    817|        p->next = p;
  787|       |
  788|  7.15k|    } else {
  789|  7.15k|        assert(last);
  ------------------
  |  Branch (789:9): [True: 7.15k, False: 0]
  ------------------
  790|  7.15k|        p->next = last->next;
  791|  7.15k|        p->prev = last;
  792|  7.15k|        last->next->prev = p;
  793|  7.15k|        last->next = p;
  794|  7.15k|    }
  795|  7.97k|    return p;
  796|  7.97k|}
_ZN6mapbox6detail6EarcutIjE10ObjectPoolINS2_4NodeENSt3__19allocatorIS4_EEE9constructIJjffEEEPS4_DpOT_:
  107|  7.97k|        T* construct(Args&&... args) {
  108|  7.97k|            if (currentIndex >= blockSize) {
  ------------------
  |  Branch (108:17): [True: 817, False: 7.15k]
  ------------------
  109|    817|                currentBlock = alloc_traits::allocate(alloc, blockSize);
  110|    817|                allocations.emplace_back(currentBlock);
  111|    817|                currentIndex = 0;
  112|    817|            }
  113|  7.97k|            T* object = &currentBlock[currentIndex++];
  114|  7.97k|            alloc_traits::construct(alloc, object, std::forward<Args>(args)...);
  115|  7.97k|            return object;
  116|  7.97k|        }
_ZN6mapbox6detail6EarcutIjE4NodeC2Ejdd:
   37|  7.98k|        Node(N index, double x_, double y_) : i(index), x(x_), y(y_) {}
_ZN6mapbox6detail6EarcutIjE6equalsEPKNS2_4NodeES5_:
  678|  16.7k|bool Earcut<N>::equals(const Node* p1, const Node* p2) {
  679|  16.7k|    return p1->x == p2->x && p1->y == p2->y;
  ------------------
  |  Branch (679:12): [True: 2.84k, False: 13.8k]
  |  Branch (679:30): [True: 1.63k, False: 1.21k]
  ------------------
  680|  16.7k|}
_ZN6mapbox6detail6EarcutIjE10removeNodeEPNS2_4NodeE:
  799|  4.47k|void Earcut<N>::removeNode(Node* p) {
  800|  4.47k|    p->next->prev = p->prev;
  801|  4.47k|    p->prev->next = p->next;
  802|       |
  803|  4.47k|    if (p->prevZ) p->prevZ->nextZ = p->nextZ;
  ------------------
  |  Branch (803:9): [True: 0, False: 4.47k]
  ------------------
  804|  4.47k|    if (p->nextZ) p->nextZ->prevZ = p->prevZ;
  ------------------
  |  Branch (804:9): [True: 0, False: 4.47k]
  ------------------
  805|  4.47k|}
_ZNK6mapbox6detail6EarcutIjE15pointInTriangleEdddddddd:
  655|  70.1k|bool Earcut<N>::pointInTriangle(double ax, double ay, double bx, double by, double cx, double cy, double px, double py) const {
  656|  70.1k|    return (cx - px) * (ay - py) >= (ax - px) * (cy - py) &&
  ------------------
  |  Branch (656:12): [True: 52.6k, False: 17.4k]
  ------------------
  657|  52.6k|           (ax - px) * (by - py) >= (bx - px) * (ay - py) &&
  ------------------
  |  Branch (657:12): [True: 46.4k, False: 6.24k]
  ------------------
  658|  46.4k|           (bx - px) * (cy - py) >= (cx - px) * (by - py);
  ------------------
  |  Branch (658:12): [True: 41.2k, False: 5.13k]
  ------------------
  659|  70.1k|}
_ZN6mapbox6detail6EarcutIjE13locallyInsideEPKNS2_4NodeES5_:
  729|    740|bool Earcut<N>::locallyInside(const Node* a, const Node* b) {
  730|    740|    return area(a->prev, a, a->next) < 0 ?
  ------------------
  |  Branch (730:12): [True: 599, False: 141]
  ------------------
  731|    599|        area(a, b, a->next) >= 0 && area(a, a->prev, b) >= 0 :
  ------------------
  |  Branch (731:9): [True: 256, False: 343]
  |  Branch (731:37): [True: 240, False: 16]
  ------------------
  732|    740|        area(a, b, a->prev) < 0 || area(a, a->next, b) < 0;
  ------------------
  |  Branch (732:9): [True: 6, False: 135]
  |  Branch (732:36): [True: 8, False: 127]
  ------------------
  733|    740|}
_ZNK6mapbox6detail6EarcutIjE4areaEPKNS2_4NodeES5_S5_:
  672|   435k|double Earcut<N>::area(const Node* p, const Node* q, const Node* r) const {
  673|   435k|    return (q->y - p->y) * (r->x - q->x) - (q->x - p->x) * (r->y - q->y);
  674|   435k|}
_ZN6mapbox6detail6EarcutIjE12splitPolygonEPNS2_4NodeES4_:
  757|      5|Earcut<N>::splitPolygon(Node* a, Node* b) {
  758|      5|    Node* a2 = nodes.construct(a->i, a->x, a->y);
  759|      5|    Node* b2 = nodes.construct(b->i, b->x, b->y);
  760|      5|    Node* an = a->next;
  761|      5|    Node* bp = b->prev;
  762|       |
  763|      5|    a->next = b;
  764|      5|    b->prev = a;
  765|       |
  766|      5|    a2->next = an;
  767|      5|    an->prev = a2;
  768|       |
  769|      5|    b2->next = a2;
  770|      5|    a2->prev = b2;
  771|       |
  772|      5|    bp->next = b2;
  773|      5|    b2->prev = bp;
  774|       |
  775|      5|    return b2;
  776|      5|}
_ZN6mapbox6detail6EarcutIjE10ObjectPoolINS2_4NodeENSt3__19allocatorIS4_EEE9constructIJRKjRKdSD_EEEPS4_DpOT_:
  107|     10|        T* construct(Args&&... args) {
  108|     10|            if (currentIndex >= blockSize) {
  ------------------
  |  Branch (108:17): [True: 0, False: 10]
  ------------------
  109|      0|                currentBlock = alloc_traits::allocate(alloc, blockSize);
  110|      0|                allocations.emplace_back(currentBlock);
  111|      0|                currentIndex = 0;
  112|      0|            }
  113|     10|            T* object = &currentBlock[currentIndex++];
  114|     10|            alloc_traits::construct(alloc, object, std::forward<Args>(args)...);
  115|     10|            return object;
  116|     10|        }
_ZN6mapbox6detail6EarcutIjE12filterPointsEPNS2_4NodeES4_:
  232|  1.06k|Earcut<N>::filterPoints(Node* start, Node* end) {
  233|  1.06k|    if (!end) end = start;
  ------------------
  |  Branch (233:9): [True: 1.05k, False: 10]
  ------------------
  234|       |
  235|  1.06k|    Node* p = start;
  236|  1.06k|    bool again;
  237|  13.1k|    do {
  238|  13.1k|        again = false;
  239|       |
  240|  13.1k|        if (!p->steiner && (equals(p, p->next) || area(p->prev, p, p->next) == 0)) {
  ------------------
  |  Branch (240:13): [True: 13.1k, False: 0]
  |  Branch (240:29): [True: 824, False: 12.3k]
  |  Branch (240:51): [True: 1.05k, False: 11.2k]
  ------------------
  241|  1.87k|            removeNode(p);
  242|  1.87k|            p = end = p->prev;
  243|       |
  244|  1.87k|            if (p == p->next) break;
  ------------------
  |  Branch (244:17): [True: 309, False: 1.56k]
  ------------------
  245|  1.56k|            again = true;
  246|       |
  247|  11.2k|        } else {
  248|  11.2k|            p = p->next;
  249|  11.2k|        }
  250|  13.1k|    } while (again || p != end);
  ------------------
  |  Branch (250:14): [True: 1.56k, False: 11.2k]
  |  Branch (250:23): [True: 10.5k, False: 755]
  ------------------
  251|       |
  252|  1.06k|    return end;
  253|  1.06k|}
_ZN6mapbox6detail6EarcutIjE12earcutLinkedEPNS2_4NodeEi:
  257|  1.62k|void Earcut<N>::earcutLinked(Node* ear, int pass) {
  258|  1.62k|    if (!ear) return;
  ------------------
  |  Branch (258:9): [True: 0, False: 1.62k]
  ------------------
  259|       |
  260|       |    // interlink polygon nodes in z-order
  261|  1.62k|    if (!pass && hashing) indexCurve(ear);
  ------------------
  |  Branch (261:9): [True: 827, False: 794]
  |  Branch (261:18): [True: 0, False: 827]
  ------------------
  262|       |
  263|  1.62k|    Node* stop = ear;
  264|  1.62k|    Node* prev;
  265|  1.62k|    Node* next;
  266|       |
  267|       |    // iterate through ears, slicing them one by one
  268|  18.2k|    while (ear->prev != ear->next) {
  ------------------
  |  Branch (268:12): [True: 17.5k, False: 690]
  ------------------
  269|  17.5k|        prev = ear->prev;
  270|  17.5k|        next = ear->next;
  271|       |
  272|  17.5k|        if (hashing ? isEarHashed(ear) : isEar(ear)) {
  ------------------
  |  Branch (272:13): [True: 0, False: 17.5k]
  |  Branch (272:13): [True: 2.33k, False: 15.2k]
  ------------------
  273|       |            // cut off the triangle
  274|  2.33k|            indices.emplace_back(prev->i);
  275|  2.33k|            indices.emplace_back(ear->i);
  276|  2.33k|            indices.emplace_back(next->i);
  277|       |
  278|  2.33k|            removeNode(ear);
  279|       |
  280|       |            // skipping the next vertice leads to less sliver triangles
  281|  2.33k|            ear = next->next;
  282|  2.33k|            stop = next->next;
  283|       |
  284|  2.33k|            continue;
  285|  2.33k|        }
  286|       |
  287|  15.2k|        ear = next;
  288|       |
  289|       |        // if we looped through the whole remaining polygon and can't find any more ears
  290|  15.2k|        if (ear == stop) {
  ------------------
  |  Branch (290:13): [True: 931, False: 14.3k]
  ------------------
  291|       |            // try filtering points and slicing again
  292|    931|            if (!pass) earcutLinked(filterPoints(ear), 1);
  ------------------
  |  Branch (292:17): [True: 534, False: 397]
  ------------------
  293|       |
  294|       |            // if this didn't work, try curing all small self-intersections locally
  295|    397|            else if (pass == 1) {
  ------------------
  |  Branch (295:22): [True: 260, False: 137]
  ------------------
  296|    260|                ear = cureLocalIntersections(filterPoints(ear));
  297|    260|                earcutLinked(ear, 2);
  298|       |
  299|       |            // as a last resort, try splitting the remaining polygon into two
  300|    260|            } else if (pass == 2) splitEarcut(ear);
  ------------------
  |  Branch (300:24): [True: 137, False: 0]
  ------------------
  301|       |
  302|    931|            break;
  303|    931|        }
  304|  15.2k|    }
  305|  1.62k|}
_ZN6mapbox6detail6EarcutIjE5isEarEPNS2_4NodeE:
  309|  17.5k|bool Earcut<N>::isEar(Node* ear) {
  310|  17.5k|    const Node* a = ear->prev;
  311|  17.5k|    const Node* b = ear;
  312|  17.5k|    const Node* c = ear->next;
  313|       |
  314|  17.5k|    if (area(a, b, c) >= 0) return false; // reflex, can't be an ear
  ------------------
  |  Branch (314:9): [True: 3.45k, False: 14.1k]
  ------------------
  315|       |
  316|       |    // now make sure we don't have other points inside the potential ear
  317|  14.1k|    Node* p = ear->next->next;
  318|       |
  319|  72.4k|    while (p != ear->prev) {
  ------------------
  |  Branch (319:12): [True: 70.1k, False: 2.33k]
  ------------------
  320|  70.1k|        if (pointInTriangle(a->x, a->y, b->x, b->y, c->x, c->y, p->x, p->y) &&
  ------------------
  |  Branch (320:13): [True: 41.2k, False: 28.8k]
  ------------------
  321|  41.2k|            area(p->prev, p, p->next) >= 0) return false;
  ------------------
  |  Branch (321:13): [True: 11.8k, False: 29.4k]
  ------------------
  322|  58.3k|        p = p->next;
  323|  58.3k|    }
  324|       |
  325|  2.33k|    return true;
  326|  14.1k|}
_ZN6mapbox6detail6EarcutIjE22cureLocalIntersectionsEPNS2_4NodeE:
  372|    260|Earcut<N>::cureLocalIntersections(Node* start) {
  373|    260|    Node* p = start;
  374|  2.77k|    do {
  375|  2.77k|        Node* a = p->prev;
  376|  2.77k|        Node* b = p->next->next;
  377|       |
  378|       |        // a self-intersection where edge (v[i-1],v[i]) intersects (v[i+1],v[i+2])
  379|  2.77k|        if (!equals(a, b) && intersects(a, p, p->next, b) && locallyInside(a, b) && locallyInside(b, a)) {
  ------------------
  |  Branch (379:13): [True: 2.00k, False: 767]
  |  Branch (379:30): [True: 591, False: 1.41k]
  |  Branch (379:62): [True: 122, False: 469]
  |  Branch (379:85): [True: 118, False: 4]
  ------------------
  380|    118|            indices.emplace_back(a->i);
  381|    118|            indices.emplace_back(p->i);
  382|    118|            indices.emplace_back(b->i);
  383|       |
  384|       |            // remove two nodes involved
  385|    118|            removeNode(p);
  386|    118|            removeNode(p->next);
  387|       |
  388|    118|            p = start = b;
  389|    118|        }
  390|  2.77k|        p = p->next;
  391|  2.77k|    } while (p != start);
  ------------------
  |  Branch (391:14): [True: 2.51k, False: 260]
  ------------------
  392|       |
  393|    260|    return filterPoints(p);
  394|    260|}
_ZN6mapbox6detail6EarcutIjE10intersectsEPKNS2_4NodeES5_S5_S5_:
  684|  90.6k|bool Earcut<N>::intersects(const Node* p1, const Node* q1, const Node* p2, const Node* q2) {
  685|  90.6k|    int o1 = sign(area(p1, q1, p2));
  686|  90.6k|    int o2 = sign(area(p1, q1, q2));
  687|  90.6k|    int o3 = sign(area(p2, q2, p1));
  688|  90.6k|    int o4 = sign(area(p2, q2, q1));
  689|       |
  690|  90.6k|    if (o1 != o2 && o3 != o4) return true; // general case
  ------------------
  |  Branch (690:9): [True: 39.6k, False: 50.9k]
  |  Branch (690:21): [True: 34.4k, False: 5.25k]
  ------------------
  691|       |
  692|  56.1k|    if (o1 == 0 && onSegment(p1, p2, q1)) return true; // p1, q1 and p2 are collinear and p2 lies on p1q1
  ------------------
  |  Branch (692:9): [True: 8.90k, False: 47.2k]
  |  Branch (692:20): [True: 8.90k, False: 0]
  ------------------
  693|  47.2k|    if (o2 == 0 && onSegment(p1, q2, q1)) return true; // p1, q1 and q2 are collinear and q2 lies on p1q1
  ------------------
  |  Branch (693:9): [True: 0, False: 47.2k]
  |  Branch (693:20): [True: 0, False: 0]
  ------------------
  694|  47.2k|    if (o3 == 0 && onSegment(p2, p1, q2)) return true; // p2, q2 and p1 are collinear and p1 lies on p2q2
  ------------------
  |  Branch (694:9): [True: 27.5k, False: 19.7k]
  |  Branch (694:20): [True: 0, False: 27.5k]
  ------------------
  695|  47.2k|    if (o4 == 0 && onSegment(p2, q1, q2)) return true; // p2, q2 and q1 are collinear and q1 lies on p2q2
  ------------------
  |  Branch (695:9): [True: 27.5k, False: 19.7k]
  |  Branch (695:20): [True: 0, False: 27.5k]
  ------------------
  696|       |
  697|  47.2k|    return false;
  698|  47.2k|}
_ZN6mapbox6detail6EarcutIjE4signEd:
  710|   362k|int Earcut<N>::sign(double val) {
  711|   362k|    return (0.0 < val) - (val < 0.0);
  712|   362k|}
_ZN6mapbox6detail6EarcutIjE9onSegmentEPKNS2_4NodeES5_S5_:
  702|  63.9k|bool Earcut<N>::onSegment(const Node* p, const Node* q, const Node* r) {
  703|  63.9k|    return q->x <= std::max<double>(p->x, r->x) &&
  ------------------
  |  Branch (703:12): [True: 38.3k, False: 25.6k]
  ------------------
  704|  38.3k|        q->x >= std::min<double>(p->x, r->x) &&
  ------------------
  |  Branch (704:9): [True: 13.7k, False: 24.5k]
  ------------------
  705|  13.7k|        q->y <= std::max<double>(p->y, r->y) &&
  ------------------
  |  Branch (705:9): [True: 11.8k, False: 1.96k]
  ------------------
  706|  11.8k|        q->y >= std::min<double>(p->y, r->y);
  ------------------
  |  Branch (706:9): [True: 8.90k, False: 2.92k]
  ------------------
  707|  63.9k|}
_ZN6mapbox6detail6EarcutIjE11splitEarcutEPNS2_4NodeE:
  398|    137|void Earcut<N>::splitEarcut(Node* start) {
  399|       |    // look for a valid diagonal that divides the polygon into two
  400|    137|    Node* a = start;
  401|  2.45k|    do {
  402|  2.45k|        Node* b = a->next->next;
  403|  45.2k|        while (b != a->prev) {
  ------------------
  |  Branch (403:16): [True: 42.7k, False: 2.44k]
  ------------------
  404|  42.7k|            if (a->i != b->i && isValidDiagonal(a, b)) {
  ------------------
  |  Branch (404:17): [True: 42.7k, False: 0]
  |  Branch (404:33): [True: 5, False: 42.7k]
  ------------------
  405|       |                // split the polygon in two by the diagonal
  406|      5|                Node* c = splitPolygon(a, b);
  407|       |
  408|       |                // filter colinear points around the cuts
  409|      5|                a = filterPoints(a, a->next);
  410|      5|                c = filterPoints(c, c->next);
  411|       |
  412|       |                // run earcut on each half
  413|      5|                earcutLinked(a);
  414|      5|                earcutLinked(c);
  415|      5|                return;
  416|      5|            }
  417|  42.7k|            b = b->next;
  418|  42.7k|        }
  419|  2.44k|        a = a->next;
  420|  2.44k|    } while (a != start);
  ------------------
  |  Branch (420:14): [True: 2.31k, False: 132]
  ------------------
  421|    137|}
_ZN6mapbox6detail6EarcutIjE15isValidDiagonalEPNS2_4NodeES4_:
  663|  42.7k|bool Earcut<N>::isValidDiagonal(Node* a, Node* b) {
  664|  42.7k|    return a->next->i != b->i && a->prev->i != b->i && !intersectsPolygon(a, b) && // dones't intersect other edges
  ------------------
  |  Branch (664:12): [True: 42.7k, False: 0]
  |  Branch (664:34): [True: 42.7k, False: 0]
  |  Branch (664:56): [True: 18, False: 42.7k]
  ------------------
  665|     18|           ((locallyInside(a, b) && locallyInside(b, a) && middleInside(a, b) && // locally visible
  ------------------
  |  Branch (665:14): [True: 9, False: 9]
  |  Branch (665:37): [True: 5, False: 4]
  |  Branch (665:60): [True: 0, False: 5]
  ------------------
  666|      0|            (area(a->prev, a, b->prev) != 0.0 || area(a, b->prev, b) != 0.0)) || // does not create opposite-facing sectors
  ------------------
  |  Branch (666:14): [True: 0, False: 0]
  |  Branch (666:50): [True: 0, False: 0]
  ------------------
  667|     18|            (equals(a, b) && area(a->prev, a, a->next) > 0 && area(b->prev, b, b->next) > 0)); // special zero-length case
  ------------------
  |  Branch (667:14): [True: 14, False: 4]
  |  Branch (667:30): [True: 7, False: 7]
  |  Branch (667:63): [True: 5, False: 2]
  ------------------
  668|  42.7k|}
_ZN6mapbox6detail6EarcutIjE17intersectsPolygonEPKNS2_4NodeES5_:
  716|  42.7k|bool Earcut<N>::intersectsPolygon(const Node* a, const Node* b) {
  717|  42.7k|    const Node* p = a;
  718|   145k|    do {
  719|   145k|        if (p->i != a->i && p->next->i != a->i && p->i != b->i && p->next->i != b->i &&
  ------------------
  |  Branch (719:13): [True: 102k, False: 42.7k]
  |  Branch (719:29): [True: 102k, False: 18]
  |  Branch (719:51): [True: 95.4k, False: 6.84k]
  |  Branch (719:67): [True: 88.6k, False: 6.84k]
  ------------------
  720|  88.6k|                intersects(p, p->next, a, b)) return true;
  ------------------
  |  Branch (720:17): [True: 42.7k, False: 45.8k]
  ------------------
  721|   102k|        p = p->next;
  722|   102k|    } while (p != a);
  ------------------
  |  Branch (722:14): [True: 102k, False: 18]
  ------------------
  723|       |
  724|     18|    return false;
  725|  42.7k|}
_ZN6mapbox6detail6EarcutIjE12middleInsideEPKNS2_4NodeES5_:
  737|      5|bool Earcut<N>::middleInside(const Node* a, const Node* b) {
  738|      5|    const Node* p = a;
  739|      5|    bool inside = false;
  740|      5|    double px = (a->x + b->x) / 2;
  741|      5|    double py = (a->y + b->y) / 2;
  742|     50|    do {
  743|     50|        if (((p->y > py) != (p->next->y > py)) && p->next->y != p->y &&
  ------------------
  |  Branch (743:13): [True: 32, False: 18]
  |  Branch (743:51): [True: 32, False: 0]
  ------------------
  744|     32|                (px < (p->next->x - p->x) * (py - p->y) / (p->next->y - p->y) + p->x))
  ------------------
  |  Branch (744:17): [True: 4, False: 28]
  ------------------
  745|      4|            inside = !inside;
  746|     50|        p = p->next;
  747|     50|    } while (p != a);
  ------------------
  |  Branch (747:14): [True: 45, False: 5]
  ------------------
  748|       |
  749|      5|    return inside;
  750|      5|}
_ZN6mapbox6detail6EarcutIjE10ObjectPoolINS2_4NodeENSt3__19allocatorIS4_EEE5clearEv:
  126|  1.63k|        void clear() { reset(blockSize); }
_ZN6mapbox6detail6EarcutIjE10ObjectPoolINS2_4NodeENSt3__19allocatorIS4_EEED2Ev:
  103|    817|        ~ObjectPool() {
  104|    817|            clear();
  105|    817|        }

_ZN10ODDLParser7DDLNodeC2ERKNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEES9_mPS0_:
   56|    409|        m_type(type),
   57|    409|        m_name(name),
   58|    409|        m_parent(parent),
   59|    409|        m_children(),
   60|    409|        m_properties(nullptr),
  ------------------
  |  |   59|    409|#define nullptr nullptr
  ------------------
   61|    409|        m_value(nullptr),
  ------------------
  |  |   59|    409|#define nullptr nullptr
  ------------------
   62|    409|        m_dtArrayList(nullptr),
  ------------------
  |  |   59|    409|#define nullptr nullptr
  ------------------
   63|    409|        m_references(nullptr),
  ------------------
  |  |   59|    409|#define nullptr nullptr
  ------------------
   64|    409|        m_idx(idx) {
   65|    409|    if (m_parent) {
  ------------------
  |  Branch (65:9): [True: 398, False: 11]
  ------------------
   66|    398|        m_parent->m_children.push_back(this);
   67|    398|    }
   68|    409|}
_ZN10ODDLParser7DDLNodeD2Ev:
   70|    408|DDLNode::~DDLNode() {
   71|    408|    delete m_properties;
   72|    408|    delete m_value;
   73|    408|    releaseReferencedNames(m_references);
   74|       |
   75|    408|    delete m_dtArrayList;
   76|    408|    m_dtArrayList = nullptr;
  ------------------
  |  |   59|    408|#define nullptr nullptr
  ------------------
   77|    408|    if (s_allocatedNodes[m_idx] == this) {
  ------------------
  |  Branch (77:9): [True: 408, False: 0]
  ------------------
   78|    408|        s_allocatedNodes[m_idx] = nullptr;
  ------------------
  |  |   59|    408|#define nullptr nullptr
  ------------------
   79|    408|    }
   80|    806|    for (size_t i = 0; i < m_children.size(); i++) {
  ------------------
  |  Branch (80:24): [True: 398, False: 408]
  ------------------
   81|    398|        delete m_children[i];
   82|    398|    }
   83|    408|}
_ZNK10ODDLParser7DDLNode9getParentEv:
  106|     21|DDLNode *DDLNode::getParent() const {
  107|     21|    return m_parent;
  108|     21|}
_ZNK10ODDLParser7DDLNode16getChildNodeListEv:
  110|     34|const DDLNode::DllNodeList &DDLNode::getChildNodeList() const {
  111|     34|    return m_children;
  112|     34|}
_ZNK10ODDLParser7DDLNode7getTypeEv:
  118|    149|const std::string &DDLNode::getType() const {
  119|    149|    return m_type;
  120|    149|}
_ZN10ODDLParser7DDLNode7setNameERKNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEE:
  122|     78|void DDLNode::setName(const std::string &name) {
  123|     78|    m_name = name;
  124|     78|}
_ZNK10ODDLParser7DDLNode7getNameEv:
  126|      6|const std::string &DDLNode::getName() const {
  127|      6|    return m_name;
  128|      6|}
_ZN10ODDLParser7DDLNode13setPropertiesEPNS_8PropertyE:
  130|    135|void DDLNode::setProperties(Property *prop) {
  131|    135|    if (m_properties != nullptr)
  ------------------
  |  |   59|    135|#define nullptr nullptr
  ------------------
  |  Branch (131:9): [True: 0, False: 135]
  ------------------
  132|      0|        delete m_properties;
  133|    135|    m_properties = prop;
  134|    135|}
_ZNK10ODDLParser7DDLNode13getPropertiesEv:
  136|     35|Property *DDLNode::getProperties() const {
  137|     35|    return m_properties;
  138|     35|}
_ZN10ODDLParser7DDLNode18findPropertyByNameERKNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEE:
  149|     21|Property *DDLNode::findPropertyByName(const std::string &name) {
  150|     21|    if (name.empty()) {
  ------------------
  |  Branch (150:9): [True: 0, False: 21]
  ------------------
  151|      0|        return nullptr;
  ------------------
  |  |   59|      0|#define nullptr nullptr
  ------------------
  152|      0|    }
  153|       |
  154|     21|    if (nullptr == m_properties) {
  ------------------
  |  |   59|     21|#define nullptr nullptr
  ------------------
  |  Branch (154:9): [True: 0, False: 21]
  ------------------
  155|      0|        return nullptr;
  ------------------
  |  |   59|      0|#define nullptr nullptr
  ------------------
  156|      0|    }
  157|       |
  158|     21|    Property *current(m_properties);
  159|     21|    while (nullptr != current) {
  ------------------
  |  |   59|     21|#define nullptr nullptr
  ------------------
  |  Branch (159:12): [True: 21, False: 0]
  ------------------
  160|     21|        int res = strncmp(current->m_key->m_buffer, name.c_str(), name.size());
  161|     21|        if (0 == res) {
  ------------------
  |  Branch (161:13): [True: 21, False: 0]
  ------------------
  162|     21|            return current;
  163|     21|        }
  164|      0|        current = current->m_next;
  165|      0|    }
  166|       |
  167|      0|    return nullptr;
  ------------------
  |  |   59|      0|#define nullptr nullptr
  ------------------
  168|     21|}
_ZN10ODDLParser7DDLNode8setValueEPNS_5ValueE:
  170|    116|void DDLNode::setValue(Value *val) {
  171|    116|    m_value = val;
  172|    116|}
_ZNK10ODDLParser7DDLNode8getValueEv:
  174|     45|Value *DDLNode::getValue() const {
  175|     45|    return m_value;
  176|     45|}
_ZN10ODDLParser7DDLNode16setDataArrayListEPNS_13DataArrayListE:
  178|     98|void DDLNode::setDataArrayList(DataArrayList *dtArrayList) {
  179|     98|    m_dtArrayList = dtArrayList;
  180|     98|}
_ZNK10ODDLParser7DDLNode16getDataArrayListEv:
  182|     31|DataArrayList *DDLNode::getDataArrayList() const {
  183|     31|    return m_dtArrayList;
  184|     31|}
_ZN10ODDLParser7DDLNode13setReferencesEPNS_9ReferenceE:
  186|     34|void DDLNode::setReferences(Reference *refs) {
  187|     34|    m_references = refs;
  188|     34|}
_ZNK10ODDLParser7DDLNode13getReferencesEv:
  190|     23|Reference *DDLNode::getReferences() const {
  191|     23|    return m_references;
  192|     23|}
_ZN10ODDLParser7DDLNode6createERKNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEES9_PS0_:
  208|    409|DDLNode *DDLNode::create(const std::string &type, const std::string &name, DDLNode *parent) {
  209|    409|    const size_t idx(s_allocatedNodes.size());
  210|    409|    DDLNode *node = new DDLNode(type, name, idx, parent);
  211|    409|    s_allocatedNodes.push_back(node);
  212|       |
  213|    409|    return node;
  214|    409|}
DDLNode.cpp:_ZN10ODDLParserL22releaseReferencedNamesEPNS_9ReferenceE:
   47|    408|static void releaseReferencedNames(Reference *ref) {
   48|    408|    if (nullptr == ref) {
  ------------------
  |  |   59|    408|#define nullptr nullptr
  ------------------
  |  Branch (48:9): [True: 374, False: 34]
  ------------------
   49|    374|        return;
   50|    374|    }
   51|       |
   52|     34|    delete ref;
   53|     34|}

_ZN10ODDLParser4TextC2EPKcm:
   30|    771|        m_capacity(0),
   31|    771|        m_len(0),
   32|    771|        m_buffer(nullptr) {
  ------------------
  |  |   59|    771|#define nullptr nullptr
  ------------------
   33|    771|    set(buffer, numChars);
   34|    771|}
_ZN10ODDLParser4TextD2Ev:
   36|    771|Text::~Text() {
   37|    771|    clear();
   38|    771|}
_ZN10ODDLParser4Text5clearEv:
   40|  1.54k|void Text::clear() {
   41|  1.54k|    delete[] m_buffer;
   42|  1.54k|    m_buffer = nullptr;
  ------------------
  |  |   59|  1.54k|#define nullptr nullptr
  ------------------
   43|  1.54k|    m_capacity = 0;
   44|  1.54k|    m_len = 0;
   45|  1.54k|}
_ZN10ODDLParser4Text3setEPKcm:
   47|    771|void Text::set(const char *buffer, size_t numChars) {
   48|    771|    clear();
   49|    771|    if (numChars > 0) {
  ------------------
  |  Branch (49:9): [True: 664, False: 107]
  ------------------
   50|    664|        m_len = numChars;
   51|    664|        m_capacity = m_len + 1;
   52|    664|        m_buffer = new char[m_capacity];
   53|    664|        strncpy(m_buffer, buffer, numChars);
   54|    664|        m_buffer[numChars] = '\0';
   55|    664|    }
   56|    771|}
_ZN10ODDLParser4NameC2ENS_8NameTypeEPNS_4TextE:
   78|    130|        m_type(type), m_id(id) {
   79|       |    // empty
   80|    130|}
_ZN10ODDLParser4NameD2Ev:
   82|    130|Name::~Name() {
   83|    130|    delete m_id;
   84|    130|    m_id = nullptr;
  ------------------
  |  |   59|    130|#define nullptr nullptr
  ------------------
   85|    130|}
_ZN10ODDLParser9ReferenceC2EmPPNS_4NameE:
   98|     44|        m_numRefs(numrefs), m_referencedName(nullptr) {
  ------------------
  |  |   59|     44|#define nullptr nullptr
  ------------------
   99|     44|    if (numrefs > 0) {
  ------------------
  |  Branch (99:9): [True: 44, False: 0]
  ------------------
  100|     44|        m_referencedName = new Name *[numrefs];
  101|     96|        for (size_t i = 0; i < numrefs; i++) {
  ------------------
  |  Branch (101:28): [True: 52, False: 44]
  ------------------
  102|     52|            m_referencedName[i] = names[i];
  103|     52|        }
  104|     44|    }
  105|     44|}
_ZN10ODDLParser9ReferenceD2Ev:
  116|     44|Reference::~Reference() {
  117|     96|    for (size_t i = 0; i < m_numRefs; i++) {
  ------------------
  |  Branch (117:24): [True: 52, False: 44]
  ------------------
  118|     52|        delete m_referencedName[i];
  119|     52|    }
  120|     44|    m_numRefs = 0;
  121|     44|    delete[] m_referencedName;
  122|     44|    m_referencedName = nullptr;
  ------------------
  |  |   59|     44|#define nullptr nullptr
  ------------------
  123|     44|}
_ZN10ODDLParser8PropertyC2EPNS_4TextE:
  142|    135|        m_key(id), m_value(nullptr), m_ref(nullptr), m_next(nullptr) {
  ------------------
  |  |   59|    135|#define nullptr nullptr
  ------------------
                      m_key(id), m_value(nullptr), m_ref(nullptr), m_next(nullptr) {
  ------------------
  |  |   59|    135|#define nullptr nullptr
  ------------------
                      m_key(id), m_value(nullptr), m_ref(nullptr), m_next(nullptr) {
  ------------------
  |  |   59|    135|#define nullptr nullptr
  ------------------
  143|       |    // empty
  144|    135|}
_ZN10ODDLParser8PropertyD2Ev:
  146|    135|Property::~Property() {
  147|    135|    delete m_key;
  148|    135|    if (m_value != nullptr)
  ------------------
  |  |   59|    135|#define nullptr nullptr
  ------------------
  |  Branch (148:9): [True: 125, False: 10]
  ------------------
  149|    125|        delete m_value;
  150|    135|    if (m_ref != nullptr)
  ------------------
  |  |   59|    135|#define nullptr nullptr
  ------------------
  |  Branch (150:9): [True: 10, False: 125]
  ------------------
  151|     10|        delete (m_ref);
  152|    135|    if (m_next != nullptr)
  ------------------
  |  |   59|    135|#define nullptr nullptr
  ------------------
  |  Branch (152:9): [True: 0, False: 135]
  ------------------
  153|      0|        delete m_next;
  154|    135|}
_ZN10ODDLParser13DataArrayListC2Ev:
  157|  22.4k|        m_numItems(0), m_dataList(nullptr), m_next(nullptr), m_refs(nullptr), m_numRefs(0) {
  ------------------
  |  |   59|  22.4k|#define nullptr nullptr
  ------------------
                      m_numItems(0), m_dataList(nullptr), m_next(nullptr), m_refs(nullptr), m_numRefs(0) {
  ------------------
  |  |   59|  22.4k|#define nullptr nullptr
  ------------------
                      m_numItems(0), m_dataList(nullptr), m_next(nullptr), m_refs(nullptr), m_numRefs(0) {
  ------------------
  |  |   59|  22.4k|#define nullptr nullptr
  ------------------
  158|       |    // empty
  159|  22.4k|}
_ZN10ODDLParser13DataArrayListD2Ev:
  161|  22.4k|DataArrayList::~DataArrayList() {
  162|  22.4k|    delete m_dataList;
  163|  22.4k|    if (m_next != nullptr)
  ------------------
  |  |   59|  22.4k|#define nullptr nullptr
  ------------------
  |  Branch (163:9): [True: 22.3k, False: 98]
  ------------------
  164|  22.3k|        delete m_next;
  165|  22.4k|    if (m_refs != nullptr)
  ------------------
  |  |   59|  22.4k|#define nullptr nullptr
  ------------------
  |  Branch (165:9): [True: 0, False: 22.4k]
  ------------------
  166|      0|        delete m_refs;
  167|  22.4k|}
_ZN10ODDLParser7ContextC2Ev:
  187|     10|        m_root(nullptr) {
  ------------------
  |  |   59|     10|#define nullptr nullptr
  ------------------
  188|       |    // empty
  189|     10|}
_ZN10ODDLParser7ContextD2Ev:
  191|     10|Context::~Context() {
  192|     10|    clear();
  193|     10|}
_ZN10ODDLParser7Context5clearEv:
  195|     10|void Context::clear() {
  196|     10|    delete m_root;
  197|     10|    m_root = nullptr;
  ------------------
  |  |   59|     10|#define nullptr nullptr
  ------------------
  198|     10|}

_ZN10ODDLParser13OpenDDLParserC2Ev:
  119|     14|        m_logCallback(nullptr),
  ------------------
  |  |   59|     14|#define nullptr nullptr
  ------------------
  120|     14|        m_buffer(),
  121|     14|        m_stack(),
  122|     14|        m_context(nullptr) {
  ------------------
  |  |   59|     14|#define nullptr nullptr
  ------------------
  123|       |    // empty
  124|     14|}
_ZN10ODDLParser13OpenDDLParserD2Ev:
  133|     14|OpenDDLParser::~OpenDDLParser() {
  134|     14|    clear();
  135|     14|}
_ZN10ODDLParser13OpenDDLParser14setLogCallbackENSt3__18functionIFvNS_11LogSeverityERKNS1_12basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEEEE:
  155|     14|void OpenDDLParser::setLogCallback(logCallback callback) {
  156|       |    // install user-specific log callback; null = no log callback
  157|     14|    m_logCallback = callback;
  158|     14|}
_ZN10ODDLParser13OpenDDLParser9setBufferEPKcm:
  164|     14|void OpenDDLParser::setBuffer(const char *buffer, size_t len) {
  165|     14|    clear();
  166|     14|    if (0 == len) {
  ------------------
  |  Branch (166:9): [True: 0, False: 14]
  ------------------
  167|      0|        return;
  168|      0|    }
  169|       |
  170|     14|    m_buffer.resize(len);
  171|     14|    ::memcpy(&m_buffer[0], buffer, len);
  172|     14|}
_ZN10ODDLParser13OpenDDLParser5clearEv:
  192|     28|void OpenDDLParser::clear() {
  193|     28|    m_buffer.resize(0);
  194|     28|    delete m_context;
  195|     28|    m_context = nullptr;
  ------------------
  |  |   59|     28|#define nullptr nullptr
  ------------------
  196|     28|}
_ZN10ODDLParser13OpenDDLParser8validateEv:
  198|     14|bool OpenDDLParser::validate() {
  199|     14|    if (m_buffer.empty()) {
  ------------------
  |  Branch (199:9): [True: 0, False: 14]
  ------------------
  200|      0|        return true;
  201|      0|    }
  202|       |
  203|     14|    if (!isCharacter(m_buffer[0]) && !isNumeric(m_buffer[0])) {
  ------------------
  |  Branch (203:9): [True: 4, False: 10]
  |  Branch (203:38): [True: 4, False: 0]
  ------------------
  204|      4|        return false;
  205|      4|    }
  206|       |
  207|     10|    return true;
  208|     14|}
_ZN10ODDLParser13OpenDDLParser5parseEv:
  210|     14|bool OpenDDLParser::parse() {
  211|     14|    if (m_buffer.empty()) {
  ------------------
  |  Branch (211:9): [True: 0, False: 14]
  ------------------
  212|      0|        return false;
  213|      0|    }
  214|       |
  215|     14|    normalizeBuffer(m_buffer);
  216|     14|    if (!validate()) {
  ------------------
  |  Branch (216:9): [True: 4, False: 10]
  ------------------
  217|      4|        return false;
  218|      4|    }
  219|       |
  220|     10|    m_context = new Context;
  221|     10|    m_context->m_root = DDLNode::create("root", "", nullptr);
  ------------------
  |  |   59|     10|#define nullptr nullptr
  ------------------
  222|     10|    pushNode(m_context->m_root);
  223|       |
  224|       |    // do the main parsing
  225|     10|    char *current(&m_buffer[0]);
  226|     10|    char *end(&m_buffer[m_buffer.size() - 1] + 1);
  227|     10|    size_t pos(current - &m_buffer[0]);
  228|     84|    while (pos < m_buffer.size()) {
  ------------------
  |  Branch (228:12): [True: 81, False: 3]
  ------------------
  229|     81|        current = parseNextNode(current, end);
  230|     81|        if (current == nullptr) {
  ------------------
  |  |   59|     81|#define nullptr nullptr
  ------------------
  |  Branch (230:13): [True: 7, False: 74]
  ------------------
  231|      7|            return false;
  232|      7|        }
  233|     74|        pos = current - &m_buffer[0];
  234|     74|    }
  235|      3|    return true;
  236|     10|}
_ZN10ODDLParser13OpenDDLParser13parseNextNodeEPcS1_:
  247|    506|char *OpenDDLParser::parseNextNode(char *in, char *end) {
  248|    506|    in = parseHeader(in, end);
  249|    506|    in = parseStructure(in, end);
  250|       |
  251|    506|    return in;
  252|    506|}
_ZN10ODDLParser13OpenDDLParser11parseHeaderEPcS1_:
  264|    506|char *OpenDDLParser::parseHeader(char *in, char *end) {
  265|    506|    if (nullptr == in || in == end) {
  ------------------
  |  |   59|    506|#define nullptr nullptr
  ------------------
  |  Branch (265:9): [True: 0, False: 506]
  |  Branch (265:26): [True: 0, False: 506]
  ------------------
  266|      0|        return in;
  267|      0|    }
  268|       |
  269|    506|    Text *id(nullptr);
  ------------------
  |  |   59|    506|#define nullptr nullptr
  ------------------
  270|    506|    in = OpenDDLParser::parseIdentifier(in, end, &id);
  271|       |
  272|       |#ifdef DEBUG_HEADER_NAME
  273|       |    dumpId(id);
  274|       |#endif // DEBUG_HEADER_NAME
  275|       |
  276|    506|    in = lookForNextToken(in, end);
  277|    506|    if (nullptr != id) {
  ------------------
  |  |   59|    506|#define nullptr nullptr
  ------------------
  |  Branch (277:9): [True: 506, False: 0]
  ------------------
  278|       |        // store the node
  279|    506|        DDLNode *node(createDDLNode(id, this));
  280|    506|        if (nullptr != node) {
  ------------------
  |  |   59|    506|#define nullptr nullptr
  ------------------
  |  Branch (280:13): [True: 399, False: 107]
  ------------------
  281|    399|            pushNode(node);
  282|    399|        } else {
  283|    107|            std::cerr << "nullptr returned by creating DDLNode." << std::endl;
  284|    107|        }
  285|    506|        delete id;
  286|       |
  287|    506|        Name *name(nullptr);
  ------------------
  |  |   59|    506|#define nullptr nullptr
  ------------------
  288|    506|        in = OpenDDLParser::parseName(in, end, &name);
  289|    506|        if (nullptr != name && nullptr != node && nullptr != name->m_id->m_buffer) {
  ------------------
  |  |   59|    506|#define nullptr nullptr
  ------------------
                      if (nullptr != name && nullptr != node && nullptr != name->m_id->m_buffer) {
  ------------------
  |  |   59|     78|#define nullptr nullptr
  ------------------
                      if (nullptr != name && nullptr != node && nullptr != name->m_id->m_buffer) {
  ------------------
  |  |   59|     78|#define nullptr nullptr
  ------------------
  |  Branch (289:13): [True: 78, False: 428]
  |  Branch (289:32): [True: 78, False: 0]
  |  Branch (289:51): [True: 78, False: 0]
  ------------------
  290|     78|            const std::string nodeName(name->m_id->m_buffer);
  291|     78|            node->setName(nodeName);
  292|     78|        }
  293|    506|        delete name;
  294|       |
  295|    506|        Property *first(nullptr);
  ------------------
  |  |   59|    506|#define nullptr nullptr
  ------------------
  296|    506|        in = lookForNextToken(in, end);
  297|    506|        if (in != end && *in == Grammar::OpenPropertyToken[0]) {
  ------------------
  |  Branch (297:13): [True: 503, False: 3]
  |  Branch (297:26): [True: 135, False: 368]
  ------------------
  298|    135|            in++;
  299|    135|            Property *prop(nullptr), *prev(nullptr);
  ------------------
  |  |   59|    135|#define nullptr nullptr
  ------------------
                          Property *prop(nullptr), *prev(nullptr);
  ------------------
  |  |   59|    135|#define nullptr nullptr
  ------------------
  300|    270|            while (in != end && *in != Grammar::ClosePropertyToken[0]) {
  ------------------
  |  Branch (300:20): [True: 270, False: 0]
  |  Branch (300:33): [True: 135, False: 135]
  ------------------
  301|    135|                in = OpenDDLParser::parseProperty(in, end, &prop);
  302|    135|                in = lookForNextToken(in, end);
  303|    135|                if(in == end) {
  ------------------
  |  Branch (303:20): [True: 0, False: 135]
  ------------------
  304|      0|                    break;
  305|      0|                }
  306|       |
  307|    135|                if (*in != Grammar::CommaSeparator[0] && *in != Grammar::ClosePropertyToken[0]) {
  ------------------
  |  Branch (307:21): [True: 135, False: 0]
  |  Branch (307:58): [True: 0, False: 135]
  ------------------
  308|      0|                    logInvalidTokenError(std::string(in, end), Grammar::ClosePropertyToken, m_logCallback);
  309|      0|                    return nullptr;
  ------------------
  |  |   59|      0|#define nullptr nullptr
  ------------------
  310|      0|                }
  311|       |
  312|    135|                if (nullptr != prop && *in != Grammar::CommaSeparator[0]) {
  ------------------
  |  |   59|    135|#define nullptr nullptr
  ------------------
  |  Branch (312:21): [True: 135, False: 0]
  |  Branch (312:40): [True: 135, False: 0]
  ------------------
  313|    135|                    if (nullptr == first) {
  ------------------
  |  |   59|    135|#define nullptr nullptr
  ------------------
  |  Branch (313:25): [True: 135, False: 0]
  ------------------
  314|    135|                        first = prop;
  315|    135|                    }
  316|    135|                    if (nullptr != prev) {
  ------------------
  |  |   59|    135|#define nullptr nullptr
  ------------------
  |  Branch (316:25): [True: 0, False: 135]
  ------------------
  317|      0|                        prev->m_next = prop;
  318|      0|                    }
  319|    135|                    prev = prop;
  320|    135|                }
  321|    135|            }
  322|    135|            if(in != end) {
  ------------------
  |  Branch (322:16): [True: 135, False: 0]
  ------------------
  323|    135|                ++in;
  324|    135|            }
  325|    135|        }
  326|       |
  327|       |        // set the properties
  328|    506|        if (nullptr != first && nullptr != node) {
  ------------------
  |  |   59|    506|#define nullptr nullptr
  ------------------
                      if (nullptr != first && nullptr != node) {
  ------------------
  |  |   59|    135|#define nullptr nullptr
  ------------------
  |  Branch (328:13): [True: 135, False: 371]
  |  Branch (328:33): [True: 135, False: 0]
  ------------------
  329|    135|            node->setProperties(first);
  330|    135|        }
  331|    506|    }
  332|       |
  333|    506|    return in;
  334|    506|}
_ZN10ODDLParser13OpenDDLParser14parseStructureEPcS1_:
  336|    506|char *OpenDDLParser::parseStructure(char *in, char *end) {
  337|    506|    if (nullptr == in || in == end) {
  ------------------
  |  |   59|    506|#define nullptr nullptr
  ------------------
  |  Branch (337:9): [True: 0, False: 506]
  |  Branch (337:26): [True: 3, False: 503]
  ------------------
  338|      3|        return in;
  339|      3|    }
  340|       |
  341|    503|    bool error(false);
  342|    503|    in = lookForNextToken(in, end);
  343|    503|    if (in != end) {
  ------------------
  |  Branch (343:9): [True: 503, False: 0]
  ------------------
  344|    503|        if (*in == *Grammar::OpenBracketToken) {
  ------------------
  |  Branch (344:13): [True: 502, False: 1]
  ------------------
  345|       |            // loop over all children ( data and nodes )
  346|    674|            do {
  347|    674|                in = parseStructureBody(in, end, error);
  348|    674|                if (in == nullptr) {
  ------------------
  |  |   59|    674|#define nullptr nullptr
  ------------------
  |  Branch (348:21): [True: 133, False: 541]
  ------------------
  349|    133|                    return nullptr;
  ------------------
  |  |   59|    133|#define nullptr nullptr
  ------------------
  350|    133|                }
  351|    674|            } while (in  != end &&
  ------------------
  |  Branch (351:22): [True: 541, False: 0]
  ------------------
  352|    541|                     *in != *Grammar::CloseBracketToken);
  ------------------
  |  Branch (352:22): [True: 172, False: 369]
  ------------------
  353|    369|            if (in != end) {
  ------------------
  |  Branch (353:17): [True: 369, False: 0]
  ------------------
  354|    369|                ++in;
  355|    369|            }
  356|    369|        } else {
  357|      1|            logInvalidTokenError(std::string(in, end), std::string(Grammar::OpenBracketToken), m_logCallback);
  358|      1|            error = true;
  359|      1|            return nullptr;
  ------------------
  |  |   59|      1|#define nullptr nullptr
  ------------------
  360|      1|        }
  361|    503|    }
  362|    369|    in = lookForNextToken(in, end);
  363|       |
  364|       |    // pop node from stack after successful parsing
  365|    369|    if (!error) {
  ------------------
  |  Branch (365:9): [True: 369, False: 0]
  ------------------
  366|    369|        popNode();
  367|    369|    }
  368|       |
  369|    369|    return in;
  370|    503|}
_ZN10ODDLParser13OpenDDLParser18parseStructureBodyEPcS1_Rb:
  396|    674|char *OpenDDLParser::parseStructureBody(char *in, char *end, bool &error) {
  397|    674|    if (!isNumeric(*in) && !isCharacter(*in)) {
  ------------------
  |  Branch (397:9): [True: 674, False: 0]
  |  Branch (397:28): [True: 502, False: 172]
  ------------------
  398|    502|        ++in;
  399|    502|    }
  400|       |
  401|    674|    in = lookForNextToken(in, end);
  402|    674|    Value::ValueType type(Value::ValueType::ddl_none);
  403|    674|    size_t arrayLen(0);
  404|    674|    in = OpenDDLParser::parsePrimitiveDataType(in, end, type, arrayLen);
  405|    674|    if (Value::ValueType::ddl_none != type) {
  ------------------
  |  Branch (405:9): [True: 249, False: 425]
  ------------------
  406|       |        // parse a primitive data type
  407|    249|        in = lookForNextToken(in, end);
  408|    249|        if (*in == Grammar::OpenBracketToken[0]) {
  ------------------
  |  Branch (408:13): [True: 249, False: 0]
  ------------------
  409|    249|            Reference *refs(nullptr);
  ------------------
  |  |   59|    249|#define nullptr nullptr
  ------------------
  410|    249|            DataArrayList *dtArrayList(nullptr);
  ------------------
  |  |   59|    249|#define nullptr nullptr
  ------------------
  411|    249|            Value *values(nullptr);
  ------------------
  |  |   59|    249|#define nullptr nullptr
  ------------------
  412|    249|            if (1 == arrayLen) {
  ------------------
  |  Branch (412:17): [True: 151, False: 98]
  ------------------
  413|    151|                size_t numRefs(0), numValues(0);
  414|    151|                in = parseDataList(in, end, type, &values, numValues, &refs, numRefs);
  415|    151|                setNodeValues(top(), values);
  416|    151|                setNodeReferences(top(), refs);
  417|    151|            } else if (arrayLen > 1) {
  ------------------
  |  Branch (417:24): [True: 98, False: 0]
  ------------------
  418|     98|                in = parseDataArrayList(in, end, type, &dtArrayList);
  419|     98|                setNodeDataArrayList(top(), dtArrayList);
  420|     98|            } else {
  421|      0|                std::cerr << "0 for array is invalid." << std::endl;
  422|      0|                error = true;
  423|      0|            }
  424|    249|        }
  425|       |
  426|    249|        in = lookForNextToken(in, end);
  427|    249|        if (in == end || *in != '}') {
  ------------------
  |  Branch (427:13): [True: 3, False: 246]
  |  Branch (427:26): [True: 3, False: 243]
  ------------------
  428|      6|            logInvalidTokenError(std::string(in, end), std::string(Grammar::CloseBracketToken), m_logCallback);
  429|      6|            return nullptr;
  ------------------
  |  |   59|      6|#define nullptr nullptr
  ------------------
  430|    243|        } else {
  431|       |            //in++;
  432|    243|        }
  433|    425|    } else {
  434|       |        // parse a complex data type
  435|    425|        in = parseNextNode(in, end);
  436|    425|    }
  437|       |
  438|    668|    return in;
  439|    674|}
_ZN10ODDLParser13OpenDDLParser8pushNodeEPNS_7DDLNodeE:
  441|    409|void OpenDDLParser::pushNode(DDLNode *node) {
  442|    409|    if (nullptr == node) {
  ------------------
  |  |   59|    409|#define nullptr nullptr
  ------------------
  |  Branch (442:9): [True: 0, False: 409]
  ------------------
  443|      0|        return;
  444|      0|    }
  445|       |
  446|    409|    m_stack.push_back(node);
  447|    409|}
_ZN10ODDLParser13OpenDDLParser7popNodeEv:
  449|    369|DDLNode *OpenDDLParser::popNode() {
  450|    369|    if (m_stack.empty()) {
  ------------------
  |  Branch (450:9): [True: 0, False: 369]
  ------------------
  451|      0|        return nullptr;
  ------------------
  |  |   59|      0|#define nullptr nullptr
  ------------------
  452|      0|    }
  453|       |
  454|    369|    DDLNode *topNode(top());
  455|    369|    m_stack.pop_back();
  456|    369|    return topNode;
  457|    369|}
_ZN10ODDLParser13OpenDDLParser3topEv:
  459|  1.16k|DDLNode *OpenDDLParser::top() {
  460|  1.16k|    if (m_stack.empty()) {
  ------------------
  |  Branch (460:9): [True: 1, False: 1.16k]
  ------------------
  461|      1|        return nullptr;
  ------------------
  |  |   59|      1|#define nullptr nullptr
  ------------------
  462|      1|    }
  463|       |
  464|  1.16k|    DDLNode *top = m_stack.back();
  465|  1.16k|    return top;
  466|  1.16k|}
_ZNK10ODDLParser13OpenDDLParser10getContextEv:
  476|      3|Context *OpenDDLParser::getContext() const {
  477|      3|    return m_context;
  478|      3|}
_ZN10ODDLParser13OpenDDLParser15normalizeBufferERNSt3__16vectorIcNS1_9allocatorIcEEEE:
  480|     14|void OpenDDLParser::normalizeBuffer(std::vector<char> &buffer) {
  481|     14|    if (buffer.empty()) {
  ------------------
  |  Branch (481:9): [True: 0, False: 14]
  ------------------
  482|      0|        return;
  483|      0|    }
  484|       |
  485|     14|    std::vector<char> newBuffer;
  486|     14|    const size_t len(buffer.size());
  487|     14|    char *end(&buffer[len - 1] + 1);
  488|  2.12M|    for (size_t readIdx = 0; readIdx < len; ++readIdx) {
  ------------------
  |  Branch (488:30): [True: 2.12M, False: 14]
  ------------------
  489|  2.12M|        char *c(&buffer[readIdx]);
  490|       |        // check for a comment
  491|  2.12M|        if (isCommentOpenTag(c, end)) {
  ------------------
  |  Branch (491:13): [True: 6, False: 2.12M]
  ------------------
  492|      6|            ++readIdx;
  493|   617k|            while (readIdx < len && !isCommentCloseTag(&buffer[readIdx], end)) {
  ------------------
  |  Branch (493:20): [True: 617k, False: 3]
  |  Branch (493:37): [True: 617k, False: 3]
  ------------------
  494|   617k|                ++readIdx;
  495|   617k|            }
  496|      6|            ++readIdx;
  497|  2.12M|        } else if (!isComment<char>(c, end) && !isNewLine(*c)) {
  ------------------
  |  Branch (497:20): [True: 2.12M, False: 61]
  |  Branch (497:48): [True: 2.12M, False: 6.42k]
  ------------------
  498|  2.12M|            newBuffer.push_back(buffer[readIdx]);
  499|  2.12M|        } else {
  500|  6.49k|            if (isComment<char>(c, end)) {
  ------------------
  |  Branch (500:17): [True: 61, False: 6.42k]
  ------------------
  501|     61|                ++readIdx;
  502|       |                // skip the comment and the rest of the line
  503|    421|                while (readIdx < len && !isEndofLine(buffer[readIdx])) {
  ------------------
  |  Branch (503:24): [True: 421, False: 0]
  |  Branch (503:41): [True: 360, False: 61]
  ------------------
  504|    360|                    ++readIdx;
  505|    360|                }
  506|     61|            }
  507|  6.49k|        }
  508|  2.12M|    }
  509|     14|    buffer = newBuffer;
  510|     14|}
_ZN10ODDLParser13OpenDDLParser9parseNameEPcS1_PPNS_4NameE:
  512|    561|char *OpenDDLParser::parseName(char *in, char *end, Name **name) {
  513|    561|    *name = nullptr;
  ------------------
  |  |   59|    561|#define nullptr nullptr
  ------------------
  514|    561|    if (nullptr == in || in == end) {
  ------------------
  |  |   59|    561|#define nullptr nullptr
  ------------------
  |  Branch (514:9): [True: 0, False: 561]
  |  Branch (514:26): [True: 3, False: 558]
  ------------------
  515|      3|        return in;
  516|      3|    }
  517|       |
  518|       |    // ignore blanks
  519|    558|    in = lookForNextToken(in, end);
  520|    558|    if (*in != '$' && *in != '%') {
  ------------------
  |  Branch (520:9): [True: 450, False: 108]
  |  Branch (520:23): [True: 428, False: 22]
  ------------------
  521|    428|        return in;
  522|    428|    }
  523|       |
  524|    130|    NameType ntype(GlobalName);
  525|    130|    if (*in == '%') {
  ------------------
  |  Branch (525:9): [True: 22, False: 108]
  ------------------
  526|     22|        ntype = LocalName;
  527|     22|    }
  528|    130|    in++;
  529|    130|    Name *currentName(nullptr);
  ------------------
  |  |   59|    130|#define nullptr nullptr
  ------------------
  530|    130|    Text *id(nullptr);
  ------------------
  |  |   59|    130|#define nullptr nullptr
  ------------------
  531|    130|    in = parseIdentifier(in, end, &id);
  532|    130|    if (id) {
  ------------------
  |  Branch (532:9): [True: 130, False: 0]
  ------------------
  533|    130|        currentName = new Name(ntype, id);
  534|    130|        if (currentName) {
  ------------------
  |  Branch (534:13): [True: 130, False: 0]
  ------------------
  535|    130|            *name = currentName;
  536|    130|        }
  537|    130|    }
  538|       |
  539|    130|    return in;
  540|    558|}
_ZN10ODDLParser13OpenDDLParser15parseIdentifierEPcS1_PPNS_4TextE:
  542|    771|char *OpenDDLParser::parseIdentifier(char *in, char *end, Text **id) {
  543|    771|    *id = nullptr;
  ------------------
  |  |   59|    771|#define nullptr nullptr
  ------------------
  544|    771|    if (nullptr == in || in == end) {
  ------------------
  |  |   59|    771|#define nullptr nullptr
  ------------------
  |  Branch (544:9): [True: 0, False: 771]
  |  Branch (544:26): [True: 0, False: 771]
  ------------------
  545|      0|        return in;
  546|      0|    }
  547|       |
  548|       |    // ignore blanks
  549|    771|    in = lookForNextToken(in, end);
  550|    771|    if (in == end) {
  ------------------
  |  Branch (550:9): [True: 0, False: 771]
  ------------------
  551|      0|        return in;
  552|      0|    }
  553|       |
  554|       |    // staring with a number is forbidden
  555|    771|    if (isNumeric<const char>(*in)) {
  ------------------
  |  Branch (555:9): [True: 0, False: 771]
  ------------------
  556|      0|        return in;
  557|      0|    }
  558|       |
  559|       |    // get size of id
  560|    771|    size_t idLen(0);
  561|    771|    char *start(in);
  562|  6.74k|    while ((in != end) && !isSeparator(*in) && !isNewLine(*in) &&
  ------------------
  |  Branch (562:12): [True: 6.74k, False: 3]
  |  Branch (562:27): [True: 5.97k, False: 768]
  |  Branch (562:48): [True: 5.97k, False: 0]
  ------------------
  563|  5.97k|            *in != Grammar::OpenPropertyToken[0] &&
  ------------------
  |  Branch (563:13): [True: 5.97k, False: 0]
  ------------------
  564|  5.97k|            *in != Grammar::ClosePropertyToken[0] &&
  ------------------
  |  Branch (564:13): [True: 5.97k, False: 0]
  ------------------
  565|  5.97k|            *in != '$') {
  ------------------
  |  Branch (565:13): [True: 5.97k, False: 0]
  ------------------
  566|  5.97k|        ++in;
  567|  5.97k|        ++idLen;
  568|  5.97k|    }
  569|       |
  570|    771|    const size_t len(idLen);
  571|    771|    *id = new Text(start, len);
  572|       |
  573|    771|    return in;
  574|    771|}
_ZN10ODDLParser13OpenDDLParser22parsePrimitiveDataTypeEPcS1_RNS_5Value9ValueTypeERm:
  576|    674|char *OpenDDLParser::parsePrimitiveDataType(char *in, char *end, Value::ValueType &type, size_t &len) {
  577|    674|    type = Value::ValueType::ddl_none;
  578|    674|    len = 0;
  579|    674|    if (nullptr == in || in == end) {
  ------------------
  |  |   59|    674|#define nullptr nullptr
  ------------------
  |  Branch (579:9): [True: 0, False: 674]
  |  Branch (579:26): [True: 0, False: 674]
  ------------------
  580|      0|        return in;
  581|      0|    }
  582|       |
  583|    674|    size_t prim_len(0);
  584|  9.27k|    for (size_t i = 0; i < (size_t) Value::ValueType::ddl_types_max; i++) {
  ------------------
  |  Branch (584:24): [True: 8.85k, False: 425]
  ------------------
  585|  8.85k|        prim_len = strlen(Grammar::PrimitiveTypeToken[i]);
  586|  8.85k|        if (static_cast<size_t>(end - in) < prim_len) {
  ------------------
  |  Branch (586:13): [True: 9, False: 8.84k]
  ------------------
  587|      9|            continue;
  588|      9|        }
  589|  8.84k|        if (0 == strncmp(in, Grammar::PrimitiveTypeToken[i], prim_len)) {
  ------------------
  |  Branch (589:13): [True: 249, False: 8.59k]
  ------------------
  590|    249|            type = static_cast<Value::ValueType>(i);
  591|    249|            break;
  592|    249|        }
  593|  8.84k|    }
  594|       |
  595|    674|    if (Value::ValueType::ddl_none == type) {
  ------------------
  |  Branch (595:9): [True: 425, False: 249]
  ------------------
  596|    425|        in = lookForNextToken(in, end);
  597|    425|        return in;
  598|    425|    } else {
  599|    249|        in += prim_len;
  600|    249|    }
  601|    249|    if (in >= end) {
  ------------------
  |  Branch (601:9): [True: 0, False: 249]
  ------------------
  602|      0|        return in;
  603|      0|    }
  604|       |
  605|    249|    bool ok(true);
  606|    249|    if (*in == Grammar::OpenArrayToken[0]) {
  ------------------
  |  Branch (606:9): [True: 98, False: 151]
  ------------------
  607|     98|        ok = false;
  608|     98|        ++in;
  609|     98|        char *start(in);
  610|    246|        while (in != end) {
  ------------------
  |  Branch (610:16): [True: 246, False: 0]
  ------------------
  611|    246|            if (*in == Grammar::CloseArrayToken[0]) {
  ------------------
  |  Branch (611:17): [True: 98, False: 148]
  ------------------
  612|     98|                len = ::atoi(start);
  613|     98|                ok = true;
  614|     98|                ++in;
  615|     98|                break;
  616|     98|            }
  617|    148|            ++in;
  618|    148|        }
  619|    151|    } else {
  620|    151|        len = 1;
  621|    151|    }
  622|    249|    if (!ok) {
  ------------------
  |  Branch (622:9): [True: 0, False: 249]
  ------------------
  623|      0|        type = Value::ValueType::ddl_none;
  624|      0|    }
  625|       |
  626|    249|    return in;
  627|    249|}
_ZN10ODDLParser13OpenDDLParser14parseReferenceEPcS1_RNSt3__16vectorIPNS_4NameENS2_9allocatorIS5_EEEE:
  629|     47|char *OpenDDLParser::parseReference(char *in, char *end, std::vector<Name *> &names) {
  630|     47|    if (nullptr == in || in == end) {
  ------------------
  |  |   59|     47|#define nullptr nullptr
  ------------------
  |  Branch (630:9): [True: 0, False: 47]
  |  Branch (630:26): [True: 0, False: 47]
  ------------------
  631|      0|        return in;
  632|      0|    }
  633|       |
  634|     47|    Name *nextName(nullptr);
  ------------------
  |  |   59|     47|#define nullptr nullptr
  ------------------
  635|     47|    in = parseName(in, end, &nextName);
  636|     47|    if (nextName) {
  ------------------
  |  Branch (636:9): [True: 44, False: 3]
  ------------------
  637|     44|        names.push_back(nextName);
  638|     44|    }
  639|     55|    while (in != end && Grammar::CommaSeparator[0] == *in) {
  ------------------
  |  Branch (639:12): [True: 55, False: 0]
  |  Branch (639:25): [True: 8, False: 47]
  ------------------
  640|      8|        in = getNextSeparator(in, end);
  641|      8|        if (in != end && Grammar::CommaSeparator[0] == *in) {
  ------------------
  |  Branch (641:13): [True: 8, False: 0]
  |  Branch (641:26): [True: 8, False: 0]
  ------------------
  642|      8|            in = parseName(in, end, &nextName);
  643|      8|            if (nextName) {
  ------------------
  |  Branch (643:17): [True: 8, False: 0]
  ------------------
  644|      8|                names.push_back(nextName);
  645|      8|            }
  646|      8|        } else {
  647|      0|            break;
  648|      0|        }
  649|      8|    }
  650|       |
  651|     47|    return in;
  652|     47|}
_ZN10ODDLParser13OpenDDLParser19parseIntegerLiteralEPcS1_PPNS_5ValueENS2_9ValueTypeE:
  685|  20.9k|char *OpenDDLParser::parseIntegerLiteral(char *in, char *end, Value **integer, Value::ValueType integerType) {
  686|  20.9k|    *integer = nullptr;
  ------------------
  |  |   59|  20.9k|#define nullptr nullptr
  ------------------
  687|  20.9k|    if (nullptr == in || in == end) {
  ------------------
  |  |   59|  20.9k|#define nullptr nullptr
  ------------------
  |  Branch (687:9): [True: 0, False: 20.9k]
  |  Branch (687:26): [True: 0, False: 20.9k]
  ------------------
  688|      0|        return in;
  689|      0|    }
  690|       |
  691|  20.9k|    if (!(isIntegerType(integerType) || isUnsignedIntegerType(integerType))) {
  ------------------
  |  Branch (691:11): [True: 8, False: 20.9k]
  |  Branch (691:41): [True: 20.9k, False: 0]
  ------------------
  692|      0|        return in;
  693|      0|    }
  694|       |
  695|  20.9k|    in = lookForNextToken(in, end);
  696|  20.9k|    char *start(in);
  697|  96.0k|    while (in != end && !isSeparator(*in)) {
  ------------------
  |  Branch (697:12): [True: 96.0k, False: 0]
  |  Branch (697:25): [True: 75.1k, False: 20.9k]
  ------------------
  698|  75.1k|        ++in;
  699|  75.1k|    }
  700|       |
  701|  20.9k|    if (isNumeric(*start)) {
  ------------------
  |  Branch (701:9): [True: 20.9k, False: 4]
  ------------------
  702|       |#ifdef OPENDDL_NO_USE_CPP11
  703|       |        const int64 value(atol(start)); // maybe not really 64bit as atoll is but exists without c++11
  704|       |        const uint64 uvalue(strtoul(start, nullptr, 10));
  705|       |#else
  706|  20.9k|        const int64 value(atoll(start));
  707|  20.9k|        const uint64 uvalue(strtoull(start, nullptr, 10));
  ------------------
  |  |   59|  20.9k|#define nullptr nullptr
  ------------------
  708|  20.9k|#endif
  709|  20.9k|        *integer = ValueAllocator::allocPrimData(integerType);
  710|  20.9k|        switch (integerType) {
  711|      0|            case Value::ValueType::ddl_int8:
  ------------------
  |  Branch (711:13): [True: 0, False: 20.9k]
  ------------------
  712|      0|                (*integer)->setInt8((int8)value);
  713|      0|                break;
  714|      0|            case Value::ValueType::ddl_int16:
  ------------------
  |  Branch (714:13): [True: 0, False: 20.9k]
  ------------------
  715|      0|                (*integer)->setInt16((int16)value);
  716|      0|                break;
  717|      8|            case Value::ValueType::ddl_int32:
  ------------------
  |  Branch (717:13): [True: 8, False: 20.9k]
  ------------------
  718|      8|                (*integer)->setInt32((int32)value);
  719|      8|                break;
  720|      0|            case Value::ValueType::ddl_int64:
  ------------------
  |  Branch (720:13): [True: 0, False: 20.9k]
  ------------------
  721|      0|                (*integer)->setInt64((int64)value);
  722|      0|                break;
  723|      0|            case Value::ValueType::ddl_unsigned_int8:
  ------------------
  |  Branch (723:13): [True: 0, False: 20.9k]
  ------------------
  724|      0|                (*integer)->setUnsignedInt8((uint8)uvalue);
  725|      0|                break;
  726|    400|            case Value::ValueType::ddl_unsigned_int16:
  ------------------
  |  Branch (726:13): [True: 400, False: 20.5k]
  ------------------
  727|    400|                (*integer)->setUnsignedInt16((uint16)uvalue);
  728|    400|                break;
  729|  20.5k|            case Value::ValueType::ddl_unsigned_int32:
  ------------------
  |  Branch (729:13): [True: 20.5k, False: 408]
  ------------------
  730|  20.5k|                (*integer)->setUnsignedInt32((uint32)uvalue);
  731|  20.5k|                break;
  732|      0|            case Value::ValueType::ddl_unsigned_int64:
  ------------------
  |  Branch (732:13): [True: 0, False: 20.9k]
  ------------------
  733|      0|                (*integer)->setUnsignedInt64((uint64)uvalue);
  734|      0|                break;
  735|      0|            default:
  ------------------
  |  Branch (735:13): [True: 0, False: 20.9k]
  ------------------
  736|      0|                break;
  737|  20.9k|        }
  738|  20.9k|    }
  739|       |
  740|  20.9k|    return in;
  741|  20.9k|}
_ZN10ODDLParser13OpenDDLParser20parseFloatingLiteralEPcS1_PPNS_5ValueENS2_9ValueTypeE:
  743|  92.5k|char *OpenDDLParser::parseFloatingLiteral(char *in, char *end, Value **floating, Value::ValueType floatType) {
  744|  92.5k|    *floating = nullptr;
  ------------------
  |  |   59|  92.5k|#define nullptr nullptr
  ------------------
  745|  92.5k|    if (nullptr == in || in == end) {
  ------------------
  |  |   59|  92.5k|#define nullptr nullptr
  ------------------
  |  Branch (745:9): [True: 0, False: 92.5k]
  |  Branch (745:26): [True: 0, False: 92.5k]
  ------------------
  746|      0|        return in;
  747|      0|    }
  748|       |
  749|  92.5k|    in = lookForNextToken(in, end);
  750|  92.5k|    char *start(in);
  751|  1.50M|    while (in != end && !isSeparator(*in)) {
  ------------------
  |  Branch (751:12): [True: 1.50M, False: 3]
  |  Branch (751:25): [True: 1.41M, False: 92.5k]
  ------------------
  752|  1.41M|        ++in;
  753|  1.41M|    }
  754|       |
  755|       |    // parse the float value
  756|  92.5k|    bool ok(false);
  757|  92.5k|    if (isHexLiteral(start, end)) {
  ------------------
  |  Branch (757:9): [True: 2, False: 92.5k]
  ------------------
  758|      2|        parseHexaLiteral(start, end, floating);
  759|      2|        return in;
  760|      2|    }
  761|       |
  762|  92.5k|    if (isNumeric(*start)) {
  ------------------
  |  Branch (762:9): [True: 65.5k, False: 27.0k]
  ------------------
  763|  65.5k|        ok = true;
  764|  65.5k|    } else {
  765|  27.0k|        if (*start == '-') {
  ------------------
  |  Branch (765:13): [True: 17.8k, False: 9.18k]
  ------------------
  766|  17.8k|            if (isNumeric(*(start + 1))) {
  ------------------
  |  Branch (766:17): [True: 17.4k, False: 455]
  ------------------
  767|  17.4k|                ok = true;
  768|  17.4k|            }
  769|  17.8k|        }
  770|  27.0k|    }
  771|       |
  772|  92.5k|    if (ok) {
  ------------------
  |  Branch (772:9): [True: 82.9k, False: 9.64k]
  ------------------
  773|  82.9k|        if (floatType == Value::ValueType::ddl_double) {
  ------------------
  |  Branch (773:13): [True: 0, False: 82.9k]
  ------------------
  774|      0|            const double value(atof(start));
  775|      0|            *floating = ValueAllocator::allocPrimData(Value::ValueType::ddl_double);
  776|      0|            (*floating)->setDouble(value);
  777|  82.9k|        } else {
  778|  82.9k|            const float value((float)atof(start));
  779|  82.9k|            *floating = ValueAllocator::allocPrimData(Value::ValueType::ddl_float);
  780|  82.9k|            (*floating)->setFloat(value);
  781|  82.9k|        }
  782|  82.9k|    }
  783|       |
  784|  92.5k|    return in;
  785|  92.5k|}
_ZN10ODDLParser13OpenDDLParser18parseStringLiteralEPcS1_PPNS_5ValueE:
  787|    164|char *OpenDDLParser::parseStringLiteral(char *in, char *end, Value **stringData) {
  788|    164|    *stringData = nullptr;
  ------------------
  |  |   59|    164|#define nullptr nullptr
  ------------------
  789|    164|    if (nullptr == in || in == end) {
  ------------------
  |  |   59|    164|#define nullptr nullptr
  ------------------
  |  Branch (789:9): [True: 0, False: 164]
  |  Branch (789:26): [True: 0, False: 164]
  ------------------
  790|      0|        return in;
  791|      0|    }
  792|       |
  793|    164|    in = lookForNextToken(in, end);
  794|    164|    size_t len(0);
  795|    164|    char *start(in);
  796|    164|    if (*start == '\"') {
  ------------------
  |  Branch (796:9): [True: 164, False: 0]
  ------------------
  797|    164|        ++start;
  798|    164|        ++in;
  799|  1.24k|        while (in != end && *in != '\"') {
  ------------------
  |  Branch (799:16): [True: 1.24k, False: 0]
  |  Branch (799:29): [True: 1.08k, False: 164]
  ------------------
  800|  1.08k|            ++in;
  801|  1.08k|            ++len;
  802|  1.08k|        }
  803|    164|        if (in == end) {
  ------------------
  |  Branch (803:13): [True: 0, False: 164]
  ------------------
  804|      0|            return in;
  805|      0|        }
  806|       |
  807|    164|        *stringData = ValueAllocator::allocPrimData(Value::ValueType::ddl_string, len);
  808|    164|        ::strncpy((char *)(*stringData)->m_data, start, len);
  809|    164|        (*stringData)->m_data[len] = '\0';
  810|    164|        ++in;
  811|    164|    }
  812|       |
  813|    164|    return in;
  814|    164|}
_ZN10ODDLParser13OpenDDLParser16parseHexaLiteralEPcS1_PPNS_5ValueE:
  823|      2|char *OpenDDLParser::parseHexaLiteral(char *in, char *end, Value **data) {
  824|      2|    *data = nullptr;
  ------------------
  |  |   59|      2|#define nullptr nullptr
  ------------------
  825|      2|    if (nullptr == in || in == end) {
  ------------------
  |  |   59|      2|#define nullptr nullptr
  ------------------
  |  Branch (825:9): [True: 0, False: 2]
  |  Branch (825:26): [True: 0, False: 2]
  ------------------
  826|      0|        return in;
  827|      0|    }
  828|       |
  829|      2|    in = lookForNextToken(in, end);
  830|      2|    if (*in != '0') {
  ------------------
  |  Branch (830:9): [True: 0, False: 2]
  ------------------
  831|      0|        return in;
  832|      0|    }
  833|       |
  834|      2|    ++in;
  835|      2|    if (*in != 'x' && *in != 'X') {
  ------------------
  |  Branch (835:9): [True: 0, False: 2]
  |  Branch (835:23): [True: 0, False: 0]
  ------------------
  836|      0|        return in;
  837|      0|    }
  838|       |
  839|      2|    ++in;
  840|      2|    bool ok(true);
  841|      2|    char *start(in);
  842|      2|    int pos(0);
  843|    160|    while (in != end && !isSeparator(*in)) {
  ------------------
  |  Branch (843:12): [True: 160, False: 0]
  |  Branch (843:25): [True: 158, False: 2]
  ------------------
  844|    158|        if ((*in < '0' && *in > '9') || (*in < 'a' && *in > 'f') || (*in < 'A' && *in > 'F')) {
  ------------------
  |  Branch (844:14): [True: 102, False: 56]
  |  Branch (844:27): [True: 0, False: 102]
  |  Branch (844:42): [True: 152, False: 6]
  |  Branch (844:55): [True: 0, False: 152]
  |  Branch (844:70): [True: 152, False: 6]
  |  Branch (844:83): [True: 0, False: 152]
  ------------------
  845|      0|            ok = false;
  846|      0|            break;
  847|      0|        }
  848|    158|        ++pos;
  849|    158|        ++in;
  850|    158|    }
  851|       |
  852|      2|    if (!ok) {
  ------------------
  |  Branch (852:9): [True: 0, False: 2]
  ------------------
  853|      0|        return in;
  854|      0|    }
  855|       |
  856|      2|    int value(0);
  857|    160|    while (pos > 0) {
  ------------------
  |  Branch (857:12): [True: 158, False: 2]
  ------------------
  858|    158|        int v = hex2Decimal(*start);
  859|    158|        if (v < 0) {
  ------------------
  |  Branch (859:13): [True: 0, False: 158]
  ------------------
  860|      0|            while (isEndofLine(*in)) {
  ------------------
  |  Branch (860:20): [True: 0, False: 0]
  ------------------
  861|      0|                ++in;
  862|      0|            }
  863|      0|            return in;
  864|      0|        }
  865|       |            
  866|    158|        --pos;
  867|    158|        value = (value << 4) | v;
  868|    158|        ++start;
  869|    158|    }
  870|       |
  871|      2|    *data = ValueAllocator::allocPrimData(Value::ValueType::ddl_unsigned_int64);
  872|      2|    if (nullptr != *data) {
  ------------------
  |  |   59|      2|#define nullptr nullptr
  ------------------
  |  Branch (872:9): [True: 2, False: 0]
  ------------------
  873|      2|        (*data)->setUnsignedInt64(value);
  874|      2|    }
  875|       |
  876|      2|    return in;
  877|      2|}
_ZN10ODDLParser13OpenDDLParser13parsePropertyEPcS1_PPNS_8PropertyE:
  879|    135|char *OpenDDLParser::parseProperty(char *in, char *end, Property **prop) {
  880|    135|    *prop = nullptr;
  ------------------
  |  |   59|    135|#define nullptr nullptr
  ------------------
  881|    135|    if (nullptr == in || in == end) {
  ------------------
  |  |   59|    135|#define nullptr nullptr
  ------------------
  |  Branch (881:9): [True: 0, False: 135]
  |  Branch (881:26): [True: 0, False: 135]
  ------------------
  882|      0|        return in;
  883|      0|    }
  884|       |
  885|    135|    in = lookForNextToken(in, end);
  886|    135|    Text *id = nullptr;
  ------------------
  |  |   59|    135|#define nullptr nullptr
  ------------------
  887|    135|    in = parseIdentifier(in, end, &id);
  888|    135|    if (nullptr != id) {
  ------------------
  |  |   59|    135|#define nullptr nullptr
  ------------------
  |  Branch (888:9): [True: 135, False: 0]
  ------------------
  889|    135|        in = lookForNextToken(in, end);
  890|    135|        if (in != end && *in == '=') {
  ------------------
  |  Branch (890:13): [True: 135, False: 0]
  |  Branch (890:26): [True: 135, False: 0]
  ------------------
  891|    135|            ++in;
  892|    135|            in = getNextToken(in, end);
  893|    135|            Value *primData(nullptr);
  ------------------
  |  |   59|    135|#define nullptr nullptr
  ------------------
  894|    135|            if (isInteger(in, end)) {
  ------------------
  |  Branch (894:17): [True: 8, False: 127]
  ------------------
  895|      8|                in = parseIntegerLiteral(in, end, &primData);
  896|      8|                createPropertyWithData(id, primData, prop);
  897|    127|            } else if (isFloat(in, end)) {
  ------------------
  |  Branch (897:24): [True: 0, False: 127]
  ------------------
  898|      0|                in = parseFloatingLiteral(in, end, &primData);
  899|      0|                createPropertyWithData(id, primData, prop);
  900|    127|            } else if (isStringLiteral(*in)) { // string data
  ------------------
  |  Branch (900:24): [True: 117, False: 10]
  ------------------
  901|    117|                in = parseStringLiteral(in, end, &primData);
  902|    117|                createPropertyWithData(id, primData, prop);
  903|    117|            } else { // reference data
  904|     10|                std::vector<Name *> names;
  905|     10|                in = parseReference(in, end, names);
  906|     10|                if (!names.empty()) {
  ------------------
  |  Branch (906:21): [True: 10, False: 0]
  ------------------
  907|     10|                    Reference *ref = new Reference(names.size(), &names[0]);
  908|     10|                    (*prop) = new Property(id);
  909|     10|                    (*prop)->m_ref = ref;
  910|     10|                }
  911|     10|            }
  912|    135|        } else {
  913|      0|            delete id;
  914|      0|        }
  915|    135|    }
  916|       |
  917|    135|    return in;
  918|    135|}
_ZN10ODDLParser13OpenDDLParser13parseDataListEPcS1_NS_5Value9ValueTypeEPPS2_RmPPNS_9ReferenceES6_:
  921|  22.6k|        size_t &numValues, Reference **refs, size_t &numRefs) {
  922|  22.6k|    *data = nullptr;
  ------------------
  |  |   59|  22.6k|#define nullptr nullptr
  ------------------
  923|  22.6k|    numValues = numRefs = 0;
  924|  22.6k|    if (nullptr == in || in == end) {
  ------------------
  |  |   59|  22.6k|#define nullptr nullptr
  ------------------
  |  Branch (924:9): [True: 0, False: 22.6k]
  |  Branch (924:26): [True: 0, False: 22.6k]
  ------------------
  925|      0|        return in;
  926|      0|    }
  927|       |
  928|  22.6k|    in = lookForNextToken(in, end);
  929|  22.6k|    if (in != end && *in == '{') {
  ------------------
  |  Branch (929:9): [True: 22.6k, False: 0]
  |  Branch (929:22): [True: 22.6k, False: 0]
  ------------------
  930|  22.6k|        ++in;
  931|  22.6k|        Value *current(nullptr), *prev(nullptr);
  ------------------
  |  |   59|  22.6k|#define nullptr nullptr
  ------------------
                      Value *current(nullptr), *prev(nullptr);
  ------------------
  |  |   59|  22.6k|#define nullptr nullptr
  ------------------
  932|   136k|        while (in != end && '}' != *in) {
  ------------------
  |  Branch (932:16): [True: 136k, False: 0]
  |  Branch (932:29): [True: 113k, False: 22.6k]
  ------------------
  933|   113k|            current = nullptr;
  ------------------
  |  |   59|   113k|#define nullptr nullptr
  ------------------
  934|   113k|            in = lookForNextToken(in, end);
  935|   113k|            if (Value::ValueType::ddl_ref == type) {
  ------------------
  |  Branch (935:17): [True: 37, False: 113k]
  ------------------
  936|     37|                std::vector<Name *> names;
  937|     37|                in = parseReference(in, end, names);
  938|     37|                if (!names.empty()) {
  ------------------
  |  Branch (938:21): [True: 34, False: 3]
  ------------------
  939|     34|                    Reference *ref = new Reference(names.size(), &names[0]);
  940|     34|                    *refs = ref;
  941|     34|                    numRefs = names.size();
  942|     34|                }
  943|   113k|            } else if (Value::ValueType::ddl_none == type) {
  ------------------
  |  Branch (943:24): [True: 0, False: 113k]
  ------------------
  944|      0|                if (isInteger(in, end)) {
  ------------------
  |  Branch (944:21): [True: 0, False: 0]
  ------------------
  945|      0|                    in = parseIntegerLiteral(in, end, &current);
  946|      0|                } else if (isFloat(in, end)) {
  ------------------
  |  Branch (946:28): [True: 0, False: 0]
  ------------------
  947|      0|                    in = parseFloatingLiteral(in, end, &current);
  948|      0|                } else if (isStringLiteral(*in)) {
  ------------------
  |  Branch (948:28): [True: 0, False: 0]
  ------------------
  949|      0|                    in = parseStringLiteral(in, end, &current);
  950|      0|                } else if (isHexLiteral(in, end)) {
  ------------------
  |  Branch (950:28): [True: 0, False: 0]
  ------------------
  951|      0|                    in = parseHexaLiteral(in, end, &current);
  952|      0|                }
  953|   113k|            } else {
  954|   113k|                switch (type) {
  955|      0|                    case Value::ValueType::ddl_int8:
  ------------------
  |  Branch (955:21): [True: 0, False: 113k]
  ------------------
  956|      0|                    case Value::ValueType::ddl_int16:
  ------------------
  |  Branch (956:21): [True: 0, False: 113k]
  ------------------
  957|      0|                    case Value::ValueType::ddl_int32:
  ------------------
  |  Branch (957:21): [True: 0, False: 113k]
  ------------------
  958|      0|                    case Value::ValueType::ddl_int64:
  ------------------
  |  Branch (958:21): [True: 0, False: 113k]
  ------------------
  959|      0|                    case Value::ValueType::ddl_unsigned_int8:
  ------------------
  |  Branch (959:21): [True: 0, False: 113k]
  ------------------
  960|    404|                    case Value::ValueType::ddl_unsigned_int16:
  ------------------
  |  Branch (960:21): [True: 404, False: 113k]
  ------------------
  961|  20.9k|                    case Value::ValueType::ddl_unsigned_int32:
  ------------------
  |  Branch (961:21): [True: 20.5k, False: 93.0k]
  ------------------
  962|  20.9k|                    case Value::ValueType::ddl_unsigned_int64:
  ------------------
  |  Branch (962:21): [True: 0, False: 113k]
  ------------------
  963|  20.9k|                        in = parseIntegerLiteral(in, end, &current, type);
  964|  20.9k|                        break;
  965|      0|                    case Value::ValueType::ddl_half:
  ------------------
  |  Branch (965:21): [True: 0, False: 113k]
  ------------------
  966|  92.5k|                    case Value::ValueType::ddl_float:
  ------------------
  |  Branch (966:21): [True: 92.5k, False: 21.0k]
  ------------------
  967|  92.5k|                    case Value::ValueType::ddl_double:
  ------------------
  |  Branch (967:21): [True: 0, False: 113k]
  ------------------
  968|  92.5k|                        in = parseFloatingLiteral(in, end, &current, type);
  969|  92.5k|                        break;
  970|     47|                    case Value::ValueType::ddl_string:
  ------------------
  |  Branch (970:21): [True: 47, False: 113k]
  ------------------
  971|     47|                        in = parseStringLiteral(in, end, &current);
  972|     47|                        break;
  973|      0|                    default:
  ------------------
  |  Branch (973:21): [True: 0, False: 113k]
  ------------------
  974|      0|                        break;
  975|   113k|                }
  976|   113k|            }
  977|       |
  978|   113k|            if (nullptr != current) {
  ------------------
  |  |   59|   113k|#define nullptr nullptr
  ------------------
  |  Branch (978:17): [True: 103k, False: 9.68k]
  ------------------
  979|   103k|                if (nullptr == *data) {
  ------------------
  |  |   59|   103k|#define nullptr nullptr
  ------------------
  |  Branch (979:21): [True: 22.5k, False: 81.3k]
  ------------------
  980|  22.5k|                    *data = current;
  981|  22.5k|                    prev = current;
  982|  81.3k|                } else {
  983|  81.3k|                    prev->setNext(current);
  984|  81.3k|                    prev = current;
  985|  81.3k|                }
  986|   103k|                ++numValues;
  987|   103k|            }
  988|       |
  989|   113k|            in = getNextSeparator(in, end);
  990|   113k|            if (in == end || (',' != *in && Grammar::CloseBracketToken[0] != *in && !isSpace(*in))) {
  ------------------
  |  Branch (990:17): [True: 3, False: 113k]
  |  Branch (990:31): [True: 23.8k, False: 89.7k]
  |  Branch (990:45): [True: 1.22k, False: 22.6k]
  |  Branch (990:85): [True: 3, False: 1.22k]
  ------------------
  991|      6|                break;
  992|      6|            }
  993|   113k|        }
  994|  22.6k|        if (in != end)
  ------------------
  |  Branch (994:13): [True: 22.6k, False: 3]
  ------------------
  995|  22.6k|            ++in;
  996|  22.6k|    }
  997|       |
  998|  22.6k|    return in;
  999|  22.6k|}
_ZN10ODDLParser13OpenDDLParser18parseDataArrayListEPcS1_NS_5Value9ValueTypeEPPNS_13DataArrayListE:
 1013|     98|        DataArrayList **dataArrayList) {
 1014|     98|    if (nullptr == dataArrayList) {
  ------------------
  |  |   59|     98|#define nullptr nullptr
  ------------------
  |  Branch (1014:9): [True: 0, False: 98]
  ------------------
 1015|      0|        return in;
 1016|      0|    }
 1017|       |
 1018|     98|    *dataArrayList = nullptr;
  ------------------
  |  |   59|     98|#define nullptr nullptr
  ------------------
 1019|     98|    if (nullptr == in || in == end) {
  ------------------
  |  |   59|     98|#define nullptr nullptr
  ------------------
  |  Branch (1019:9): [True: 0, False: 98]
  |  Branch (1019:26): [True: 0, False: 98]
  ------------------
 1020|      0|        return in;
 1021|      0|    }
 1022|       |
 1023|     98|    in = lookForNextToken(in, end);
 1024|     98|    if (*in == Grammar::OpenBracketToken[0]) {
  ------------------
  |  Branch (1024:9): [True: 98, False: 0]
  ------------------
 1025|     98|        ++in;
 1026|     98|        Value *currentValue(nullptr);
  ------------------
  |  |   59|     98|#define nullptr nullptr
  ------------------
 1027|     98|        Reference *refs(nullptr);
  ------------------
  |  |   59|     98|#define nullptr nullptr
  ------------------
 1028|     98|        DataArrayList *prev(nullptr), *currentDataList(nullptr);
  ------------------
  |  |   59|     98|#define nullptr nullptr
  ------------------
                      DataArrayList *prev(nullptr), *currentDataList(nullptr);
  ------------------
  |  |   59|     98|#define nullptr nullptr
  ------------------
 1029|  22.4k|        do {
 1030|  22.4k|            size_t numRefs(0), numValues(0);
 1031|  22.4k|            currentValue = nullptr;
  ------------------
  |  |   59|  22.4k|#define nullptr nullptr
  ------------------
 1032|       |
 1033|  22.4k|            in = parseDataList(in, end, type, &currentValue, numValues, &refs, numRefs);
 1034|  22.4k|            if (nullptr != currentValue || 0 != numRefs) {
  ------------------
  |  |   59|  22.4k|#define nullptr nullptr
  ------------------
  |  Branch (1034:17): [True: 22.4k, False: 0]
  |  Branch (1034:44): [True: 0, False: 0]
  ------------------
 1035|  22.4k|                if (nullptr == prev) {
  ------------------
  |  |   59|  22.4k|#define nullptr nullptr
  ------------------
  |  Branch (1035:21): [True: 98, False: 22.3k]
  ------------------
 1036|     98|                    *dataArrayList = createDataArrayList(currentValue, numValues, refs, numRefs);
 1037|     98|                    prev = *dataArrayList;
 1038|  22.3k|                } else {
 1039|  22.3k|                    currentDataList = createDataArrayList(currentValue, numValues, refs, numRefs);
 1040|  22.3k|                    if (nullptr != prev) {
  ------------------
  |  |   59|  22.3k|#define nullptr nullptr
  ------------------
  |  Branch (1040:25): [True: 22.3k, False: 0]
  ------------------
 1041|  22.3k|                        prev->m_next = currentDataList;
 1042|  22.3k|                        prev = currentDataList;
 1043|  22.3k|                    }
 1044|  22.3k|                }
 1045|  22.4k|            }
 1046|  22.4k|        } while (Grammar::CommaSeparator[0] == *in && in != end);
  ------------------
  |  Branch (1046:18): [True: 22.3k, False: 98]
  |  Branch (1046:55): [True: 22.3k, False: 0]
  ------------------
 1047|     98|        in = lookForNextToken(in, end);
 1048|     98|        ++in;
 1049|     98|    }
 1050|       |
 1051|     98|    return in;
 1052|     98|}
OpenDDLParser.cpp:_ZN10ODDLParserL13createDDLNodeEPNS_4TextEPNS_13OpenDDLParserE:
  106|    506|static DDLNode *createDDLNode(Text *id, OpenDDLParser *parser) {
  107|    506|    if (nullptr == id || nullptr == parser || id->m_buffer == nullptr) {
  ------------------
  |  |   59|    506|#define nullptr nullptr
  ------------------
                  if (nullptr == id || nullptr == parser || id->m_buffer == nullptr) {
  ------------------
  |  |   59|    506|#define nullptr nullptr
  ------------------
                  if (nullptr == id || nullptr == parser || id->m_buffer == nullptr) {
  ------------------
  |  |   59|    506|#define nullptr nullptr
  ------------------
  |  Branch (107:9): [True: 0, False: 506]
  |  Branch (107:26): [True: 0, False: 506]
  |  Branch (107:47): [True: 107, False: 399]
  ------------------
  108|    107|        return nullptr;
  ------------------
  |  |   59|    107|#define nullptr nullptr
  ------------------
  109|    107|    }
  110|       |
  111|    399|    const std::string type(id->m_buffer);
  112|    399|    DDLNode *parent(parser->top());
  113|    399|    DDLNode *node = DDLNode::create(type, "", parent);
  114|       |
  115|    399|    return node;
  116|    506|}
OpenDDLParser.cpp:_ZN10ODDLParserL20logInvalidTokenErrorERKNSt3__112basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEES8_NS0_8functionIFvNS_11LogSeverityES8_EEE:
   77|      7|static void logInvalidTokenError(const std::string &in, const std::string &exp, OpenDDLParser::logCallback callback) {
   78|      7|    if (callback) {\
  ------------------
  |  Branch (78:9): [True: 7, False: 0]
  ------------------
   79|      7|        std::string part(in.substr(0, 50));
   80|      7|        std::stringstream stream;
   81|      7|        stream << "Invalid token \"" << in << "\" "
   82|      7|               << "(expected \"" << exp << "\") "
   83|      7|               << "in: \"" << part << "\"";
   84|      7|        callback(ddl_error_msg, stream.str());
   85|      7|    }
   86|      7|}
OpenDDLParser.cpp:_ZN10ODDLParserL13setNodeValuesEPNS_7DDLNodeEPNS_5ValueE:
  372|    151|static void setNodeValues(DDLNode *currentNode, Value *values) {
  373|    151|    if (nullptr != values) {
  ------------------
  |  |   59|    151|#define nullptr nullptr
  ------------------
  |  Branch (373:9): [True: 116, False: 35]
  ------------------
  374|    116|        if (nullptr != currentNode) {
  ------------------
  |  |   59|    116|#define nullptr nullptr
  ------------------
  |  Branch (374:13): [True: 116, False: 0]
  ------------------
  375|    116|            currentNode->setValue(values);
  376|    116|        }
  377|    116|    }
  378|    151|}
OpenDDLParser.cpp:_ZN10ODDLParserL17setNodeReferencesEPNS_7DDLNodeEPNS_9ReferenceE:
  380|    151|static void setNodeReferences(DDLNode *currentNode, Reference *refs) {
  381|    151|    if (nullptr != refs) {
  ------------------
  |  |   59|    151|#define nullptr nullptr
  ------------------
  |  Branch (381:9): [True: 34, False: 117]
  ------------------
  382|     34|        if (nullptr != currentNode) {
  ------------------
  |  |   59|     34|#define nullptr nullptr
  ------------------
  |  Branch (382:13): [True: 34, False: 0]
  ------------------
  383|     34|            currentNode->setReferences(refs);
  384|     34|        }
  385|     34|    }
  386|    151|}
OpenDDLParser.cpp:_ZN10ODDLParserL20setNodeDataArrayListEPNS_7DDLNodeEPNS_13DataArrayListE:
  388|     98|static void setNodeDataArrayList(DDLNode *currentNode, DataArrayList *dtArrayList) {
  389|     98|    if (nullptr != dtArrayList) {
  ------------------
  |  |   59|     98|#define nullptr nullptr
  ------------------
  |  Branch (389:9): [True: 98, False: 0]
  ------------------
  390|     98|        if (nullptr != currentNode) {
  ------------------
  |  |   59|     98|#define nullptr nullptr
  ------------------
  |  Branch (390:13): [True: 98, False: 0]
  ------------------
  391|     98|            currentNode->setDataArrayList(dtArrayList);
  392|     98|        }
  393|     98|    }
  394|     98|}
OpenDDLParser.cpp:_ZN10ODDLParserL13isIntegerTypeENS_5Value9ValueTypeE:
   88|  20.9k|static bool isIntegerType(Value::ValueType integerType) {
   89|  20.9k|    if (integerType != Value::ValueType::ddl_int8 && integerType != Value::ValueType::ddl_int16 &&
  ------------------
  |  Branch (89:9): [True: 20.9k, False: 0]
  |  Branch (89:54): [True: 20.9k, False: 0]
  ------------------
   90|  20.9k|            integerType != Value::ValueType::ddl_int32 && integerType != Value::ValueType::ddl_int64) {
  ------------------
  |  Branch (90:13): [True: 20.9k, False: 8]
  |  Branch (90:59): [True: 20.9k, False: 0]
  ------------------
   91|  20.9k|        return false;
   92|  20.9k|    }
   93|       |
   94|      8|    return true;
   95|  20.9k|}
OpenDDLParser.cpp:_ZN10ODDLParserL21isUnsignedIntegerTypeENS_5Value9ValueTypeE:
   97|  20.9k|static bool isUnsignedIntegerType(Value::ValueType integerType) {
   98|  20.9k|    if (integerType != Value::ValueType::ddl_unsigned_int8 && integerType != Value::ValueType::ddl_unsigned_int16 &&
  ------------------
  |  Branch (98:9): [True: 20.9k, False: 0]
  |  Branch (98:63): [True: 20.5k, False: 404]
  ------------------
   99|  20.5k|            integerType != Value::ValueType::ddl_unsigned_int32 && integerType != Value::ValueType::ddl_unsigned_int64) {
  ------------------
  |  Branch (99:13): [True: 0, False: 20.5k]
  |  Branch (99:68): [True: 0, False: 0]
  ------------------
  100|      0|        return false;
  101|      0|    }
  102|       |
  103|  20.9k|    return true;
  104|  20.9k|}
OpenDDLParser.cpp:_ZN10ODDLParserL22createPropertyWithDataEPNS_4TextEPNS_5ValueEPPNS_8PropertyE:
  816|    125|static void createPropertyWithData(Text *id, Value *primData, Property **prop) {
  817|    125|    if (nullptr != primData) {
  ------------------
  |  |   59|    125|#define nullptr nullptr
  ------------------
  |  Branch (817:9): [True: 125, False: 0]
  ------------------
  818|    125|        (*prop) = new Property(id);
  819|    125|        (*prop)->m_value = primData;
  820|    125|    }
  821|    125|}
OpenDDLParser.cpp:_ZN10ODDLParserL19createDataArrayListEPNS_5ValueEmPNS_9ReferenceEm:
 1002|  22.4k|        Reference *refs, size_t numRefs) {
 1003|  22.4k|    DataArrayList *dataList(new DataArrayList);
 1004|  22.4k|    dataList->m_dataList = currentValue;
 1005|  22.4k|    dataList->m_numItems = numValues;
 1006|  22.4k|    dataList->m_refs = refs;
 1007|  22.4k|    dataList->m_numRefs = numRefs;
 1008|       |
 1009|  22.4k|    return dataList;
 1010|  22.4k|}

_ZN10ODDLParser5Value8IteratorC2EPS0_:
   39|      2|        m_start(start),
   40|      2|        m_current(start) {
   41|       |    // empty
   42|      2|}
_ZN10ODDLParser5ValueC2ENS0_9ValueTypeE:
  105|   104k|        m_type(type),
  106|   104k|        m_size(0),
  107|   104k|        m_data(nullptr),
  ------------------
  |  |   59|   104k|#define nullptr nullptr
  ------------------
  108|   104k|        m_next(nullptr) {
  ------------------
  |  |   59|   104k|#define nullptr nullptr
  ------------------
  109|       |    // empty
  110|   104k|}
_ZN10ODDLParser5ValueD2Ev:
  112|   104k|Value::~Value() {
  113|   104k|    if (m_data != nullptr) {
  ------------------
  |  |   59|   104k|#define nullptr nullptr
  ------------------
  |  Branch (113:9): [True: 104k, False: 0]
  ------------------
  114|   104k|        if (m_type == ValueType::ddl_ref) {
  ------------------
  |  Branch (114:13): [True: 0, False: 104k]
  ------------------
  115|      0|            Reference *tmp = (Reference *)m_data;
  116|      0|            if (tmp != nullptr) {
  ------------------
  |  |   59|      0|#define nullptr nullptr
  ------------------
  |  Branch (116:17): [True: 0, False: 0]
  ------------------
  117|      0|                delete tmp;
  118|      0|            }
  119|   104k|        } else {
  120|   104k|            delete[] m_data;
  121|   104k|        }
  122|   104k|    }
  123|   104k|    delete m_next;
  124|   104k|}
_ZN10ODDLParser5Value8setInt32Ei:
  158|      8|void Value::setInt32(int32 value) {
  159|      8|    assert(ValueType::ddl_int32 == m_type);
  ------------------
  |  Branch (159:5): [True: 8, False: 0]
  ------------------
  160|      8|    ::memcpy(m_data, &value, m_size);
  161|      8|}
_ZN10ODDLParser5Value16setUnsignedInt16Et:
  194|    400|void Value::setUnsignedInt16(uint16 value) {
  195|    400|    assert(ValueType::ddl_unsigned_int16 == m_type);
  ------------------
  |  Branch (195:5): [True: 400, False: 0]
  ------------------
  196|    400|    ::memcpy(m_data, &value, m_size);
  197|    400|}
_ZN10ODDLParser5Value16setUnsignedInt32Ej:
  206|  20.5k|void Value::setUnsignedInt32(uint32 value) {
  207|  20.5k|    assert(ValueType::ddl_unsigned_int32 == m_type);
  ------------------
  |  Branch (207:5): [True: 20.5k, False: 0]
  ------------------
  208|  20.5k|    ::memcpy(m_data, &value, m_size);
  209|  20.5k|}
_ZNK10ODDLParser5Value16getUnsignedInt32Ev:
  211|  20.3k|uint32 Value::getUnsignedInt32() const {
  212|  20.3k|    assert(ValueType::ddl_unsigned_int32 == m_type);
  ------------------
  |  Branch (212:5): [True: 20.3k, False: 0]
  ------------------
  213|  20.3k|    uint32 i;
  214|  20.3k|    ::memcpy(&i, m_data, m_size);
  215|  20.3k|    return i;
  216|  20.3k|}
_ZN10ODDLParser5Value16setUnsignedInt64Em:
  218|      2|void Value::setUnsignedInt64(uint64 value) {
  219|      2|    assert(ValueType::ddl_unsigned_int64 == m_type);
  ------------------
  |  Branch (219:5): [True: 2, False: 0]
  ------------------
  220|      2|    ::memcpy(m_data, &value, m_size);
  221|      2|}
_ZN10ODDLParser5Value8setFloatEf:
  230|  82.9k|void Value::setFloat(float value) {
  231|  82.9k|    assert(ValueType::ddl_float == m_type);
  ------------------
  |  Branch (231:5): [True: 82.9k, False: 0]
  ------------------
  232|  82.9k|    ::memcpy(m_data, &value, m_size);
  233|  82.9k|}
_ZNK10ODDLParser5Value8getFloatEv:
  235|  38.1k|float Value::getFloat() const {
  236|  38.1k|    if (m_type == ValueType::ddl_float) {
  ------------------
  |  Branch (236:9): [True: 38.1k, False: 0]
  ------------------
  237|  38.1k|        float v;
  238|  38.1k|        ::memcpy(&v, m_data, m_size);
  239|  38.1k|        return (float)v;
  240|  38.1k|    } else {
  241|      0|        float tmp;
  242|      0|        ::memcpy(&tmp, m_data, 4);
  243|      0|        return (float)tmp;
  244|      0|    }
  245|  38.1k|}
_ZNK10ODDLParser5Value9getStringEv:
  270|     77|const char *Value::getString() const {
  271|     77|    assert(ValueType::ddl_string == m_type);
  ------------------
  |  Branch (271:5): [True: 77, False: 0]
  ------------------
  272|     77|    return (const char *)m_data;
  273|     77|}
_ZN10ODDLParser5Value7setNextEPS0_:
  348|  81.3k|void Value::setNext(Value *next) {
  349|  81.3k|    m_next = next;
  350|  81.3k|}
_ZN10ODDLParser14ValueAllocator13allocPrimDataENS_5Value9ValueTypeEm:
  366|   104k|Value *ValueAllocator::allocPrimData(Value::ValueType type, size_t len) {
  367|   104k|    if (type == Value::ValueType::ddl_none || Value::ValueType::ddl_types_max == type) {
  ------------------
  |  Branch (367:9): [True: 0, False: 104k]
  |  Branch (367:47): [True: 0, False: 104k]
  ------------------
  368|      0|        return nullptr;
  ------------------
  |  |   59|      0|#define nullptr nullptr
  ------------------
  369|      0|    }
  370|       |
  371|   104k|    Value *data = new Value(type);
  372|   104k|    switch (type) {
  373|      0|        case Value::ValueType::ddl_bool:
  ------------------
  |  Branch (373:9): [True: 0, False: 104k]
  ------------------
  374|      0|            data->m_size = sizeof(bool);
  375|      0|            break;
  376|      0|        case Value::ValueType::ddl_int8:
  ------------------
  |  Branch (376:9): [True: 0, False: 104k]
  ------------------
  377|      0|            data->m_size = sizeof(int8);
  378|      0|            break;
  379|      0|        case Value::ValueType::ddl_int16:
  ------------------
  |  Branch (379:9): [True: 0, False: 104k]
  ------------------
  380|      0|            data->m_size = sizeof(int16);
  381|      0|            break;
  382|      8|        case Value::ValueType::ddl_int32:
  ------------------
  |  Branch (382:9): [True: 8, False: 104k]
  ------------------
  383|      8|            data->m_size = sizeof(int32);
  384|      8|            break;
  385|      0|        case Value::ValueType::ddl_int64:
  ------------------
  |  Branch (385:9): [True: 0, False: 104k]
  ------------------
  386|      0|            data->m_size = sizeof(int64);
  387|      0|            break;
  388|      0|        case Value::ValueType::ddl_unsigned_int8:
  ------------------
  |  Branch (388:9): [True: 0, False: 104k]
  ------------------
  389|      0|            data->m_size = sizeof(uint8);
  390|      0|            break;
  391|    400|        case Value::ValueType::ddl_unsigned_int16:
  ------------------
  |  Branch (391:9): [True: 400, False: 103k]
  ------------------
  392|    400|            data->m_size = sizeof(uint16);
  393|    400|            break;
  394|  20.5k|        case Value::ValueType::ddl_unsigned_int32:
  ------------------
  |  Branch (394:9): [True: 20.5k, False: 83.5k]
  ------------------
  395|  20.5k|            data->m_size = sizeof(uint32);
  396|  20.5k|            break;
  397|      2|        case Value::ValueType::ddl_unsigned_int64:
  ------------------
  |  Branch (397:9): [True: 2, False: 104k]
  ------------------
  398|      2|            data->m_size = sizeof(uint64);
  399|      2|            break;
  400|      0|        case Value::ValueType::ddl_half:
  ------------------
  |  Branch (400:9): [True: 0, False: 104k]
  ------------------
  401|      0|            data->m_size = sizeof(short);
  402|      0|            break;
  403|  82.9k|        case Value::ValueType::ddl_float:
  ------------------
  |  Branch (403:9): [True: 82.9k, False: 21.1k]
  ------------------
  404|  82.9k|            data->m_size = sizeof(float);
  405|  82.9k|            break;
  406|      0|        case Value::ValueType::ddl_double:
  ------------------
  |  Branch (406:9): [True: 0, False: 104k]
  ------------------
  407|      0|            data->m_size = sizeof(double);
  408|      0|            break;
  409|    164|        case Value::ValueType::ddl_string:
  ------------------
  |  Branch (409:9): [True: 164, False: 103k]
  ------------------
  410|    164|            data->m_size = sizeof(char) * (len + 1);
  411|    164|            break;
  412|      0|        case Value::ValueType::ddl_ref:
  ------------------
  |  Branch (412:9): [True: 0, False: 104k]
  ------------------
  413|      0|            data->m_size = 0;
  414|      0|            break;
  415|      0|        case Value::ValueType::ddl_none:
  ------------------
  |  Branch (415:9): [True: 0, False: 104k]
  ------------------
  416|      0|        case Value::ValueType::ddl_types_max:
  ------------------
  |  Branch (416:9): [True: 0, False: 104k]
  ------------------
  417|      0|        default:
  ------------------
  |  Branch (417:9): [True: 0, False: 104k]
  ------------------
  418|      0|            break;
  419|   104k|    }
  420|       |
  421|   104k|    if (data->m_size) {
  ------------------
  |  Branch (421:9): [True: 104k, False: 0]
  ------------------
  422|   104k|        data->m_data = new unsigned char[data->m_size];
  423|   104k|        ::memset(data->m_data, 0, data->m_size);
  424|   104k|    }
  425|       |
  426|   104k|    return data;
  427|   104k|}

_ZN10ODDLParser16lookForNextTokenIcEEPT_S2_S2_:
   49|   255k|inline T *lookForNextToken(T *in, T *end) {
   50|   502k|    while ((in != end) && (isSpace(*in) || isNewLine(*in) || ',' == *in)) {
  ------------------
  |  Branch (50:12): [True: 502k, False: 9]
  |  Branch (50:28): [True: 134k, False: 367k]
  |  Branch (50:44): [True: 0, False: 367k]
  |  Branch (50:62): [True: 112k, False: 255k]
  ------------------
   51|   246k|        ++in;
   52|   246k|    }
   53|   255k|    return in;
   54|   255k|}
_ZN10ODDLParser12getNextTokenIcEEPT_S2_S2_:
   62|    135|inline T *getNextToken(T *in, T *end) {
   63|    135|    T *tmp(in);
   64|    135|    in = lookForNextToken(in, end);
   65|    135|    if (tmp == in) {
  ------------------
  |  Branch (65:9): [True: 0, False: 135]
  ------------------
   66|      0|        ++in;
   67|      0|    }
   68|    135|    return in;
   69|    135|}

_ZN10ODDLParser11hex2DecimalEc:
  450|    158|inline int hex2Decimal(char in) {
  451|    158|    if (isNumeric(in)) {
  ------------------
  |  Branch (451:9): [True: 50, False: 108]
  ------------------
  452|     50|        return (in - 48);
  453|     50|    }
  454|       |
  455|    108|    char hexCodeLower('a'), hexCodeUpper('A');
  456|  1.78k|    for (int i = 0; i < 16; i++) {
  ------------------
  |  Branch (456:21): [True: 1.68k, False: 104]
  ------------------
  457|  1.68k|        if (in == hexCodeLower + i || in == hexCodeUpper + i) {
  ------------------
  |  Branch (457:13): [True: 4, False: 1.67k]
  |  Branch (457:39): [True: 0, False: 1.67k]
  ------------------
  458|      4|            return (i + 10);
  459|      4|        }
  460|  1.68k|    }
  461|       |
  462|    104|    return ErrorHex2Decimal;
  463|    108|}
_ZN10ODDLParser9isNumericIcEEbT_:
  322|   132k|inline bool isNumeric(const T in) {
  323|   132k|    if (static_cast<size_t>(in) >= CharTableSize) {
  ------------------
  |  Branch (323:9): [True: 444, False: 132k]
  ------------------
  324|    444|        return '\0';
  325|    444|    }
  326|       |
  327|   132k|    size_t idx = static_cast<size_t>(in);
  328|   132k|    return idx < sizeof(chartype_table) && (chartype_table[idx] == 1);
  ------------------
  |  Branch (328:12): [True: 132k, False: 0]
  |  Branch (328:44): [True: 103k, False: 28.1k]
  ------------------
  329|   132k|}
_ZN10ODDLParser11isCharacterIcEEbT_:
  398|    688|inline bool isCharacter(const T in) {
  399|    688|    return ((in >= 'a' && in <= 'z') || (in >= 'A' && in <= 'Z'));
  ------------------
  |  Branch (399:14): [True: 508, False: 180]
  |  Branch (399:27): [True: 6, False: 502]
  |  Branch (399:42): [True: 678, False: 4]
  |  Branch (399:55): [True: 176, False: 502]
  ------------------
  400|    688|}
_ZN10ODDLParser16isCommentOpenTagIcEEbPT_S2_:
  484|  2.12M|inline bool isCommentOpenTag(T *in, T *end) {
  485|  2.12M|    if (*in == '/') {
  ------------------
  |  Branch (485:9): [True: 1.39k, False: 2.12M]
  ------------------
  486|  1.39k|        if (in + 1 != end) {
  ------------------
  |  Branch (486:13): [True: 1.39k, False: 0]
  ------------------
  487|  1.39k|            if (*(in + 1) == '*') {
  ------------------
  |  Branch (487:17): [True: 6, False: 1.38k]
  ------------------
  488|      6|                return true;
  489|      6|            }
  490|  1.39k|        }
  491|  1.39k|    }
  492|       |
  493|  2.12M|    return false;
  494|  2.12M|}
_ZN10ODDLParser17isCommentCloseTagIcEEbPT_S2_:
  497|   617k|inline bool isCommentCloseTag(T *in, T *end) {
  498|   617k|    if (*in == '*') {
  ------------------
  |  Branch (498:9): [True: 1.24k, False: 616k]
  ------------------
  499|  1.24k|        if (in + 1 != end) {
  ------------------
  |  Branch (499:13): [True: 1.24k, False: 0]
  ------------------
  500|  1.24k|            if (*(in + 1) == '/') {
  ------------------
  |  Branch (500:17): [True: 3, False: 1.24k]
  ------------------
  501|      3|                return true;
  502|      3|            }
  503|  1.24k|        }
  504|  1.24k|    }
  505|       |
  506|   617k|    return false;
  507|   617k|}
_ZN10ODDLParser9isCommentIcEEbPT_S2_:
  466|  2.13M|inline bool isComment(T *in, T *end) {
  467|  2.13M|    if (*in == '/') {
  ------------------
  |  Branch (467:9): [True: 1.44k, False: 2.13M]
  ------------------
  468|  1.44k|        if (in + 1 != end) {
  ------------------
  |  Branch (468:13): [True: 1.44k, False: 0]
  ------------------
  469|  1.44k|            if (*(in + 1) == '/') {
  ------------------
  |  Branch (469:17): [True: 122, False: 1.32k]
  ------------------
  470|    122|                char *drive((in + 2));
  471|    122|                if ((isUpperCase<T>(*drive) || isLowerCase<T>(*drive)) && *(drive + 1) == '/') {
  ------------------
  |  Branch (471:22): [True: 0, False: 122]
  |  Branch (471:48): [True: 0, False: 122]
  |  Branch (471:75): [True: 0, False: 0]
  ------------------
  472|      0|                    return false;
  473|    122|                } else {
  474|    122|                    return true;
  475|    122|                }
  476|    122|            }
  477|  1.44k|        }
  478|  1.44k|    }
  479|       |
  480|  2.13M|    return false;
  481|  2.13M|}
_ZN10ODDLParser11isUpperCaseIcEEbT_:
   30|    122|inline bool isUpperCase(T in) {
   31|    122|    return (in >= 'A' && in <= 'Z');
  ------------------
  |  Branch (31:13): [True: 0, False: 122]
  |  Branch (31:26): [True: 0, False: 0]
  ------------------
   32|    122|}
_ZN10ODDLParser11isLowerCaseIcEEbT_:
   35|    122|inline bool isLowerCase(T in) {
   36|    122|    return (in >= 'a' && in <= 'z');
  ------------------
  |  Branch (36:13): [True: 0, False: 122]
  |  Branch (36:26): [True: 0, False: 0]
  ------------------
   37|    122|}
_ZN10ODDLParser9isNewLineIcEEbT_:
   45|  2.50M|inline bool isNewLine(const T in) {
   46|  2.50M|    return ('\n' == in || ('\r' == in));
  ------------------
  |  Branch (46:13): [True: 6.16k, False: 2.49M]
  |  Branch (46:27): [True: 266, False: 2.49M]
  ------------------
   47|  2.50M|}
_ZN10ODDLParser11isEndofLineIcEEbT_:
  436|    421|inline bool isEndofLine(const T in) {
  437|    421|    return ('\n' == in);
  438|    421|}
_ZN10ODDLParser9isNumericIKcEEbT_:
  322|    771|inline bool isNumeric(const T in) {
  323|    771|    if (static_cast<size_t>(in) >= CharTableSize) {
  ------------------
  |  Branch (323:9): [True: 16, False: 755]
  ------------------
  324|     16|        return '\0';
  325|     16|    }
  326|       |
  327|    755|    size_t idx = static_cast<size_t>(in);
  328|    755|    return idx < sizeof(chartype_table) && (chartype_table[idx] == 1);
  ------------------
  |  Branch (328:12): [True: 755, False: 0]
  |  Branch (328:44): [True: 0, False: 755]
  ------------------
  329|    771|}
_ZN10ODDLParser11isSeparatorIcEEbT_:
   50|  1.71M|inline bool isSeparator(T in) {
   51|  1.71M|    if (isSpace(in) || ',' == in || '{' == in || '}' == in || '[' == in || '(' == in || ')' == in) {
  ------------------
  |  Branch (51:9): [True: 2.99k, False: 1.71M]
  |  Branch (51:24): [True: 179k, False: 1.53M]
  |  Branch (51:37): [True: 165, False: 1.53M]
  |  Branch (51:50): [True: 45.1k, False: 1.49M]
  |  Branch (51:63): [True: 0, False: 1.49M]
  |  Branch (51:76): [True: 4, False: 1.49M]
  |  Branch (51:89): [True: 18, False: 1.49M]
  ------------------
   52|   227k|        return true;
   53|   227k|    }
   54|  1.49M|    return false;
   55|  1.71M|}
OpenDDLParser.cpp:_ZN10ODDLParserL16getNextSeparatorIcEEPT_S2_S2_:
  441|   113k|inline static T *getNextSeparator(T *in, T *end) {
  442|   113k|    while (in != end && !isSeparator(*in)) {
  ------------------
  |  Branch (442:12): [True: 113k, False: 3]
  |  Branch (442:25): [True: 15, False: 113k]
  ------------------
  443|     15|        ++in;
  444|     15|    }
  445|   113k|    return in;
  446|   113k|}
_ZN10ODDLParser12isHexLiteralIcEEbPT_S2_:
  408|  92.5k|inline bool isHexLiteral(T *in, T *end) {
  409|  92.5k|    if (*in == '0') {
  ------------------
  |  Branch (409:9): [True: 36.9k, False: 55.5k]
  ------------------
  410|  36.9k|        if (in + 1 != end) {
  ------------------
  |  Branch (410:13): [True: 36.9k, False: 0]
  ------------------
  411|  36.9k|            if (*(in + 1) == 'x' || *(in + 1) == 'X') {
  ------------------
  |  Branch (411:17): [True: 2, False: 36.9k]
  |  Branch (411:37): [True: 0, False: 36.9k]
  ------------------
  412|      2|                return true;
  413|      2|            }
  414|  36.9k|        }
  415|  36.9k|    }
  416|       |
  417|  92.5k|    return false;
  418|  92.5k|}
_ZN10ODDLParser9isIntegerIcEEbPT_S2_:
  337|    135|inline bool isInteger(T *in, T *end) {
  338|    135|    if (in != end) {
  ------------------
  |  Branch (338:9): [True: 135, False: 0]
  ------------------
  339|    135|        if (*in == '-') {
  ------------------
  |  Branch (339:13): [True: 0, False: 135]
  ------------------
  340|      0|            ++in;
  341|      0|        }
  342|    135|    }
  343|       |
  344|    135|    bool result(false);
  345|    143|    while (isNotEndOfToken(in, end)) {
  ------------------
  |  Branch (345:12): [True: 135, False: 8]
  ------------------
  346|    135|        result = isNumeric(*in);
  347|    135|        if (!result) {
  ------------------
  |  Branch (347:13): [True: 127, False: 8]
  ------------------
  348|    127|            break;
  349|    127|        }
  350|      8|        ++in;
  351|      8|    }
  352|       |
  353|    135|    return result;
  354|    135|}
_ZN10ODDLParser15isNotEndOfTokenIcEEbPT_S2_:
  332|    270|inline bool isNotEndOfToken(T *in, T *end) {
  333|    270|    return ('}' != *in && ',' != *in && !isSpace(*in) && ')' != *in && in != end);
  ------------------
  |  Branch (333:13): [True: 270, False: 0]
  |  Branch (333:27): [True: 270, False: 0]
  |  Branch (333:41): [True: 270, False: 0]
  |  Branch (333:58): [True: 262, False: 8]
  |  Branch (333:72): [True: 262, False: 0]
  ------------------
  334|    270|}
_ZN10ODDLParser7isFloatIcEEbPT_S2_:
  357|    127|inline bool isFloat(T *in, T *end) {
  358|    127|    if (in != end) {
  ------------------
  |  Branch (358:9): [True: 127, False: 0]
  ------------------
  359|    127|        if (*in == '-') {
  ------------------
  |  Branch (359:13): [True: 0, False: 127]
  ------------------
  360|      0|            ++in;
  361|      0|        }
  362|    127|    }
  363|       |
  364|       |    // check for <1>.0f
  365|    127|    bool result(false);
  366|    127|    while (isNotEndOfToken(in, end)) {
  ------------------
  |  Branch (366:12): [True: 127, False: 0]
  ------------------
  367|    127|        if (*in == '.') {
  ------------------
  |  Branch (367:13): [True: 0, False: 127]
  ------------------
  368|      0|            result = true;
  369|      0|            break;
  370|      0|        }
  371|    127|        result = isNumeric(*in);
  372|    127|        if (!result) {
  ------------------
  |  Branch (372:13): [True: 127, False: 0]
  ------------------
  373|    127|            return false;
  374|    127|        }
  375|      0|        ++in;
  376|      0|    }
  377|       |
  378|       |    // check for 1<.>0f
  379|      0|    if (*in == '.') {
  ------------------
  |  Branch (379:9): [True: 0, False: 0]
  ------------------
  380|      0|        ++in;
  381|      0|    } else {
  382|      0|        return false;
  383|      0|    }
  384|       |
  385|       |    // check for 1.<0>f
  386|      0|    while (isNotEndOfToken(in, end)) {
  ------------------
  |  Branch (386:12): [True: 0, False: 0]
  ------------------
  387|      0|        result = isNumeric(*in);
  388|      0|        if (!result) {
  ------------------
  |  Branch (388:13): [True: 0, False: 0]
  ------------------
  389|      0|            return false;
  390|      0|        }
  391|      0|        ++in;
  392|      0|    }
  393|       |
  394|      0|    return result;
  395|      0|}
_ZN10ODDLParser15isStringLiteralIcEEbT_:
  403|    127|inline bool isStringLiteral(const T in) {
  404|    127|    return (in == '\"');
  405|    127|}
_ZN10ODDLParser7isSpaceIcEEbT_:
   40|  2.22M|inline bool isSpace(const T in) {
   41|  2.22M|    return (' ' == in || '\t' == in);
  ------------------
  |  Branch (41:13): [True: 105k, False: 2.11M]
  |  Branch (41:26): [True: 33.6k, False: 2.08M]
  ------------------
   42|  2.22M|}

_ZN4pugi13xml_attributeC2Ev:
 5234|  4.74k|	PUGI_IMPL_FN xml_attribute::xml_attribute(): _attr(nullptr)
 5235|  4.74k|	{
 5236|  4.74k|	}
_ZN4pugi13xml_attributeC2EPNS_20xml_attribute_structE:
 5238|  34.0k|	PUGI_IMPL_FN xml_attribute::xml_attribute(xml_attribute_struct* attr): _attr(attr)
 5239|  34.0k|	{
 5240|  34.0k|	}
_ZNK4pugi13xml_attributecvPFvPPPS0_EEv:
 5247|    923|	{
 5248|    923|		return _attr ? unspecified_bool_xml_attribute : nullptr;
  ------------------
  |  Branch (5248:10): [True: 155, False: 768]
  ------------------
 5249|    923|	}
_ZNK4pugi13xml_attribute9as_stringEPKc:
 5300|  16.5k|	{
 5301|  16.5k|		if (!_attr) return def;
  ------------------
  |  Branch (5301:7): [True: 28, False: 16.4k]
  ------------------
 5302|  16.4k|		const char_t* value = _attr->value;
 5303|  16.4k|		return value ? value : def;
  ------------------
  |  Branch (5303:10): [True: 16.4k, False: 0]
  ------------------
 5304|  16.5k|	}
_ZNK4pugi13xml_attribute6as_intEi:
 5307|  1.72k|	{
 5308|  1.72k|		if (!_attr) return def;
  ------------------
  |  Branch (5308:7): [True: 0, False: 1.72k]
  ------------------
 5309|  1.72k|		const char_t* value = _attr->value;
 5310|  1.72k|		return value ? impl::get_value_int(value) : def;
  ------------------
  |  Branch (5310:10): [True: 1.72k, False: 0]
  ------------------
 5311|  1.72k|	}
_ZNK4pugi13xml_attribute7as_uintEj:
 5314|  3.84k|	{
 5315|  3.84k|		if (!_attr) return def;
  ------------------
  |  Branch (5315:7): [True: 0, False: 3.84k]
  ------------------
 5316|  3.84k|		const char_t* value = _attr->value;
 5317|  3.84k|		return value ? impl::get_value_uint(value) : def;
  ------------------
  |  Branch (5317:10): [True: 3.84k, False: 0]
  ------------------
 5318|  3.84k|	}
_ZNK4pugi13xml_attribute5emptyEv:
 5358|  35.6k|	{
 5359|  35.6k|		return !_attr;
 5360|  35.6k|	}
_ZNK4pugi13xml_attribute4nameEv:
 5363|  3.61k|	{
 5364|  3.61k|		if (!_attr) return PUGIXML_TEXT("");
  ------------------
  |  |  144|      0|#	define PUGIXML_TEXT(t) t
  ------------------
  |  Branch (5364:7): [True: 0, False: 3.61k]
  ------------------
 5365|  3.61k|		const char_t* name = _attr->name;
 5366|  3.61k|		return name ? name : PUGIXML_TEXT("");
  ------------------
  |  |  144|  3.61k|#	define PUGIXML_TEXT(t) t
  ------------------
  |  Branch (5366:10): [True: 3.61k, False: 0]
  ------------------
 5367|  3.61k|	}
_ZNK4pugi13xml_attribute5valueEv:
 5370|  2.71k|	{
 5371|  2.71k|		if (!_attr) return PUGIXML_TEXT("");
  ------------------
  |  |  144|      0|#	define PUGIXML_TEXT(t) t
  ------------------
  |  Branch (5371:7): [True: 0, False: 2.71k]
  ------------------
 5372|  2.71k|		const char_t* value = _attr->value;
 5373|  2.71k|		return value ? value : PUGIXML_TEXT("");
  ------------------
  |  |  144|  2.71k|#	define PUGIXML_TEXT(t) t
  ------------------
  |  Branch (5373:10): [True: 2.71k, False: 0]
  ------------------
 5374|  2.71k|	}
_ZN4pugi8xml_nodeC2Ev:
 5593|  5.36k|	PUGI_IMPL_FN xml_node::xml_node(): _root(nullptr)
 5594|  5.36k|	{
 5595|  5.36k|	}
_ZN4pugi8xml_nodeC2EPNS_15xml_node_structE:
 5597|   290k|	PUGI_IMPL_FN xml_node::xml_node(xml_node_struct* p): _root(p)
 5598|   290k|	{
 5599|   290k|	}
_ZNK4pugi8xml_nodecvPFvPPPS0_EEv:
 5606|    359|	{
 5607|    359|		return _root ? unspecified_bool_xml_node : nullptr;
  ------------------
  |  Branch (5607:10): [True: 163, False: 196]
  ------------------
 5608|    359|	}
_ZNK4pugi8xml_nodentEv:
 5611|     20|	{
 5612|     20|		return !_root;
 5613|     20|	}
_ZNK4pugi8xml_node5beginEv:
 5616|  71.4k|	{
 5617|  71.4k|		return iterator(_root ? _root->first_child + 0 : nullptr, _root);
  ------------------
  |  Branch (5617:19): [True: 71.4k, False: 0]
  ------------------
 5618|  71.4k|	}
_ZNK4pugi8xml_node3endEv:
 5621|  71.4k|	{
 5622|  71.4k|		return iterator(nullptr, _root);
 5623|  71.4k|	}
_ZNK4pugi8xml_node16attributes_beginEv:
 5626|  1.20k|	{
 5627|  1.20k|		return attribute_iterator(_root ? _root->first_attribute + 0 : nullptr, _root);
  ------------------
  |  Branch (5627:29): [True: 1.20k, False: 0]
  ------------------
 5628|  1.20k|	}
_ZNK4pugi8xml_node14attributes_endEv:
 5631|  1.20k|	{
 5632|  1.20k|		return attribute_iterator(nullptr, _root);
 5633|  1.20k|	}
_ZNK4pugi8xml_node8childrenEv:
 5636|  71.4k|	{
 5637|  71.4k|		return xml_object_range<xml_node_iterator>(begin(), end());
 5638|  71.4k|	}
_ZNK4pugi8xml_node10attributesEv:
 5646|  1.20k|	{
 5647|  1.20k|		return xml_object_range<xml_attribute_iterator>(attributes_begin(), attributes_end());
 5648|  1.20k|	}
_ZNK4pugi8xml_nodeneERKS0_:
 5656|  69.2k|	{
 5657|  69.2k|		return (_root != r._root);
 5658|  69.2k|	}
_ZNK4pugi8xml_node5emptyEv:
 5681|  25.2k|	{
 5682|  25.2k|		return !_root;
 5683|  25.2k|	}
_ZNK4pugi8xml_node4nameEv:
 5686|  47.9k|	{
 5687|  47.9k|		if (!_root) return PUGIXML_TEXT("");
  ------------------
  |  |  144|      0|#	define PUGIXML_TEXT(t) t
  ------------------
  |  Branch (5687:7): [True: 0, False: 47.9k]
  ------------------
 5688|  47.9k|		const char_t* name = _root->name;
 5689|  47.9k|		return name ? name : PUGIXML_TEXT("");
  ------------------
  |  |  144|  48.0k|#	define PUGIXML_TEXT(t) t
  ------------------
  |  Branch (5689:10): [True: 47.8k, False: 93]
  ------------------
 5690|  47.9k|	}
_ZNK4pugi8xml_node4typeEv:
 5693|  65.9k|	{
 5694|  65.9k|		return _root ? PUGI_IMPL_NODETYPE(_root) : node_null;
  ------------------
  |  |  492|  65.9k|	#define PUGI_IMPL_NODETYPE(n) static_cast<xml_node_type>((n)->header & impl::xml_memory_page_type_mask)
  ------------------
  |  Branch (5694:10): [True: 65.9k, False: 0]
  ------------------
 5695|  65.9k|	}
_ZNK4pugi8xml_node5childEPKc:
 5705|  1.95k|	{
 5706|  1.95k|		if (!_root) return xml_node();
  ------------------
  |  Branch (5706:7): [True: 0, False: 1.95k]
  ------------------
 5707|       |
 5708|  2.12k|		for (xml_node_struct* i = _root->first_child; i; i = i->next_sibling)
  ------------------
  |  Branch (5708:49): [True: 2.12k, False: 0]
  ------------------
 5709|  2.12k|		{
 5710|  2.12k|			const char_t* iname = i->name;
 5711|  2.12k|			if (iname && impl::strequal(name_, iname))
  ------------------
  |  Branch (5711:8): [True: 2.12k, False: 0]
  |  Branch (5711:17): [True: 1.95k, False: 167]
  ------------------
 5712|  1.95k|				return xml_node(i);
 5713|  2.12k|		}
 5714|       |
 5715|      0|		return xml_node();
 5716|  1.95k|	}
_ZNK4pugi8xml_node9attributeEPKc:
 5719|  36.4k|	{
 5720|  36.4k|		if (!_root) return xml_attribute();
  ------------------
  |  Branch (5720:7): [True: 0, False: 36.4k]
  ------------------
 5721|       |
 5722|  63.0k|		for (xml_attribute_struct* i = _root->first_attribute; i; i = i->next_attribute)
  ------------------
  |  Branch (5722:58): [True: 58.2k, False: 4.74k]
  ------------------
 5723|  58.2k|		{
 5724|  58.2k|			const char_t* iname = i->name;
 5725|  58.2k|			if (iname && impl::strequal(name_, iname))
  ------------------
  |  Branch (5725:8): [True: 58.2k, False: 0]
  |  Branch (5725:17): [True: 31.6k, False: 26.5k]
  ------------------
 5726|  31.6k|				return xml_attribute(i);
 5727|  58.2k|		}
 5728|       |
 5729|  4.74k|		return xml_attribute();
 5730|  36.4k|	}
_ZNK4pugi8xml_node12next_siblingEPKc:
 5733|     21|	{
 5734|     21|		if (!_root) return xml_node();
  ------------------
  |  Branch (5734:7): [True: 0, False: 21]
  ------------------
 5735|       |
 5736|     63|		for (xml_node_struct* i = _root->next_sibling; i; i = i->next_sibling)
  ------------------
  |  Branch (5736:50): [True: 42, False: 21]
  ------------------
 5737|     42|		{
 5738|     42|			const char_t* iname = i->name;
 5739|     42|			if (iname && impl::strequal(name_, iname))
  ------------------
  |  Branch (5739:8): [True: 42, False: 0]
  |  Branch (5739:17): [True: 0, False: 42]
  ------------------
 5740|      0|				return xml_node(i);
 5741|     42|		}
 5742|       |
 5743|     21|		return xml_node();
 5744|     21|	}
_ZNK4pugi8xml_node12next_siblingEv:
 5747|     60|	{
 5748|     60|		return _root ? xml_node(_root->next_sibling) : xml_node();
  ------------------
  |  Branch (5748:10): [True: 60, False: 0]
  ------------------
 5749|     60|	}
_ZNK4pugi8xml_node4rootEv:
 5916|     48|	{
 5917|     48|		return _root ? xml_node(&impl::get_document(_root)) : xml_node();
  ------------------
  |  Branch (5917:10): [True: 48, False: 0]
  ------------------
 5918|     48|	}
_ZNK4pugi8xml_node4textEv:
 5921|  11.3k|	{
 5922|  11.3k|		return xml_text(_root);
 5923|  11.3k|	}
_ZNK4pugi8xml_node11first_childEv:
 5962|    158|	{
 5963|    158|		if (!_root) return xml_node();
  ------------------
  |  Branch (5963:7): [True: 0, False: 158]
  ------------------
 5964|    158|		return xml_node(_root->first_child);
 5965|    158|	}
_ZN4pugi8xml_textC2EPNS_15xml_node_structE:
 6913|  11.3k|	PUGI_IMPL_FN xml_text::xml_text(xml_node_struct* root): _root(root)
 6914|  11.3k|	{
 6915|  11.3k|	}
_ZNK4pugi8xml_text5_dataEv:
 6918|  11.3k|	{
 6919|  11.3k|		if (!_root || impl::is_text_node(_root)) return _root;
  ------------------
  |  Branch (6919:7): [True: 0, False: 11.3k]
  |  Branch (6919:17): [True: 0, False: 11.3k]
  ------------------
 6920|       |
 6921|       |		// element nodes can have value if parse_embed_pcdata was used
 6922|  11.3k|		if (PUGI_IMPL_NODETYPE(_root) == node_element && _root->value)
  ------------------
  |  |  492|  11.3k|	#define PUGI_IMPL_NODETYPE(n) static_cast<xml_node_type>((n)->header & impl::xml_memory_page_type_mask)
  ------------------
  |  Branch (6922:7): [True: 11.3k, False: 0]
  |  Branch (6922:52): [True: 0, False: 11.3k]
  ------------------
 6923|      0|			return _root;
 6924|       |
 6925|  11.3k|		for (xml_node_struct* node = _root->first_child; node; node = node->next_sibling)
  ------------------
  |  Branch (6925:52): [True: 11.2k, False: 71]
  ------------------
 6926|  11.2k|			if (impl::is_text_node(node))
  ------------------
  |  Branch (6926:8): [True: 11.2k, False: 0]
  ------------------
 6927|  11.2k|				return node;
 6928|       |
 6929|     71|		return nullptr;
 6930|  11.3k|	}
_ZNK4pugi8xml_text3getEv:
 6964|     41|	{
 6965|     41|		xml_node_struct* d = _data();
 6966|     41|		if (!d) return PUGIXML_TEXT("");
  ------------------
  |  |  144|      0|#	define PUGIXML_TEXT(t) t
  ------------------
  |  Branch (6966:7): [True: 0, False: 41]
  ------------------
 6967|     41|		const char_t* value = d->value;
 6968|     41|		return value ? value : PUGIXML_TEXT("");
  ------------------
  |  |  144|     41|#	define PUGIXML_TEXT(t) t
  ------------------
  |  Branch (6968:10): [True: 41, False: 0]
  ------------------
 6969|     41|	}
_ZNK4pugi8xml_text9as_stringEPKc:
 6972|  11.1k|	{
 6973|  11.1k|		xml_node_struct* d = _data();
 6974|  11.1k|		if (!d) return def;
  ------------------
  |  Branch (6974:7): [True: 71, False: 11.0k]
  ------------------
 6975|  11.0k|		const char_t* value = d->value;
 6976|  11.0k|		return value ? value : def;
  ------------------
  |  Branch (6976:10): [True: 11.0k, False: 0]
  ------------------
 6977|  11.1k|	}
_ZNK4pugi8xml_text8as_floatEf:
 7004|    169|	{
 7005|    169|		xml_node_struct* d = _data();
 7006|    169|		if (!d) return def;
  ------------------
  |  Branch (7006:7): [True: 0, False: 169]
  ------------------
 7007|    169|		const char_t* value = d->value;
 7008|    169|		return value ? impl::get_value_float(value) : def;
  ------------------
  |  Branch (7008:10): [True: 169, False: 0]
  ------------------
 7009|    169|	}
_ZNK4pugi8xml_text7as_boolEb:
 7012|     18|	{
 7013|     18|		xml_node_struct* d = _data();
 7014|     18|		if (!d) return def;
  ------------------
  |  Branch (7014:7): [True: 0, False: 18]
  ------------------
 7015|     18|		const char_t* value = d->value;
 7016|     18|		return value ? impl::get_value_bool(value) : def;
  ------------------
  |  Branch (7016:10): [True: 18, False: 0]
  ------------------
 7017|     18|	}
_ZN4pugi17xml_node_iteratorC2EPNS_15xml_node_structES2_:
 7234|   142k|	PUGI_IMPL_FN xml_node_iterator::xml_node_iterator(xml_node_struct* ref, xml_node_struct* parent): _wrap(ref), _parent(parent)
 7235|   142k|	{
 7236|   142k|	}
_ZNK4pugi17xml_node_iteratorneERKS0_:
 7244|   145k|	{
 7245|   145k|		return _wrap._root != rhs._wrap._root || _parent._root != rhs._parent._root;
  ------------------
  |  Branch (7245:10): [True: 73.9k, False: 71.4k]
  |  Branch (7245:44): [True: 0, False: 71.4k]
  ------------------
 7246|   145k|	}
_ZNK4pugi17xml_node_iteratordeEv:
 7249|  73.9k|	{
 7250|  73.9k|		assert(_wrap._root);
  ------------------
  |  Branch (7250:3): [True: 73.9k, False: 0]
  ------------------
 7251|  73.9k|		return _wrap;
 7252|  73.9k|	}
_ZN4pugi17xml_node_iteratorppEv:
 7261|  73.9k|	{
 7262|  73.9k|		assert(_wrap._root);
  ------------------
  |  Branch (7262:3): [True: 73.9k, False: 0]
  ------------------
 7263|  73.9k|		_wrap._root = _wrap._root->next_sibling;
 7264|  73.9k|		return *this;
 7265|  73.9k|	}
_ZN4pugi22xml_attribute_iteratorC2EPNS_20xml_attribute_structEPNS_15xml_node_structE:
 7295|  2.41k|	PUGI_IMPL_FN xml_attribute_iterator::xml_attribute_iterator(xml_attribute_struct* ref, xml_node_struct* parent): _wrap(ref), _parent(parent)
 7296|  2.41k|	{
 7297|  2.41k|	}
_ZNK4pugi22xml_attribute_iteratorneERKS0_:
 7305|  3.61k|	{
 7306|  3.61k|		return _wrap._attr != rhs._wrap._attr || _parent._root != rhs._parent._root;
  ------------------
  |  Branch (7306:10): [True: 2.41k, False: 1.20k]
  |  Branch (7306:44): [True: 0, False: 1.20k]
  ------------------
 7307|  3.61k|	}
_ZNK4pugi22xml_attribute_iteratordeEv:
 7310|  2.41k|	{
 7311|  2.41k|		assert(_wrap._attr);
  ------------------
  |  Branch (7311:3): [True: 2.41k, False: 0]
  ------------------
 7312|  2.41k|		return _wrap;
 7313|  2.41k|	}
_ZN4pugi22xml_attribute_iteratorppEv:
 7322|  2.41k|	{
 7323|  2.41k|		assert(_wrap._attr);
  ------------------
  |  Branch (7323:3): [True: 2.41k, False: 0]
  ------------------
 7324|  2.41k|		_wrap._attr = _wrap._attr->next_attribute;
 7325|  2.41k|		return *this;
 7326|  2.41k|	}
_ZN4pugi16xml_parse_resultC2Ev:
 7418|     61|	PUGI_IMPL_FN xml_parse_result::xml_parse_result(): status(status_internal_error), offset(0), encoding(encoding_auto)
 7419|     61|	{
 7420|     61|	}
_ZNK4pugi16xml_parse_resultcvbEv:
 7423|     60|	{
 7424|     60|		return status == status_ok;
 7425|     60|	}
_ZNK4pugi16xml_parse_result11descriptionEv:
 7428|     12|	{
 7429|     12|		switch (status)
 7430|     12|		{
 7431|      0|		case status_ok: return "No error";
  ------------------
  |  Branch (7431:3): [True: 0, False: 12]
  ------------------
 7432|       |
 7433|      0|		case status_file_not_found: return "File was not found";
  ------------------
  |  Branch (7433:3): [True: 0, False: 12]
  ------------------
 7434|      0|		case status_io_error: return "Error reading from file/stream";
  ------------------
  |  Branch (7434:3): [True: 0, False: 12]
  ------------------
 7435|      0|		case status_out_of_memory: return "Could not allocate memory";
  ------------------
  |  Branch (7435:3): [True: 0, False: 12]
  ------------------
 7436|      0|		case status_internal_error: return "Internal error occurred";
  ------------------
  |  Branch (7436:3): [True: 0, False: 12]
  ------------------
 7437|       |
 7438|      0|		case status_unrecognized_tag: return "Could not determine tag type";
  ------------------
  |  Branch (7438:3): [True: 0, False: 12]
  ------------------
 7439|       |
 7440|      0|		case status_bad_pi: return "Error parsing document declaration/processing instruction";
  ------------------
  |  Branch (7440:3): [True: 0, False: 12]
  ------------------
 7441|      0|		case status_bad_comment: return "Error parsing comment";
  ------------------
  |  Branch (7441:3): [True: 0, False: 12]
  ------------------
 7442|      0|		case status_bad_cdata: return "Error parsing CDATA section";
  ------------------
  |  Branch (7442:3): [True: 0, False: 12]
  ------------------
 7443|      0|		case status_bad_doctype: return "Error parsing document type declaration";
  ------------------
  |  Branch (7443:3): [True: 0, False: 12]
  ------------------
 7444|      0|		case status_bad_pcdata: return "Error parsing PCDATA section";
  ------------------
  |  Branch (7444:3): [True: 0, False: 12]
  ------------------
 7445|      2|		case status_bad_start_element: return "Error parsing start element tag";
  ------------------
  |  Branch (7445:3): [True: 2, False: 10]
  ------------------
 7446|      4|		case status_bad_attribute: return "Error parsing element attribute";
  ------------------
  |  Branch (7446:3): [True: 4, False: 8]
  ------------------
 7447|      0|		case status_bad_end_element: return "Error parsing end element tag";
  ------------------
  |  Branch (7447:3): [True: 0, False: 12]
  ------------------
 7448|      5|		case status_end_element_mismatch: return "Start-end tags mismatch";
  ------------------
  |  Branch (7448:3): [True: 5, False: 7]
  ------------------
 7449|       |
 7450|      0|		case status_append_invalid_root: return "Unable to append nodes: root is not an element or document";
  ------------------
  |  Branch (7450:3): [True: 0, False: 12]
  ------------------
 7451|       |
 7452|      1|		case status_no_document_element: return "No document element found";
  ------------------
  |  Branch (7452:3): [True: 1, False: 11]
  ------------------
 7453|       |
 7454|      0|		default: return "Unknown error";
  ------------------
  |  Branch (7454:3): [True: 0, False: 12]
  ------------------
 7455|     12|		}
 7456|     12|	}
_ZN4pugi12xml_documentC2Ev:
 7458|     60|	PUGI_IMPL_FN xml_document::xml_document(): _buffer(nullptr)
 7459|     60|	{
 7460|     60|		_create();
 7461|     60|	}
_ZN4pugi12xml_documentD2Ev:
 7464|     60|	{
 7465|     60|		_destroy();
 7466|     60|	}
_ZN4pugi12xml_document5resetEv:
 7488|     60|	{
 7489|     60|		_destroy();
 7490|     60|		_create();
 7491|     60|	}
_ZN4pugi12xml_document7_createEv:
 7501|    120|	{
 7502|    120|		assert(!_root);
  ------------------
  |  Branch (7502:3): [True: 120, False: 0]
  ------------------
 7503|       |
 7504|       |	#ifdef PUGIXML_COMPACT
 7505|       |		// space for page marker for the first page (uint32_t), rounded up to pointer size; assumes pointers are at least 32-bit
 7506|       |		const size_t page_offset = sizeof(void*);
 7507|       |	#else
 7508|    120|		const size_t page_offset = 0;
 7509|    120|	#endif
 7510|       |
 7511|       |		// initialize sentinel page
 7512|    120|		PUGI_IMPL_STATIC_ASSERT(sizeof(impl::xml_memory_page) + sizeof(impl::xml_document_struct) + page_offset <= sizeof(_memory));
  ------------------
  |  |  110|    120|#define PUGI_IMPL_STATIC_ASSERT(cond) { static const char condition_failed[(cond) ? 1 : -1] = {0}; (void)condition_failed[0]; }
  ------------------
 7513|       |
 7514|       |		// prepare page structure
 7515|    120|		impl::xml_memory_page* page = impl::xml_memory_page::construct(_memory);
 7516|    120|		assert(page);
  ------------------
  |  Branch (7516:3): [True: 120, False: 0]
  ------------------
 7517|       |
 7518|    120|		page->busy_size = impl::xml_memory_page_size;
 7519|       |
 7520|       |		// setup first page marker
 7521|       |	#ifdef PUGIXML_COMPACT
 7522|       |		// round-trip through void* to avoid 'cast increases required alignment of target type' warning
 7523|       |		page->compact_page_marker = reinterpret_cast<uint32_t*>(static_cast<void*>(reinterpret_cast<char*>(page) + sizeof(impl::xml_memory_page)));
 7524|       |		*page->compact_page_marker = sizeof(impl::xml_memory_page);
 7525|       |	#endif
 7526|       |
 7527|       |		// allocate new root
 7528|    120|		_root = new (reinterpret_cast<char*>(page) + sizeof(impl::xml_memory_page) + page_offset) impl::xml_document_struct(page);
 7529|    120|		_root->prev_sibling_c = _root;
 7530|       |
 7531|       |		// setup sentinel page
 7532|    120|		page->allocator = static_cast<impl::xml_document_struct*>(_root);
 7533|       |
 7534|       |		// setup hash table pointer in allocator
 7535|       |	#ifdef PUGIXML_COMPACT
 7536|       |		page->allocator->_hash = &static_cast<impl::xml_document_struct*>(_root)->hash;
 7537|       |	#endif
 7538|       |
 7539|       |		// verify the document allocation
 7540|       |		assert(reinterpret_cast<char*>(_root) + sizeof(impl::xml_document_struct) <= _memory + sizeof(_memory));
  ------------------
  |  Branch (7540:3): [True: 120, False: 0]
  ------------------
 7541|    120|	}
_ZN4pugi12xml_document8_destroyEv:
 7544|    120|	{
 7545|    120|		assert(_root);
  ------------------
  |  Branch (7545:3): [True: 120, False: 0]
  ------------------
 7546|       |
 7547|       |		// destroy static storage
 7548|    120|		if (_buffer)
  ------------------
  |  Branch (7548:7): [True: 60, False: 60]
  ------------------
 7549|     60|		{
 7550|     60|			impl::xml_memory::deallocate(_buffer);
 7551|     60|			_buffer = nullptr;
 7552|     60|		}
 7553|       |
 7554|       |		// destroy extra buffers (note: no need to destroy linked list nodes, they're allocated using document allocator)
 7555|    120|		for (impl::xml_extra_buffer* extra = static_cast<impl::xml_document_struct*>(_root)->extra_buffers; extra; extra = extra->next)
  ------------------
  |  Branch (7555:103): [True: 0, False: 120]
  ------------------
 7556|      0|		{
 7557|      0|			if (extra->buffer) impl::xml_memory::deallocate(extra->buffer);
  ------------------
  |  Branch (7557:8): [True: 0, False: 0]
  ------------------
 7558|      0|		}
 7559|       |
 7560|       |		// destroy dynamic storage, leave sentinel page (it's in static memory)
 7561|    120|		impl::xml_memory_page* root_page = PUGI_IMPL_GETPAGE(_root);
  ------------------
  |  |  491|    120|	#define PUGI_IMPL_GETPAGE(n) PUGI_IMPL_GETPAGE_IMPL((n)->header)
  |  |  ------------------
  |  |  |  |  488|    120|	#define PUGI_IMPL_GETPAGE_IMPL(header) static_cast<impl::xml_memory_page*>(const_cast<void*>(static_cast<const void*>(reinterpret_cast<const char*>(&header) - (header >> 8))))
  |  |  ------------------
  ------------------
 7562|    120|		assert(root_page && !root_page->prev);
  ------------------
  |  Branch (7562:3): [True: 120, False: 0]
  |  Branch (7562:3): [True: 120, False: 0]
  |  Branch (7562:3): [True: 120, False: 0]
  ------------------
 7563|    120|		assert(reinterpret_cast<char*>(root_page) >= _memory && reinterpret_cast<char*>(root_page) < _memory + sizeof(_memory));
  ------------------
  |  Branch (7563:3): [True: 120, False: 0]
  |  Branch (7563:3): [True: 120, False: 0]
  |  Branch (7563:3): [True: 120, False: 0]
  ------------------
 7564|       |
 7565|    348|		for (impl::xml_memory_page* page = root_page->next; page; )
  ------------------
  |  Branch (7565:55): [True: 228, False: 120]
  ------------------
 7566|    228|		{
 7567|    228|			impl::xml_memory_page* next = page->next;
 7568|       |
 7569|    228|			impl::xml_allocator::deallocate_page(page);
 7570|       |
 7571|    228|			page = next;
 7572|    228|		}
 7573|       |
 7574|       |	#ifdef PUGIXML_COMPACT
 7575|       |		// destroy hash table
 7576|       |		static_cast<impl::xml_document_struct*>(_root)->hash.clear();
 7577|       |	#endif
 7578|       |
 7579|    120|		_root = nullptr;
 7580|    120|	}
_ZN4pugi12xml_document11load_bufferEPKvmjNS_12xml_encodingE:
 7747|     60|	{
 7748|     60|		reset();
 7749|       |
 7750|     60|		return impl::load_buffer_impl(static_cast<impl::xml_document_struct*>(_root), _root, const_cast<void*>(contents), size, options, encoding, false, false, &_buffer);
 7751|     60|	}
_ZN4pugi10xpath_nodeC2Ev:
12714|      2|	{
12715|      2|	}
_ZN4pugi14xpath_node_setC2Ev:
12821|      2|	PUGI_IMPL_FN xpath_node_set::xpath_node_set(): _type(type_unsorted), _begin(_storage), _end(_storage)
12822|      2|	{
12823|      2|	}
pugixml.cpp:_ZN4pugi4impl12_GLOBAL__N_113get_value_intEPKc:
 4653|  1.72k|	{
 4654|  1.72k|		return string_to_integer<unsigned int>(value, static_cast<unsigned int>(INT_MIN), INT_MAX);
 4655|  1.72k|	}
pugixml.cpp:_ZN4pugi4impl12_GLOBAL__N_117string_to_integerIjEET_PKcS3_S3_:
 4571|  5.56k|	{
 4572|  5.56k|		U result = 0;
 4573|  5.56k|		const char_t* s = value;
 4574|       |
 4575|  5.56k|		while (PUGI_IMPL_IS_CHARTYPE(*s, ct_space))
 4576|      0|			s++;
 4577|       |
 4578|  5.56k|		bool negative = (*s == '-');
 4579|       |
 4580|  5.56k|		s += (*s == '+' || *s == '-');
  ------------------
  |  Branch (4580:9): [True: 0, False: 5.56k]
  |  Branch (4580:22): [True: 0, False: 5.56k]
  ------------------
 4581|       |
 4582|  5.56k|		bool overflow = false;
 4583|       |
 4584|  5.56k|		if (s[0] == '0' && (s[1] | ' ') == 'x')
  ------------------
  |  Branch (4584:7): [True: 225, False: 5.34k]
  |  Branch (4584:22): [True: 0, False: 225]
  ------------------
 4585|      0|		{
 4586|      0|			s += 2;
 4587|       |
 4588|       |			// since overflow detection relies on length of the sequence skip leading zeros
 4589|      0|			while (*s == '0')
  ------------------
  |  Branch (4589:11): [True: 0, False: 0]
  ------------------
 4590|      0|				s++;
 4591|       |
 4592|      0|			const char_t* start = s;
 4593|       |
 4594|      0|			for (;;)
 4595|      0|			{
 4596|      0|				if (static_cast<unsigned>(*s - '0') < 10)
  ------------------
  |  Branch (4596:9): [True: 0, False: 0]
  ------------------
 4597|      0|					result = result * 16 + (*s - '0');
 4598|      0|				else if (static_cast<unsigned>((*s | ' ') - 'a') < 6)
  ------------------
  |  Branch (4598:14): [True: 0, False: 0]
  ------------------
 4599|      0|					result = result * 16 + ((*s | ' ') - 'a' + 10);
 4600|      0|				else
 4601|      0|					break;
 4602|       |
 4603|      0|				s++;
 4604|      0|			}
 4605|       |
 4606|      0|			size_t digits = static_cast<size_t>(s - start);
 4607|       |
 4608|      0|			overflow = digits > sizeof(U) * 2;
 4609|      0|		}
 4610|  5.56k|		else
 4611|  5.56k|		{
 4612|       |			// since overflow detection relies on length of the sequence skip leading zeros
 4613|  5.79k|			while (*s == '0')
  ------------------
  |  Branch (4613:11): [True: 225, False: 5.56k]
  ------------------
 4614|    225|				s++;
 4615|       |
 4616|  5.56k|			const char_t* start = s;
 4617|       |
 4618|  5.56k|			for (;;)
 4619|  12.2k|			{
 4620|  12.2k|				if (static_cast<unsigned>(*s - '0') < 10)
  ------------------
  |  Branch (4620:9): [True: 6.71k, False: 5.56k]
  ------------------
 4621|  6.71k|					result = result * 10 + (*s - '0');
 4622|  5.56k|				else
 4623|  5.56k|					break;
 4624|       |
 4625|  6.71k|				s++;
 4626|  6.71k|			}
 4627|       |
 4628|  5.56k|			size_t digits = static_cast<size_t>(s - start);
 4629|       |
 4630|  5.56k|			PUGI_IMPL_STATIC_ASSERT(sizeof(U) == 8 || sizeof(U) == 4 || sizeof(U) == 2);
  ------------------
  |  |  110|  5.56k|#define PUGI_IMPL_STATIC_ASSERT(cond) { static const char condition_failed[(cond) ? 1 : -1] = {0}; (void)condition_failed[0]; }
  ------------------
 4631|       |
 4632|  5.56k|			const size_t max_digits10 = sizeof(U) == 8 ? 20 : sizeof(U) == 4 ? 10 : 5;
  ------------------
  |  Branch (4632:32): [Folded, False: 5.56k]
  |  Branch (4632:54): [True: 0, Folded]
  ------------------
 4633|  5.56k|			const char_t max_lead = sizeof(U) == 8 ? '1' : sizeof(U) == 4 ? '4' : '6';
  ------------------
  |  Branch (4633:28): [Folded, False: 5.56k]
  |  Branch (4633:51): [True: 0, Folded]
  ------------------
 4634|  5.56k|			const size_t high_bit = sizeof(U) * 8 - 1;
 4635|       |
 4636|  5.56k|			overflow = digits >= max_digits10 && !(digits == max_digits10 && (*start < max_lead || (*start == max_lead && result >> high_bit)));
  ------------------
  |  Branch (4636:15): [True: 0, False: 5.56k]
  |  Branch (4636:43): [True: 0, False: 0]
  |  Branch (4636:70): [True: 0, False: 0]
  |  Branch (4636:92): [True: 0, False: 0]
  |  Branch (4636:114): [True: 0, False: 0]
  ------------------
 4637|  5.56k|		}
 4638|       |
 4639|  5.56k|		if (negative)
  ------------------
  |  Branch (4639:7): [True: 0, False: 5.56k]
  ------------------
 4640|      0|		{
 4641|       |			// Workaround for crayc++ CC-3059: Expected no overflow in routine.
 4642|       |		#ifdef _CRAYC
 4643|       |			return (overflow || result > ~minv + 1) ? minv : ~result + 1;
 4644|       |		#else
 4645|      0|			return (overflow || result > 0 - minv) ? minv : 0 - result;
  ------------------
  |  Branch (4645:12): [True: 0, False: 0]
  |  Branch (4645:24): [True: 0, False: 0]
  ------------------
 4646|      0|		#endif
 4647|      0|		}
 4648|  5.56k|		else
 4649|  5.56k|			return (overflow || result > maxv) ? maxv : result;
  ------------------
  |  Branch (4649:12): [True: 0, False: 5.56k]
  |  Branch (4649:24): [True: 0, False: 5.56k]
  ------------------
 4650|  5.56k|	}
pugixml.cpp:_ZN4pugi4impl12_GLOBAL__N_114get_value_uintEPKc:
 4658|  3.84k|	{
 4659|       |		return string_to_integer<unsigned int>(value, 0, UINT_MAX);
 4660|  3.84k|	}
pugixml.cpp:_ZN4pugi4impl12_GLOBAL__N_115get_value_floatEPKc:
 4672|    169|	{
 4673|       |	#ifdef PUGIXML_WCHAR_MODE
 4674|       |		return static_cast<float>(wcstod(value, nullptr));
 4675|       |	#else
 4676|    169|		return static_cast<float>(strtod(value, nullptr));
 4677|    169|	#endif
 4678|    169|	}
pugixml.cpp:_ZN4pugi4impl12_GLOBAL__N_114get_value_boolEPKc:
 4681|     18|	{
 4682|       |		// only look at first char
 4683|     18|		char_t first = *value;
 4684|       |
 4685|       |		// 1*, t* (true), T* (True), y* (yes), Y* (YES)
 4686|     18|		return (first == '1' || first == 't' || first == 'T' || first == 'y' || first == 'Y');
  ------------------
  |  Branch (4686:11): [True: 0, False: 18]
  |  Branch (4686:27): [True: 0, False: 18]
  |  Branch (4686:43): [True: 16, False: 2]
  |  Branch (4686:59): [True: 0, False: 2]
  |  Branch (4686:75): [True: 0, False: 2]
  ------------------
 4687|     18|	}
pugixml.cpp:_ZN4pugi4impl12_GLOBAL__N_18strequalEPKcS3_:
  245|  60.4k|	{
  246|  60.4k|		assert(src && dst);
  ------------------
  |  Branch (246:3): [True: 60.4k, False: 0]
  |  Branch (246:3): [True: 60.4k, False: 0]
  |  Branch (246:3): [True: 60.4k, False: 0]
  ------------------
  247|       |
  248|       |	#ifdef PUGIXML_WCHAR_MODE
  249|       |		return wcscmp(src, dst) == 0;
  250|       |	#else
  251|  60.4k|		return strcmp(src, dst) == 0;
  252|  60.4k|	#endif
  253|  60.4k|	}
pugixml.cpp:_ZN4pugi4impl12_GLOBAL__N_112is_text_nodeEPNS_15xml_node_structE:
 4563|  22.6k|	{
 4564|  22.6k|		xml_node_type type = PUGI_IMPL_NODETYPE(node);
  ------------------
  |  |  492|  22.6k|	#define PUGI_IMPL_NODETYPE(n) static_cast<xml_node_type>((n)->header & impl::xml_memory_page_type_mask)
  ------------------
 4565|       |
 4566|  22.6k|		return type == node_pcdata || type == node_cdata;
  ------------------
  |  Branch (4566:10): [True: 11.2k, False: 11.3k]
  |  Branch (4566:33): [True: 0, False: 11.3k]
  ------------------
 4567|  22.6k|	}
pugixml.cpp:_ZN4pugi4impl12_GLOBAL__N_113xml_allocator7reserveEv:
  730|   116k|		{
  731|       |		#ifdef PUGIXML_COMPACT
  732|       |			return _hash->reserve();
  733|       |		#else
  734|   116k|			return true;
  735|   116k|		#endif
  736|   116k|		}
pugixml.cpp:_ZN4pugi4impl12_GLOBAL__N_118allocate_attributeERNS1_13xml_allocatorE:
 1213|  47.7k|	{
 1214|  47.7k|		xml_memory_page* page;
 1215|  47.7k|		void* memory = alloc.allocate_object(sizeof(xml_attribute_struct), page);
 1216|  47.7k|		if (!memory) return nullptr;
  ------------------
  |  Branch (1216:7): [True: 0, False: 47.7k]
  ------------------
 1217|       |
 1218|  47.7k|		return new (memory) xml_attribute_struct(page);
 1219|  47.7k|	}
pugixml.cpp:_ZN4pugi4impl12_GLOBAL__N_113xml_allocator15allocate_objectEmRPNS1_15xml_memory_pageE:
  627|   116k|		{
  628|   116k|			return allocate_memory(size, out_page);
  629|   116k|		}
pugixml.cpp:_ZN4pugi20xml_attribute_structC2EPNS_4impl12_GLOBAL__N_115xml_memory_pageE:
 1135|  47.7k|		xml_attribute_struct(impl::xml_memory_page* page): name(nullptr), value(nullptr), prev_attribute_c(nullptr), next_attribute(nullptr)
 1136|  47.7k|		{
 1137|  47.7k|			header = PUGI_IMPL_GETHEADER_IMPL(this, page, 0);
  ------------------
  |  |  486|  47.7k|	#define PUGI_IMPL_GETHEADER_IMPL(object, page, flags) (((reinterpret_cast<char*>(object) - reinterpret_cast<char*>(page)) << 8) | (flags))
  ------------------
 1138|  47.7k|		}
pugixml.cpp:_ZN4pugi4impl12_GLOBAL__N_116append_attributeEPNS_20xml_attribute_structEPNS_15xml_node_structE:
 1370|  47.7k|	{
 1371|  47.7k|		xml_attribute_struct* head = node->first_attribute;
 1372|       |
 1373|  47.7k|		if (head)
  ------------------
  |  Branch (1373:7): [True: 21.9k, False: 25.8k]
  ------------------
 1374|  21.9k|		{
 1375|  21.9k|			xml_attribute_struct* tail = head->prev_attribute_c;
 1376|       |
 1377|  21.9k|			tail->next_attribute = attr;
 1378|  21.9k|			attr->prev_attribute_c = tail;
 1379|  21.9k|			head->prev_attribute_c = attr;
 1380|  21.9k|		}
 1381|  25.8k|		else
 1382|  25.8k|		{
 1383|  25.8k|			node->first_attribute = attr;
 1384|  25.8k|			attr->prev_attribute_c = attr;
 1385|  25.8k|		}
 1386|  47.7k|	}
pugixml.cpp:_ZN4pugi4impl12_GLOBAL__N_113allocate_nodeERNS1_13xml_allocatorENS_13xml_node_typeE:
 1222|  69.2k|	{
 1223|  69.2k|		xml_memory_page* page;
 1224|  69.2k|		void* memory = alloc.allocate_object(sizeof(xml_node_struct), page);
 1225|  69.2k|		if (!memory) return nullptr;
  ------------------
  |  Branch (1225:7): [True: 0, False: 69.2k]
  ------------------
 1226|       |
 1227|  69.2k|		return new (memory) xml_node_struct(page, type);
 1228|  69.2k|	}
pugixml.cpp:_ZN4pugi15xml_node_structC2EPNS_4impl12_GLOBAL__N_115xml_memory_pageENS_13xml_node_typeE:
 1151|  69.3k|		xml_node_struct(impl::xml_memory_page* page, xml_node_type type): name(nullptr), value(nullptr), parent(nullptr), first_child(nullptr), prev_sibling_c(nullptr), next_sibling(nullptr), first_attribute(nullptr)
 1152|  69.3k|		{
 1153|  69.3k|			header = PUGI_IMPL_GETHEADER_IMPL(this, page, type);
  ------------------
  |  |  486|  69.3k|	#define PUGI_IMPL_GETHEADER_IMPL(object, page, flags) (((reinterpret_cast<char*>(object) - reinterpret_cast<char*>(page)) << 8) | (flags))
  ------------------
 1154|  69.3k|		}
pugixml.cpp:_ZN4pugi4impl12_GLOBAL__N_111append_nodeEPNS_15xml_node_structES3_:
 1271|  69.2k|	{
 1272|  69.2k|		child->parent = node;
 1273|       |
 1274|  69.2k|		xml_node_struct* head = node->first_child;
 1275|       |
 1276|  69.2k|		if (head)
  ------------------
  |  Branch (1276:7): [True: 35.8k, False: 33.3k]
  ------------------
 1277|  35.8k|		{
 1278|  35.8k|			xml_node_struct* tail = head->prev_sibling_c;
 1279|       |
 1280|  35.8k|			tail->next_sibling = child;
 1281|  35.8k|			child->prev_sibling_c = tail;
 1282|  35.8k|			head->prev_sibling_c = child;
 1283|  35.8k|		}
 1284|  33.3k|		else
 1285|  33.3k|		{
 1286|  33.3k|			node->first_child = child;
 1287|  33.3k|			child->prev_sibling_c = child;
 1288|  33.3k|		}
 1289|  69.2k|	}
pugixml.cpp:_ZN4pugi4impl12_GLOBAL__N_120append_new_attributeEPNS_15xml_node_structERNS1_13xml_allocatorE:
 1464|  47.7k|	{
 1465|  47.7k|		if (!alloc.reserve()) return nullptr;
  ------------------
  |  Branch (1465:7): [True: 0, False: 47.7k]
  ------------------
 1466|       |
 1467|  47.7k|		xml_attribute_struct* attr = allocate_attribute(alloc);
 1468|  47.7k|		if (!attr) return nullptr;
  ------------------
  |  Branch (1468:7): [True: 0, False: 47.7k]
  ------------------
 1469|       |
 1470|  47.7k|		append_attribute(attr, node);
 1471|       |
 1472|  47.7k|		return attr;
 1473|  47.7k|	}
pugixml.cpp:_ZN4pugi4impl12_GLOBAL__N_115append_new_nodeEPNS_15xml_node_structERNS1_13xml_allocatorENS_13xml_node_typeE:
 1452|  69.2k|	{
 1453|  69.2k|		if (!alloc.reserve()) return nullptr;
  ------------------
  |  Branch (1453:7): [True: 0, False: 69.2k]
  ------------------
 1454|       |
 1455|  69.2k|		xml_node_struct* child = allocate_node(alloc, type);
 1456|  69.2k|		if (!child) return nullptr;
  ------------------
  |  Branch (1456:7): [True: 0, False: 69.2k]
  ------------------
 1457|       |
 1458|  69.2k|		append_node(child, node);
 1459|       |
 1460|  69.2k|		return child;
 1461|  69.2k|	}
pugixml.cpp:_ZN4pugi4impl12_GLOBAL__N_117make_parse_resultENS_16xml_parse_statusEl:
 2959|     61|	{
 2960|     61|		xml_parse_result result;
 2961|     61|		result.status = status;
 2962|     61|		result.offset = offset;
 2963|       |
 2964|     61|		return result;
 2965|     61|	}
pugixml.cpp:_ZN4pugi4impl12_GLOBAL__N_113xml_allocator15allocate_memoryEmRPNS1_15xml_memory_pageE:
  581|   116k|		{
  582|   116k|			if (PUGI_IMPL_UNLIKELY(_busy_size + size > xml_memory_page_size))
  ------------------
  |  |  104|   116k|#	define PUGI_IMPL_UNLIKELY(cond) __builtin_expect(cond, 0)
  |  |  ------------------
  |  |  |  Branch (104:35): [True: 228, False: 116k]
  |  |  ------------------
  ------------------
  583|    228|				return allocate_memory_oob(size, out_page);
  584|       |
  585|   116k|			void* buf = reinterpret_cast<char*>(_root) + sizeof(xml_memory_page) + _busy_size;
  586|       |
  587|   116k|			_busy_size += size;
  588|       |
  589|   116k|			out_page = _root;
  590|       |
  591|   116k|			return buf;
  592|   116k|		}
pugixml.cpp:_ZN4pugi4impl12_GLOBAL__N_113xml_allocator19allocate_memory_oobEmRPNS1_15xml_memory_pageE:
  747|    228|	{
  748|    228|		const size_t large_allocation_threshold = xml_memory_page_size / 4;
  749|       |
  750|    228|		xml_memory_page* page = allocate_page(size <= large_allocation_threshold ? xml_memory_page_size : size);
  ------------------
  |  Branch (750:41): [True: 228, False: 0]
  ------------------
  751|    228|		out_page = page;
  752|       |
  753|    228|		if (!page) return nullptr;
  ------------------
  |  Branch (753:7): [True: 0, False: 228]
  ------------------
  754|       |
  755|    228|		if (size <= large_allocation_threshold)
  ------------------
  |  Branch (755:7): [True: 228, False: 0]
  ------------------
  756|    228|		{
  757|    228|			_root->busy_size = _busy_size;
  758|       |
  759|       |			// insert page at the end of linked list
  760|    228|			page->prev = _root;
  761|    228|			_root->next = page;
  762|    228|			_root = page;
  763|       |
  764|    228|			_busy_size = size;
  765|    228|		}
  766|      0|		else
  767|      0|		{
  768|       |			// insert page before the end of linked list, so that it is deleted as soon as possible
  769|       |			// the last page is not deleted even if it's empty (see deallocate_memory)
  770|      0|			assert(_root->prev);
  ------------------
  |  Branch (770:4): [True: 0, False: 0]
  ------------------
  771|       |
  772|      0|			page->prev = _root->prev;
  773|      0|			page->next = _root;
  774|       |
  775|      0|			_root->prev->next = page;
  776|      0|			_root->prev = page;
  777|       |
  778|      0|			page->busy_size = size;
  779|      0|		}
  780|       |
  781|    228|		return reinterpret_cast<char*>(page) + sizeof(xml_memory_page);
  782|    228|	}
pugixml.cpp:_ZN4pugi4impl12_GLOBAL__N_113xml_allocator13allocate_pageEm:
  556|    228|		{
  557|    228|			size_t size = sizeof(xml_memory_page) + data_size;
  558|       |
  559|       |			// allocate block with some alignment, leaving memory for worst-case padding
  560|    228|			void* memory = xml_memory::allocate(size);
  561|    228|			if (!memory) return nullptr;
  ------------------
  |  Branch (561:8): [True: 0, False: 228]
  ------------------
  562|       |
  563|       |			// prepare page structure
  564|    228|			xml_memory_page* page = xml_memory_page::construct(memory);
  565|    228|			assert(page);
  ------------------
  |  Branch (565:4): [True: 228, False: 0]
  ------------------
  566|       |
  567|    228|			assert(this == _root->allocator);
  ------------------
  |  Branch (567:4): [True: 228, False: 0]
  ------------------
  568|    228|			page->allocator = this;
  569|       |
  570|    228|			return page;
  571|    228|		}
pugixml.cpp:_ZN4pugi4impl12_GLOBAL__N_116load_buffer_implEPNS1_19xml_document_structEPNS_15xml_node_structEPvmjNS_12xml_encodingEbbPPc:
 4773|     60|	{
 4774|       |		// check input buffer
 4775|     60|		if (!contents && size) return make_parse_result(status_io_error);
  ------------------
  |  Branch (4775:7): [True: 0, False: 60]
  |  Branch (4775:20): [True: 0, False: 0]
  ------------------
 4776|       |
 4777|       |		// get actual encoding
 4778|     60|		xml_encoding buffer_encoding = impl::get_buffer_encoding(encoding, contents, size);
 4779|       |
 4780|       |		// if convert_buffer below throws bad_alloc, we still need to deallocate contents if we own it
 4781|     60|		auto_deleter<void> contents_guard(own ? contents : nullptr, xml_memory::deallocate);
  ------------------
  |  Branch (4781:37): [True: 0, False: 60]
  ------------------
 4782|       |
 4783|       |		// get private buffer
 4784|     60|		char_t* buffer = nullptr;
 4785|     60|		size_t length = 0;
 4786|       |
 4787|       |		// coverity[var_deref_model]
 4788|     60|		if (!impl::convert_buffer(buffer, length, buffer_encoding, contents, size, is_mutable)) return impl::make_parse_result(status_out_of_memory);
  ------------------
  |  Branch (4788:7): [True: 0, False: 60]
  ------------------
 4789|       |
 4790|       |		// after this we either deallocate contents (below) or hold on to it via doc->buffer, so we don't need to guard it
 4791|     60|		contents_guard.release();
 4792|       |
 4793|       |		// delete original buffer if we performed a conversion
 4794|     60|		if (own && buffer != contents && contents) impl::xml_memory::deallocate(contents);
  ------------------
  |  Branch (4794:7): [True: 0, False: 60]
  |  Branch (4794:14): [True: 0, False: 0]
  |  Branch (4794:36): [True: 0, False: 0]
  ------------------
 4795|       |
 4796|       |		// grab onto buffer if it's our buffer, user is responsible for deallocating contents himself
 4797|     60|		if (own || buffer != contents) *out_buffer = buffer;
  ------------------
  |  Branch (4797:7): [True: 0, False: 60]
  |  Branch (4797:14): [True: 60, False: 0]
  ------------------
 4798|       |
 4799|       |		// store buffer for offset_debug
 4800|     60|		doc->buffer = buffer;
 4801|       |
 4802|       |		// parse
 4803|     60|		xml_parse_result res = impl::xml_parser::parse(buffer, length, doc, root, options);
 4804|       |
 4805|       |		// remember encoding
 4806|     60|		res.encoding = buffer_encoding;
 4807|       |
 4808|     60|		return res;
 4809|     60|	}
pugixml.cpp:_ZN4pugi4impl12_GLOBAL__N_119get_buffer_encodingENS_12xml_encodingEPKvm:
 2074|     60|	{
 2075|       |		// replace wchar encoding with utf implementation
 2076|     60|		if (encoding == encoding_wchar) return get_wchar_encoding();
  ------------------
  |  Branch (2076:7): [True: 0, False: 60]
  ------------------
 2077|       |
 2078|       |		// replace utf16 encoding with utf16 with specific endianness
 2079|     60|		if (encoding == encoding_utf16) return is_little_endian() ? encoding_utf16_le : encoding_utf16_be;
  ------------------
  |  Branch (2079:7): [True: 0, False: 60]
  |  Branch (2079:42): [True: 0, False: 0]
  ------------------
 2080|       |
 2081|       |		// replace utf32 encoding with utf32 with specific endianness
 2082|     60|		if (encoding == encoding_utf32) return is_little_endian() ? encoding_utf32_le : encoding_utf32_be;
  ------------------
  |  Branch (2082:7): [True: 0, False: 60]
  |  Branch (2082:42): [True: 0, False: 0]
  ------------------
 2083|       |
 2084|       |		// only do autodetection if no explicit encoding is requested
 2085|     60|		if (encoding != encoding_auto) return encoding;
  ------------------
  |  Branch (2085:7): [True: 0, False: 60]
  ------------------
 2086|       |
 2087|       |		// try to guess encoding (based on XML specification, Appendix F.1)
 2088|     60|		const uint8_t* data = static_cast<const uint8_t*>(contents);
 2089|       |
 2090|     60|		return guess_buffer_encoding(data, size);
 2091|     60|	}
pugixml.cpp:_ZN4pugi4impl12_GLOBAL__N_116is_little_endianEv:
 1955|      6|	{
 1956|      6|		unsigned int ui = 1;
 1957|       |
 1958|      6|		return *reinterpret_cast<unsigned char*>(&ui) == 1;
 1959|      6|	}
pugixml.cpp:_ZN4pugi4impl12_GLOBAL__N_121guess_buffer_encodingEPKhm:
 2026|     60|	{
 2027|       |		// skip encoding autodetection if input buffer is too small
 2028|     60|		if (size < 4) return encoding_utf8;
  ------------------
  |  Branch (2028:7): [True: 0, False: 60]
  ------------------
 2029|       |
 2030|     60|		uint8_t d0 = data[0], d1 = data[1], d2 = data[2], d3 = data[3];
 2031|       |
 2032|       |		// look for BOM in first few bytes
 2033|     60|		if (d0 == 0 && d1 == 0 && d2 == 0xfe && d3 == 0xff) return encoding_utf32_be;
  ------------------
  |  Branch (2033:7): [True: 2, False: 58]
  |  Branch (2033:18): [True: 0, False: 2]
  |  Branch (2033:29): [True: 0, False: 0]
  |  Branch (2033:43): [True: 0, False: 0]
  ------------------
 2034|     60|		if (d0 == 0xff && d1 == 0xfe && d2 == 0 && d3 == 0) return encoding_utf32_le;
  ------------------
  |  Branch (2034:7): [True: 5, False: 55]
  |  Branch (2034:21): [True: 5, False: 0]
  |  Branch (2034:35): [True: 0, False: 5]
  |  Branch (2034:46): [True: 0, False: 0]
  ------------------
 2035|     60|		if (d0 == 0xfe && d1 == 0xff) return encoding_utf16_be;
  ------------------
  |  Branch (2035:7): [True: 0, False: 60]
  |  Branch (2035:21): [True: 0, False: 0]
  ------------------
 2036|     60|		if (d0 == 0xff && d1 == 0xfe) return encoding_utf16_le;
  ------------------
  |  Branch (2036:7): [True: 5, False: 55]
  |  Branch (2036:21): [True: 5, False: 0]
  ------------------
 2037|     55|		if (d0 == 0xef && d1 == 0xbb && d2 == 0xbf) return encoding_utf8;
  ------------------
  |  Branch (2037:7): [True: 14, False: 41]
  |  Branch (2037:21): [True: 14, False: 0]
  |  Branch (2037:35): [True: 14, False: 0]
  ------------------
 2038|       |
 2039|       |		// look for <, <? or <?xm in various encodings
 2040|     41|		if (d0 == 0 && d1 == 0 && d2 == 0 && d3 == 0x3c) return encoding_utf32_be;
  ------------------
  |  Branch (2040:7): [True: 2, False: 39]
  |  Branch (2040:18): [True: 0, False: 2]
  |  Branch (2040:29): [True: 0, False: 0]
  |  Branch (2040:40): [True: 0, False: 0]
  ------------------
 2041|     41|		if (d0 == 0x3c && d1 == 0 && d2 == 0 && d3 == 0) return encoding_utf32_le;
  ------------------
  |  Branch (2041:7): [True: 33, False: 8]
  |  Branch (2041:21): [True: 0, False: 33]
  |  Branch (2041:32): [True: 0, False: 0]
  |  Branch (2041:43): [True: 0, False: 0]
  ------------------
 2042|     41|		if (d0 == 0 && d1 == 0x3c && d2 == 0 && d3 == 0x3f) return encoding_utf16_be;
  ------------------
  |  Branch (2042:7): [True: 2, False: 39]
  |  Branch (2042:18): [True: 1, False: 1]
  |  Branch (2042:32): [True: 0, False: 1]
  |  Branch (2042:43): [True: 0, False: 0]
  ------------------
 2043|     41|		if (d0 == 0x3c && d1 == 0 && d2 == 0x3f && d3 == 0) return encoding_utf16_le;
  ------------------
  |  Branch (2043:7): [True: 33, False: 8]
  |  Branch (2043:21): [True: 0, False: 33]
  |  Branch (2043:32): [True: 0, False: 0]
  |  Branch (2043:46): [True: 0, False: 0]
  ------------------
 2044|       |
 2045|       |		// look for utf16 < followed by node name (this may fail, but is better than utf8 since it's zero terminated so early)
 2046|     41|		if (d0 == 0 && d1 == 0x3c) return encoding_utf16_be;
  ------------------
  |  Branch (2046:7): [True: 2, False: 39]
  |  Branch (2046:18): [True: 1, False: 1]
  ------------------
 2047|     40|		if (d0 == 0x3c && d1 == 0) return encoding_utf16_le;
  ------------------
  |  Branch (2047:7): [True: 33, False: 7]
  |  Branch (2047:21): [True: 0, False: 33]
  ------------------
 2048|       |
 2049|       |		// no known BOM detected; parse declaration
 2050|     40|		const uint8_t* enc = nullptr;
 2051|     40|		size_t enc_length = 0;
 2052|       |
 2053|     40|		if (d0 == 0x3c && d1 == 0x3f && d2 == 0x78 && d3 == 0x6d && parse_declaration_encoding(data, size, enc, enc_length))
  ------------------
  |  Branch (2053:7): [True: 33, False: 7]
  |  Branch (2053:21): [True: 33, False: 0]
  |  Branch (2053:35): [True: 33, False: 0]
  |  Branch (2053:49): [True: 33, False: 0]
  |  Branch (2053:63): [True: 23, False: 10]
  ------------------
 2054|     23|		{
 2055|       |			// iso-8859-1 (case-insensitive)
 2056|     23|			if (enc_length == 10
  ------------------
  |  Branch (2056:8): [True: 0, False: 23]
  ------------------
 2057|      0|				&& (enc[0] | ' ') == 'i' && (enc[1] | ' ') == 's' && (enc[2] | ' ') == 'o'
  ------------------
  |  Branch (2057:8): [True: 0, False: 0]
  |  Branch (2057:33): [True: 0, False: 0]
  |  Branch (2057:58): [True: 0, False: 0]
  ------------------
 2058|      0|				&& enc[3] == '-' && enc[4] == '8' && enc[5] == '8' && enc[6] == '5' && enc[7] == '9'
  ------------------
  |  Branch (2058:8): [True: 0, False: 0]
  |  Branch (2058:25): [True: 0, False: 0]
  |  Branch (2058:42): [True: 0, False: 0]
  |  Branch (2058:59): [True: 0, False: 0]
  |  Branch (2058:76): [True: 0, False: 0]
  ------------------
 2059|      0|				&& enc[8] == '-' && enc[9] == '1')
  ------------------
  |  Branch (2059:8): [True: 0, False: 0]
  |  Branch (2059:25): [True: 0, False: 0]
  ------------------
 2060|      0|				return encoding_latin1;
 2061|       |
 2062|       |			// latin1 (case-insensitive)
 2063|     23|			if (enc_length == 6
  ------------------
  |  Branch (2063:8): [True: 0, False: 23]
  ------------------
 2064|      0|				&& (enc[0] | ' ') == 'l' && (enc[1] | ' ') == 'a' && (enc[2] | ' ') == 't'
  ------------------
  |  Branch (2064:8): [True: 0, False: 0]
  |  Branch (2064:33): [True: 0, False: 0]
  |  Branch (2064:58): [True: 0, False: 0]
  ------------------
 2065|      0|				&& (enc[3] | ' ') == 'i' && (enc[4] | ' ') == 'n'
  ------------------
  |  Branch (2065:8): [True: 0, False: 0]
  |  Branch (2065:33): [True: 0, False: 0]
  ------------------
 2066|      0|				&& enc[5] == '1')
  ------------------
  |  Branch (2066:8): [True: 0, False: 0]
  ------------------
 2067|      0|				return encoding_latin1;
 2068|     23|		}
 2069|       |
 2070|     40|		return encoding_utf8;
 2071|     40|	}
pugixml.cpp:_ZN4pugi4impl12_GLOBAL__N_126parse_declaration_encodingEPKhmRS3_Rm:
 1972|     33|	{
 1973|     33|	#define PUGI_IMPL_SCANCHAR(ch) { if (offset >= size || data[offset] != ch) return false; offset++; }
 1974|     33|	#define PUGI_IMPL_SCANCHARTYPE(ct) { while (offset < size && PUGI_IMPL_IS_CHARTYPE(data[offset], ct)) offset++; }
 1975|       |
 1976|       |		// check if we have a non-empty XML declaration
 1977|     33|		if (size < 6 || !((data[0] == '<') & (data[1] == '?') & (data[2] == 'x') & (data[3] == 'm') & (data[4] == 'l') && PUGI_IMPL_IS_CHARTYPE(data[5], ct_space)))
  ------------------
  |  | 1951|     33|	#define PUGI_IMPL_IS_CHARTYPE(c, ct) PUGI_IMPL_IS_CHARTYPE_IMPL(c, ct, chartype_table)
  |  |  ------------------
  |  |  |  | 1948|     33|	#define PUGI_IMPL_IS_CHARTYPE_IMPL(c, ct, table) (table[static_cast<unsigned char>(c)] & (ct))
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (1948:51): [True: 33, False: 0]
  |  |  |  |  ------------------
  |  |  ------------------
  ------------------
  |  Branch (1977:7): [True: 0, False: 33]
  |  Branch (1977:21): [True: 33, False: 0]
  ------------------
 1978|      0|			return false;
 1979|       |
 1980|       |		// scan XML declaration until the encoding field
 1981|    485|		for (size_t i = 6; i + 1 < size; ++i)
  ------------------
  |  Branch (1981:22): [True: 485, False: 0]
  ------------------
 1982|    485|		{
 1983|       |			// declaration can not contain ? in quoted values
 1984|    485|			if (data[i] == '?')
  ------------------
  |  Branch (1984:8): [True: 10, False: 475]
  ------------------
 1985|     10|				return false;
 1986|       |
 1987|    475|			if (data[i] == 'e' && data[i + 1] == 'n')
  ------------------
  |  Branch (1987:8): [True: 56, False: 419]
  |  Branch (1987:26): [True: 23, False: 33]
  ------------------
 1988|     23|			{
 1989|     23|				size_t offset = i;
 1990|       |
 1991|       |				// encoding follows the version field which can't contain 'en' so this has to be the encoding if XML is well formed
 1992|     23|				PUGI_IMPL_SCANCHAR('e'); PUGI_IMPL_SCANCHAR('n'); PUGI_IMPL_SCANCHAR('c'); PUGI_IMPL_SCANCHAR('o');
  ------------------
  |  | 1973|     23|	#define PUGI_IMPL_SCANCHAR(ch) { if (offset >= size || data[offset] != ch) return false; offset++; }
  |  |  ------------------
  |  |  |  Branch (1973:39): [True: 0, False: 23]
  |  |  |  Branch (1973:57): [True: 0, False: 23]
  |  |  ------------------
  ------------------
              				PUGI_IMPL_SCANCHAR('e'); PUGI_IMPL_SCANCHAR('n'); PUGI_IMPL_SCANCHAR('c'); PUGI_IMPL_SCANCHAR('o');
  ------------------
  |  | 1973|     23|	#define PUGI_IMPL_SCANCHAR(ch) { if (offset >= size || data[offset] != ch) return false; offset++; }
  |  |  ------------------
  |  |  |  Branch (1973:39): [True: 0, False: 23]
  |  |  |  Branch (1973:57): [True: 0, False: 23]
  |  |  ------------------
  ------------------
              				PUGI_IMPL_SCANCHAR('e'); PUGI_IMPL_SCANCHAR('n'); PUGI_IMPL_SCANCHAR('c'); PUGI_IMPL_SCANCHAR('o');
  ------------------
  |  | 1973|     23|	#define PUGI_IMPL_SCANCHAR(ch) { if (offset >= size || data[offset] != ch) return false; offset++; }
  |  |  ------------------
  |  |  |  Branch (1973:39): [True: 0, False: 23]
  |  |  |  Branch (1973:57): [True: 0, False: 23]
  |  |  ------------------
  ------------------
              				PUGI_IMPL_SCANCHAR('e'); PUGI_IMPL_SCANCHAR('n'); PUGI_IMPL_SCANCHAR('c'); PUGI_IMPL_SCANCHAR('o');
  ------------------
  |  | 1973|     23|	#define PUGI_IMPL_SCANCHAR(ch) { if (offset >= size || data[offset] != ch) return false; offset++; }
  |  |  ------------------
  |  |  |  Branch (1973:39): [True: 0, False: 23]
  |  |  |  Branch (1973:57): [True: 0, False: 23]
  |  |  ------------------
  ------------------
 1993|     23|				PUGI_IMPL_SCANCHAR('d'); PUGI_IMPL_SCANCHAR('i'); PUGI_IMPL_SCANCHAR('n'); PUGI_IMPL_SCANCHAR('g');
  ------------------
  |  | 1973|     23|	#define PUGI_IMPL_SCANCHAR(ch) { if (offset >= size || data[offset] != ch) return false; offset++; }
  |  |  ------------------
  |  |  |  Branch (1973:39): [True: 0, False: 23]
  |  |  |  Branch (1973:57): [True: 0, False: 23]
  |  |  ------------------
  ------------------
              				PUGI_IMPL_SCANCHAR('d'); PUGI_IMPL_SCANCHAR('i'); PUGI_IMPL_SCANCHAR('n'); PUGI_IMPL_SCANCHAR('g');
  ------------------
  |  | 1973|     23|	#define PUGI_IMPL_SCANCHAR(ch) { if (offset >= size || data[offset] != ch) return false; offset++; }
  |  |  ------------------
  |  |  |  Branch (1973:39): [True: 0, False: 23]
  |  |  |  Branch (1973:57): [True: 0, False: 23]
  |  |  ------------------
  ------------------
              				PUGI_IMPL_SCANCHAR('d'); PUGI_IMPL_SCANCHAR('i'); PUGI_IMPL_SCANCHAR('n'); PUGI_IMPL_SCANCHAR('g');
  ------------------
  |  | 1973|     23|	#define PUGI_IMPL_SCANCHAR(ch) { if (offset >= size || data[offset] != ch) return false; offset++; }
  |  |  ------------------
  |  |  |  Branch (1973:39): [True: 0, False: 23]
  |  |  |  Branch (1973:57): [True: 0, False: 23]
  |  |  ------------------
  ------------------
              				PUGI_IMPL_SCANCHAR('d'); PUGI_IMPL_SCANCHAR('i'); PUGI_IMPL_SCANCHAR('n'); PUGI_IMPL_SCANCHAR('g');
  ------------------
  |  | 1973|     23|	#define PUGI_IMPL_SCANCHAR(ch) { if (offset >= size || data[offset] != ch) return false; offset++; }
  |  |  ------------------
  |  |  |  Branch (1973:39): [True: 0, False: 23]
  |  |  |  Branch (1973:57): [True: 0, False: 23]
  |  |  ------------------
  ------------------
 1994|       |
 1995|       |				// S? = S?
 1996|     23|				PUGI_IMPL_SCANCHARTYPE(ct_space);
  ------------------
  |  | 1974|     23|	#define PUGI_IMPL_SCANCHARTYPE(ct) { while (offset < size && PUGI_IMPL_IS_CHARTYPE(data[offset], ct)) offset++; }
  |  |  ------------------
  |  |  |  | 1951|     23|	#define PUGI_IMPL_IS_CHARTYPE(c, ct) PUGI_IMPL_IS_CHARTYPE_IMPL(c, ct, chartype_table)
  |  |  |  |  ------------------
  |  |  |  |  |  | 1948|     23|	#define PUGI_IMPL_IS_CHARTYPE_IMPL(c, ct, table) (table[static_cast<unsigned char>(c)] & (ct))
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  Branch (1948:51): [True: 0, False: 23]
  |  |  |  |  |  |  ------------------
  |  |  |  |  ------------------
  |  |  ------------------
  |  |  |  Branch (1974:46): [True: 23, False: 0]
  |  |  ------------------
  ------------------
 1997|     23|				PUGI_IMPL_SCANCHAR('=');
  ------------------
  |  | 1973|     23|	#define PUGI_IMPL_SCANCHAR(ch) { if (offset >= size || data[offset] != ch) return false; offset++; }
  |  |  ------------------
  |  |  |  Branch (1973:39): [True: 0, False: 23]
  |  |  |  Branch (1973:57): [True: 0, False: 23]
  |  |  ------------------
  ------------------
 1998|     23|				PUGI_IMPL_SCANCHARTYPE(ct_space);
  ------------------
  |  | 1974|     23|	#define PUGI_IMPL_SCANCHARTYPE(ct) { while (offset < size && PUGI_IMPL_IS_CHARTYPE(data[offset], ct)) offset++; }
  |  |  ------------------
  |  |  |  | 1951|     23|	#define PUGI_IMPL_IS_CHARTYPE(c, ct) PUGI_IMPL_IS_CHARTYPE_IMPL(c, ct, chartype_table)
  |  |  |  |  ------------------
  |  |  |  |  |  | 1948|     23|	#define PUGI_IMPL_IS_CHARTYPE_IMPL(c, ct, table) (table[static_cast<unsigned char>(c)] & (ct))
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  Branch (1948:51): [True: 0, False: 23]
  |  |  |  |  |  |  ------------------
  |  |  |  |  ------------------
  |  |  ------------------
  |  |  |  Branch (1974:46): [True: 23, False: 0]
  |  |  ------------------
  ------------------
 1999|       |
 2000|       |				// the only two valid delimiters are ' and "
 2001|     23|				uint8_t delimiter = (offset < size && data[offset] == '"') ? '"' : '\'';
  ------------------
  |  Branch (2001:26): [True: 23, False: 0]
  |  Branch (2001:43): [True: 23, False: 0]
  ------------------
 2002|       |
 2003|     23|				PUGI_IMPL_SCANCHAR(delimiter);
  ------------------
  |  | 1973|     23|	#define PUGI_IMPL_SCANCHAR(ch) { if (offset >= size || data[offset] != ch) return false; offset++; }
  |  |  ------------------
  |  |  |  Branch (1973:39): [True: 0, False: 23]
  |  |  |  Branch (1973:57): [True: 0, False: 23]
  |  |  ------------------
  ------------------
 2004|       |
 2005|     23|				size_t start = offset;
 2006|       |
 2007|     23|				out_encoding = data + offset;
 2008|       |
 2009|     23|				PUGI_IMPL_SCANCHARTYPE(ct_symbol);
  ------------------
  |  | 1974|    138|	#define PUGI_IMPL_SCANCHARTYPE(ct) { while (offset < size && PUGI_IMPL_IS_CHARTYPE(data[offset], ct)) offset++; }
  |  |  ------------------
  |  |  |  | 1951|    138|	#define PUGI_IMPL_IS_CHARTYPE(c, ct) PUGI_IMPL_IS_CHARTYPE_IMPL(c, ct, chartype_table)
  |  |  |  |  ------------------
  |  |  |  |  |  | 1948|    138|	#define PUGI_IMPL_IS_CHARTYPE_IMPL(c, ct, table) (table[static_cast<unsigned char>(c)] & (ct))
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  Branch (1948:51): [True: 115, False: 23]
  |  |  |  |  |  |  ------------------
  |  |  |  |  ------------------
  |  |  ------------------
  |  |  |  Branch (1974:46): [True: 138, False: 0]
  |  |  ------------------
  ------------------
 2010|       |
 2011|     23|				out_length = offset - start;
 2012|       |
 2013|     23|				PUGI_IMPL_SCANCHAR(delimiter);
  ------------------
  |  | 1973|     23|	#define PUGI_IMPL_SCANCHAR(ch) { if (offset >= size || data[offset] != ch) return false; offset++; }
  |  |  ------------------
  |  |  |  Branch (1973:39): [True: 0, False: 23]
  |  |  |  Branch (1973:57): [True: 0, False: 23]
  |  |  ------------------
  ------------------
 2014|       |
 2015|     23|				return true;
 2016|     23|			}
 2017|    475|		}
 2018|       |
 2019|      0|		return false;
 2020|       |
 2021|     33|	#undef PUGI_IMPL_SCANCHAR
 2022|     33|	#undef PUGI_IMPL_SCANCHARTYPE
 2023|     33|	}
pugixml.cpp:_ZN4pugi4impl12_GLOBAL__N_112auto_deleterIvEC2EPvPFvS4_E:
  307|     60|		auto_deleter(T* data_, D deleter_): data(data_), deleter(deleter_)
  308|     60|		{
  309|     60|		}
pugixml.cpp:_ZN4pugi4impl12_GLOBAL__N_114convert_bufferERPcRmNS_12xml_encodingEPKvmb:
 2299|     60|	{
 2300|       |		// fast path: no conversion required
 2301|     60|		if (encoding == encoding_utf8)
  ------------------
  |  Branch (2301:7): [True: 54, False: 6]
  ------------------
 2302|     54|			return get_mutable_buffer(out_buffer, out_length, contents, size, is_mutable);
 2303|       |
 2304|       |		// source encoding is utf16
 2305|      6|		if (encoding == encoding_utf16_be || encoding == encoding_utf16_le)
  ------------------
  |  Branch (2305:7): [True: 1, False: 5]
  |  Branch (2305:40): [True: 5, False: 0]
  ------------------
 2306|      6|		{
 2307|      6|			xml_encoding native_encoding = is_little_endian() ? encoding_utf16_le : encoding_utf16_be;
  ------------------
  |  Branch (2307:35): [True: 6, False: 0]
  ------------------
 2308|       |
 2309|      6|			return (native_encoding == encoding) ?
  ------------------
  |  Branch (2309:11): [True: 5, False: 1]
  ------------------
 2310|      5|				convert_buffer_generic(out_buffer, out_length, contents, size, utf16_decoder<opt_false>()) :
 2311|      6|				convert_buffer_generic(out_buffer, out_length, contents, size, utf16_decoder<opt_true>());
 2312|      6|		}
 2313|       |
 2314|       |		// source encoding is utf32
 2315|      0|		if (encoding == encoding_utf32_be || encoding == encoding_utf32_le)
  ------------------
  |  Branch (2315:7): [True: 0, False: 0]
  |  Branch (2315:40): [True: 0, False: 0]
  ------------------
 2316|      0|		{
 2317|      0|			xml_encoding native_encoding = is_little_endian() ? encoding_utf32_le : encoding_utf32_be;
  ------------------
  |  Branch (2317:35): [True: 0, False: 0]
  ------------------
 2318|       |
 2319|      0|			return (native_encoding == encoding) ?
  ------------------
  |  Branch (2319:11): [True: 0, False: 0]
  ------------------
 2320|      0|				convert_buffer_generic(out_buffer, out_length, contents, size, utf32_decoder<opt_false>()) :
 2321|      0|				convert_buffer_generic(out_buffer, out_length, contents, size, utf32_decoder<opt_true>());
 2322|      0|		}
 2323|       |
 2324|       |		// source encoding is latin1
 2325|      0|		if (encoding == encoding_latin1)
  ------------------
  |  Branch (2325:7): [True: 0, False: 0]
  ------------------
 2326|      0|			return convert_buffer_latin1(out_buffer, out_length, contents, size, is_mutable);
 2327|       |
 2328|      0|		assert(false && "Invalid encoding"); // unreachable
  ------------------
  |  Branch (2328:3): [Folded, False: 0]
  |  Branch (2328:3): [True: 0, Folded]
  |  Branch (2328:3): [Folded, False: 0]
  ------------------
 2329|      0|		return false;
 2330|      0|	}
pugixml.cpp:_ZN4pugi4impl12_GLOBAL__N_118get_mutable_bufferERPcRmPKvmb:
 2094|     54|	{
 2095|     54|		size_t length = size / sizeof(char_t);
 2096|       |
 2097|     54|		if (is_mutable)
  ------------------
  |  Branch (2097:7): [True: 0, False: 54]
  ------------------
 2098|      0|		{
 2099|      0|			out_buffer = static_cast<char_t*>(const_cast<void*>(contents));
 2100|      0|			out_length = length;
 2101|      0|		}
 2102|     54|		else
 2103|     54|		{
 2104|     54|			char_t* buffer = static_cast<char_t*>(xml_memory::allocate((length + 1) * sizeof(char_t)));
 2105|     54|			if (!buffer) return false;
  ------------------
  |  Branch (2105:8): [True: 0, False: 54]
  ------------------
 2106|       |
 2107|     54|			if (contents)
  ------------------
  |  Branch (2107:8): [True: 54, False: 0]
  ------------------
 2108|     54|				memcpy(buffer, contents, length * sizeof(char_t));
 2109|      0|			else
 2110|     54|				assert(length == 0);
  ------------------
  |  Branch (2110:5): [True: 0, False: 0]
  ------------------
 2111|       |
 2112|     54|			buffer[length] = 0;
 2113|       |
 2114|     54|			out_buffer = buffer;
 2115|     54|			out_length = length + 1;
 2116|     54|		}
 2117|       |
 2118|     54|		return true;
 2119|     54|	}
pugixml.cpp:_ZN4pugi4impl12_GLOBAL__N_122convert_buffer_genericINS1_13utf16_decoderINS1_9opt_falseEEEEEbRPcRmPKvmT_:
 2228|      5|	{
 2229|      5|		const typename D::type* data = static_cast<const typename D::type*>(contents);
 2230|      5|		size_t data_length = size / sizeof(typename D::type);
 2231|       |
 2232|       |		// first pass: get length in utf8 units
 2233|      5|		size_t length = D::process(data, data_length, 0, utf8_counter());
 2234|       |
 2235|       |		// allocate buffer of suitable length
 2236|      5|		char_t* buffer = static_cast<char_t*>(xml_memory::allocate((length + 1) * sizeof(char_t)));
 2237|      5|		if (!buffer) return false;
  ------------------
  |  Branch (2237:7): [True: 0, False: 5]
  ------------------
 2238|       |
 2239|       |		// second pass: convert utf16 input to utf8
 2240|      5|		uint8_t* obegin = reinterpret_cast<uint8_t*>(buffer);
 2241|      5|		uint8_t* oend = D::process(data, data_length, obegin, utf8_writer());
 2242|       |
 2243|      5|		assert(oend == obegin + length);
  ------------------
  |  Branch (2243:3): [True: 5, False: 0]
  ------------------
 2244|      5|		*oend = 0;
 2245|       |
 2246|      5|		out_buffer = buffer;
 2247|      5|		out_length = length + 1;
 2248|       |
 2249|      5|		return true;
 2250|      5|	}
pugixml.cpp:_ZN4pugi4impl12_GLOBAL__N_113utf16_decoderINS1_9opt_falseEE7processINS1_12utf8_counterEEENT_10value_typeEPKtmS8_S7_:
 1744|      5|		{
 1745|   256k|			while (size)
  ------------------
  |  Branch (1745:11): [True: 256k, False: 5]
  ------------------
 1746|   256k|			{
 1747|   256k|				uint16_t lead = opt_swap::value ? endian_swap(*data) : *data;
  ------------------
  |  Branch (1747:21): [Folded, False: 256k]
  ------------------
 1748|       |
 1749|       |				// U+0000..U+D7FF
 1750|   256k|				if (lead < 0xD800)
  ------------------
  |  Branch (1750:9): [True: 255k, False: 149]
  ------------------
 1751|   255k|				{
 1752|   255k|					result = Traits::low(result, lead);
 1753|   255k|					data += 1;
 1754|   255k|					size -= 1;
 1755|   255k|				}
 1756|       |				// U+E000..U+FFFF
 1757|    149|				else if (static_cast<unsigned int>(lead - 0xE000) < 0x2000)
  ------------------
  |  Branch (1757:14): [True: 144, False: 5]
  ------------------
 1758|    144|				{
 1759|    144|					result = Traits::low(result, lead);
 1760|    144|					data += 1;
 1761|    144|					size -= 1;
 1762|    144|				}
 1763|       |				// surrogate pair lead
 1764|      5|				else if (static_cast<unsigned int>(lead - 0xD800) < 0x400 && size >= 2)
  ------------------
  |  Branch (1764:14): [True: 2, False: 3]
  |  Branch (1764:66): [True: 2, False: 0]
  ------------------
 1765|      2|				{
 1766|      2|					uint16_t next = opt_swap::value ? endian_swap(data[1]) : data[1];
  ------------------
  |  Branch (1766:22): [Folded, False: 2]
  ------------------
 1767|       |
 1768|      2|					if (static_cast<unsigned int>(next - 0xDC00) < 0x400)
  ------------------
  |  Branch (1768:10): [True: 0, False: 2]
  ------------------
 1769|      0|					{
 1770|      0|						result = Traits::high(result, 0x10000 + ((lead & 0x3ff) << 10) + (next & 0x3ff));
 1771|      0|						data += 2;
 1772|      0|						size -= 2;
 1773|      0|					}
 1774|      2|					else
 1775|      2|					{
 1776|      2|						data += 1;
 1777|      2|						size -= 1;
 1778|      2|					}
 1779|      2|				}
 1780|      3|				else
 1781|      3|				{
 1782|      3|					data += 1;
 1783|      3|					size -= 1;
 1784|      3|				}
 1785|   256k|			}
 1786|       |
 1787|      5|			return result;
 1788|      5|		}
pugixml.cpp:_ZN4pugi4impl12_GLOBAL__N_112utf8_counter3lowEmj:
 1506|   263k|		{
 1507|       |			// U+0000..U+007F
 1508|   263k|			if (ch < 0x80) return result + 1;
  ------------------
  |  Branch (1508:8): [True: 254k, False: 9.01k]
  ------------------
 1509|       |			// U+0080..U+07FF
 1510|  9.01k|			else if (ch < 0x800) return result + 2;
  ------------------
  |  Branch (1510:13): [True: 239, False: 8.77k]
  ------------------
 1511|       |			// U+0800..U+FFFF
 1512|  8.77k|			else return result + 3;
 1513|   263k|		}
pugixml.cpp:_ZN4pugi4impl12_GLOBAL__N_112utf8_counter4highEmj:
 1516|      1|		{
 1517|       |			// U+10000..U+10FFFF
 1518|      1|			return result + 4;
 1519|      1|		}
pugixml.cpp:_ZN4pugi4impl12_GLOBAL__N_113utf16_decoderINS1_9opt_falseEE7processINS1_11utf8_writerEEENT_10value_typeEPKtmS8_S7_:
 1744|      5|		{
 1745|   256k|			while (size)
  ------------------
  |  Branch (1745:11): [True: 256k, False: 5]
  ------------------
 1746|   256k|			{
 1747|   256k|				uint16_t lead = opt_swap::value ? endian_swap(*data) : *data;
  ------------------
  |  Branch (1747:21): [Folded, False: 256k]
  ------------------
 1748|       |
 1749|       |				// U+0000..U+D7FF
 1750|   256k|				if (lead < 0xD800)
  ------------------
  |  Branch (1750:9): [True: 255k, False: 149]
  ------------------
 1751|   255k|				{
 1752|   255k|					result = Traits::low(result, lead);
 1753|   255k|					data += 1;
 1754|   255k|					size -= 1;
 1755|   255k|				}
 1756|       |				// U+E000..U+FFFF
 1757|    149|				else if (static_cast<unsigned int>(lead - 0xE000) < 0x2000)
  ------------------
  |  Branch (1757:14): [True: 144, False: 5]
  ------------------
 1758|    144|				{
 1759|    144|					result = Traits::low(result, lead);
 1760|    144|					data += 1;
 1761|    144|					size -= 1;
 1762|    144|				}
 1763|       |				// surrogate pair lead
 1764|      5|				else if (static_cast<unsigned int>(lead - 0xD800) < 0x400 && size >= 2)
  ------------------
  |  Branch (1764:14): [True: 2, False: 3]
  |  Branch (1764:66): [True: 2, False: 0]
  ------------------
 1765|      2|				{
 1766|      2|					uint16_t next = opt_swap::value ? endian_swap(data[1]) : data[1];
  ------------------
  |  Branch (1766:22): [Folded, False: 2]
  ------------------
 1767|       |
 1768|      2|					if (static_cast<unsigned int>(next - 0xDC00) < 0x400)
  ------------------
  |  Branch (1768:10): [True: 0, False: 2]
  ------------------
 1769|      0|					{
 1770|      0|						result = Traits::high(result, 0x10000 + ((lead & 0x3ff) << 10) + (next & 0x3ff));
 1771|      0|						data += 2;
 1772|      0|						size -= 2;
 1773|      0|					}
 1774|      2|					else
 1775|      2|					{
 1776|      2|						data += 1;
 1777|      2|						size -= 1;
 1778|      2|					}
 1779|      2|				}
 1780|      3|				else
 1781|      3|				{
 1782|      3|					data += 1;
 1783|      3|					size -= 1;
 1784|      3|				}
 1785|   256k|			}
 1786|       |
 1787|      5|			return result;
 1788|      5|		}
pugixml.cpp:_ZN4pugi4impl12_GLOBAL__N_111utf8_writer3lowEPhj:
 1527|   263k|		{
 1528|       |			// U+0000..U+007F
 1529|   263k|			if (ch < 0x80)
  ------------------
  |  Branch (1529:8): [True: 254k, False: 9.15k]
  ------------------
 1530|   254k|			{
 1531|   254k|				*result = static_cast<uint8_t>(ch);
 1532|   254k|				return result + 1;
 1533|   254k|			}
 1534|       |			// U+0080..U+07FF
 1535|  9.15k|			else if (ch < 0x800)
  ------------------
  |  Branch (1535:13): [True: 374, False: 8.77k]
  ------------------
 1536|    374|			{
 1537|    374|				result[0] = static_cast<uint8_t>(0xC0 | (ch >> 6));
 1538|    374|				result[1] = static_cast<uint8_t>(0x80 | (ch & 0x3F));
 1539|    374|				return result + 2;
 1540|    374|			}
 1541|       |			// U+0800..U+FFFF
 1542|  8.77k|			else
 1543|  8.77k|			{
 1544|  8.77k|				result[0] = static_cast<uint8_t>(0xE0 | (ch >> 12));
 1545|  8.77k|				result[1] = static_cast<uint8_t>(0x80 | ((ch >> 6) & 0x3F));
 1546|  8.77k|				result[2] = static_cast<uint8_t>(0x80 | (ch & 0x3F));
 1547|  8.77k|				return result + 3;
 1548|  8.77k|			}
 1549|   263k|		}
pugixml.cpp:_ZN4pugi4impl12_GLOBAL__N_111utf8_writer4highEPhj:
 1552|      1|		{
 1553|       |			// U+10000..U+10FFFF
 1554|      1|			result[0] = static_cast<uint8_t>(0xF0 | (ch >> 18));
 1555|      1|			result[1] = static_cast<uint8_t>(0x80 | ((ch >> 12) & 0x3F));
 1556|      1|			result[2] = static_cast<uint8_t>(0x80 | ((ch >> 6) & 0x3F));
 1557|      1|			result[3] = static_cast<uint8_t>(0x80 | (ch & 0x3F));
 1558|      1|			return result + 4;
 1559|      1|		}
pugixml.cpp:_ZN4pugi4impl12_GLOBAL__N_122convert_buffer_genericINS1_13utf16_decoderINS1_8opt_trueEEEEEbRPcRmPKvmT_:
 2228|      1|	{
 2229|      1|		const typename D::type* data = static_cast<const typename D::type*>(contents);
 2230|      1|		size_t data_length = size / sizeof(typename D::type);
 2231|       |
 2232|       |		// first pass: get length in utf8 units
 2233|      1|		size_t length = D::process(data, data_length, 0, utf8_counter());
 2234|       |
 2235|       |		// allocate buffer of suitable length
 2236|      1|		char_t* buffer = static_cast<char_t*>(xml_memory::allocate((length + 1) * sizeof(char_t)));
 2237|      1|		if (!buffer) return false;
  ------------------
  |  Branch (2237:7): [True: 0, False: 1]
  ------------------
 2238|       |
 2239|       |		// second pass: convert utf16 input to utf8
 2240|      1|		uint8_t* obegin = reinterpret_cast<uint8_t*>(buffer);
 2241|      1|		uint8_t* oend = D::process(data, data_length, obegin, utf8_writer());
 2242|       |
 2243|      1|		assert(oend == obegin + length);
  ------------------
  |  Branch (2243:3): [True: 1, False: 0]
  ------------------
 2244|      1|		*oend = 0;
 2245|       |
 2246|      1|		out_buffer = buffer;
 2247|      1|		out_length = length + 1;
 2248|       |
 2249|      1|		return true;
 2250|      1|	}
pugixml.cpp:_ZN4pugi4impl12_GLOBAL__N_113utf16_decoderINS1_8opt_trueEE7processINS1_12utf8_counterEEENT_10value_typeEPKtmS8_S7_:
 1744|      1|		{
 1745|  7.20k|			while (size)
  ------------------
  |  Branch (1745:11): [True: 7.20k, False: 1]
  ------------------
 1746|  7.20k|			{
 1747|  7.20k|				uint16_t lead = opt_swap::value ? endian_swap(*data) : *data;
  ------------------
  |  Branch (1747:21): [True: 7.20k, Folded]
  ------------------
 1748|       |
 1749|       |				// U+0000..U+D7FF
 1750|  7.20k|				if (lead < 0xD800)
  ------------------
  |  Branch (1750:9): [True: 6.06k, False: 1.13k]
  ------------------
 1751|  6.06k|				{
 1752|  6.06k|					result = Traits::low(result, lead);
 1753|  6.06k|					data += 1;
 1754|  6.06k|					size -= 1;
 1755|  6.06k|				}
 1756|       |				// U+E000..U+FFFF
 1757|  1.13k|				else if (static_cast<unsigned int>(lead - 0xE000) < 0x2000)
  ------------------
  |  Branch (1757:14): [True: 906, False: 230]
  ------------------
 1758|    906|				{
 1759|    906|					result = Traits::low(result, lead);
 1760|    906|					data += 1;
 1761|    906|					size -= 1;
 1762|    906|				}
 1763|       |				// surrogate pair lead
 1764|    230|				else if (static_cast<unsigned int>(lead - 0xD800) < 0x400 && size >= 2)
  ------------------
  |  Branch (1764:14): [True: 120, False: 110]
  |  Branch (1764:66): [True: 120, False: 0]
  ------------------
 1765|    120|				{
 1766|    120|					uint16_t next = opt_swap::value ? endian_swap(data[1]) : data[1];
  ------------------
  |  Branch (1766:22): [True: 120, Folded]
  ------------------
 1767|       |
 1768|    120|					if (static_cast<unsigned int>(next - 0xDC00) < 0x400)
  ------------------
  |  Branch (1768:10): [True: 1, False: 119]
  ------------------
 1769|      1|					{
 1770|      1|						result = Traits::high(result, 0x10000 + ((lead & 0x3ff) << 10) + (next & 0x3ff));
 1771|      1|						data += 2;
 1772|      1|						size -= 2;
 1773|      1|					}
 1774|    119|					else
 1775|    119|					{
 1776|    119|						data += 1;
 1777|    119|						size -= 1;
 1778|    119|					}
 1779|    120|				}
 1780|    110|				else
 1781|    110|				{
 1782|    110|					data += 1;
 1783|    110|					size -= 1;
 1784|    110|				}
 1785|  7.20k|			}
 1786|       |
 1787|      1|			return result;
 1788|      1|		}
pugixml.cpp:_ZN4pugi4impl12_GLOBAL__N_111endian_swapEt:
 1492|  14.6k|	{
 1493|  14.6k|		return static_cast<uint16_t>(((value & 0xff) << 8) | (value >> 8));
 1494|  14.6k|	}
pugixml.cpp:_ZN4pugi4impl12_GLOBAL__N_113utf16_decoderINS1_8opt_trueEE7processINS1_11utf8_writerEEENT_10value_typeEPKtmS8_S7_:
 1744|      1|		{
 1745|  7.20k|			while (size)
  ------------------
  |  Branch (1745:11): [True: 7.20k, False: 1]
  ------------------
 1746|  7.20k|			{
 1747|  7.20k|				uint16_t lead = opt_swap::value ? endian_swap(*data) : *data;
  ------------------
  |  Branch (1747:21): [True: 7.20k, Folded]
  ------------------
 1748|       |
 1749|       |				// U+0000..U+D7FF
 1750|  7.20k|				if (lead < 0xD800)
  ------------------
  |  Branch (1750:9): [True: 6.06k, False: 1.13k]
  ------------------
 1751|  6.06k|				{
 1752|  6.06k|					result = Traits::low(result, lead);
 1753|  6.06k|					data += 1;
 1754|  6.06k|					size -= 1;
 1755|  6.06k|				}
 1756|       |				// U+E000..U+FFFF
 1757|  1.13k|				else if (static_cast<unsigned int>(lead - 0xE000) < 0x2000)
  ------------------
  |  Branch (1757:14): [True: 906, False: 230]
  ------------------
 1758|    906|				{
 1759|    906|					result = Traits::low(result, lead);
 1760|    906|					data += 1;
 1761|    906|					size -= 1;
 1762|    906|				}
 1763|       |				// surrogate pair lead
 1764|    230|				else if (static_cast<unsigned int>(lead - 0xD800) < 0x400 && size >= 2)
  ------------------
  |  Branch (1764:14): [True: 120, False: 110]
  |  Branch (1764:66): [True: 120, False: 0]
  ------------------
 1765|    120|				{
 1766|    120|					uint16_t next = opt_swap::value ? endian_swap(data[1]) : data[1];
  ------------------
  |  Branch (1766:22): [True: 120, Folded]
  ------------------
 1767|       |
 1768|    120|					if (static_cast<unsigned int>(next - 0xDC00) < 0x400)
  ------------------
  |  Branch (1768:10): [True: 1, False: 119]
  ------------------
 1769|      1|					{
 1770|      1|						result = Traits::high(result, 0x10000 + ((lead & 0x3ff) << 10) + (next & 0x3ff));
 1771|      1|						data += 2;
 1772|      1|						size -= 2;
 1773|      1|					}
 1774|    119|					else
 1775|    119|					{
 1776|    119|						data += 1;
 1777|    119|						size -= 1;
 1778|    119|					}
 1779|    120|				}
 1780|    110|				else
 1781|    110|				{
 1782|    110|					data += 1;
 1783|    110|					size -= 1;
 1784|    110|				}
 1785|  7.20k|			}
 1786|       |
 1787|      1|			return result;
 1788|      1|		}
pugixml.cpp:_ZN4pugi4impl12_GLOBAL__N_112auto_deleterIvE7releaseEv:
  317|     60|		{
  318|     60|			T* result = data;
  319|     60|			data = nullptr;
  320|     60|			return result;
  321|     60|		}
pugixml.cpp:_ZN4pugi4impl12_GLOBAL__N_110xml_parser5parseEPcmPNS1_19xml_document_structEPNS_15xml_node_structEj:
 3579|     60|		{
 3580|       |			// early-out for empty documents
 3581|     60|			if (length == 0)
  ------------------
  |  Branch (3581:8): [True: 0, False: 60]
  ------------------
 3582|      0|				return make_parse_result(PUGI_IMPL_OPTSET(parse_fragment) ? status_ok : status_no_document_element);
  ------------------
  |  | 2644|      0|	#define PUGI_IMPL_OPTSET(OPT)           ( optmsk & (OPT) )
  |  |  ------------------
  |  |  |  Branch (2644:42): [True: 0, False: 0]
  |  |  ------------------
  ------------------
 3583|       |
 3584|       |			// get last child of the root before parsing
 3585|     60|			xml_node_struct* last_root_child = root->first_child ? root->first_child->prev_sibling_c + 0 : nullptr;
  ------------------
  |  Branch (3585:39): [True: 0, False: 60]
  ------------------
 3586|       |
 3587|       |			// create parser on stack
 3588|     60|			xml_parser parser(static_cast<xml_allocator*>(xmldoc));
 3589|       |
 3590|       |			// save last character and make buffer zero-terminated (speeds up parsing)
 3591|     60|			char_t endch = buffer[length - 1];
 3592|     60|			buffer[length - 1] = 0;
 3593|       |
 3594|       |			// skip BOM to make sure it does not end up as part of parse output
 3595|     60|			char_t* buffer_data = parse_skip_bom(buffer);
 3596|       |
 3597|       |			// perform actual parsing
 3598|     60|			parser.parse_tree(buffer_data, root, optmsk, endch);
 3599|       |
 3600|     60|			xml_parse_result result = make_parse_result(parser.error_status, parser.error_offset ? parser.error_offset - buffer : 0);
  ------------------
  |  Branch (3600:69): [True: 11, False: 49]
  ------------------
 3601|     60|			assert(result.offset >= 0 && static_cast<size_t>(result.offset) <= length);
  ------------------
  |  Branch (3601:4): [True: 60, False: 0]
  |  Branch (3601:4): [True: 60, False: 0]
  |  Branch (3601:4): [True: 60, False: 0]
  ------------------
 3602|       |
 3603|     60|			if (result)
  ------------------
  |  Branch (3603:8): [True: 49, False: 11]
  ------------------
 3604|     49|			{
 3605|       |				// since we removed last character, we have to handle the only possible false positive (stray <)
 3606|     49|				if (endch == '<')
  ------------------
  |  Branch (3606:9): [True: 0, False: 49]
  ------------------
 3607|      0|					return make_parse_result(status_unrecognized_tag, length - 1);
 3608|       |
 3609|       |				// check if there are any element nodes parsed
 3610|     49|				xml_node_struct* first_root_child_parsed = last_root_child ? last_root_child->next_sibling + 0 : root->first_child + 0;
  ------------------
  |  Branch (3610:48): [True: 0, False: 49]
  ------------------
 3611|       |
 3612|     49|				if (!PUGI_IMPL_OPTSET(parse_fragment) && !has_element_node_siblings(first_root_child_parsed))
  ------------------
  |  | 2644|     98|	#define PUGI_IMPL_OPTSET(OPT)           ( optmsk & (OPT) )
  ------------------
  |  Branch (3612:9): [True: 49, False: 0]
  |  Branch (3612:46): [True: 1, False: 48]
  ------------------
 3613|      1|					return make_parse_result(status_no_document_element, length - 1);
 3614|     49|			}
 3615|     11|			else
 3616|     11|			{
 3617|       |				// roll back offset if it occurs on a null terminator in the source buffer
 3618|     11|				if (result.offset > 0 && static_cast<size_t>(result.offset) == length - 1 && endch == 0)
  ------------------
  |  Branch (3618:9): [True: 11, False: 0]
  |  Branch (3618:30): [True: 0, False: 11]
  |  Branch (3618:82): [True: 0, False: 0]
  ------------------
 3619|      0|					result.offset--;
 3620|     11|			}
 3621|       |
 3622|     59|			return result;
 3623|     60|		}
pugixml.cpp:_ZN4pugi4impl12_GLOBAL__N_110xml_parserC2EPNS1_13xml_allocatorE:
 2973|     60|		xml_parser(xml_allocator* alloc_): alloc(alloc_), error_offset(nullptr), error_status(status_ok)
 2974|     60|		{
 2975|     60|		}
pugixml.cpp:_ZN4pugi4impl12_GLOBAL__N_110xml_parser14parse_skip_bomEPc:
 3561|     60|		{
 3562|     60|			return (s[0] == '\xef' && s[1] == '\xbb' && s[2] == '\xbf') ? s + 3 : s;
  ------------------
  |  Branch (3562:12): [True: 19, False: 41]
  |  Branch (3562:30): [True: 19, False: 0]
  |  Branch (3562:48): [True: 19, False: 0]
  ------------------
 3563|     60|		}
pugixml.cpp:_ZN4pugi4impl12_GLOBAL__N_110xml_parser10parse_treeEPcPNS_15xml_node_structEjc:
 3298|     60|		{
 3299|     60|			strconv_attribute_t strconv_attribute = get_strconv_attribute(optmsk);
 3300|     60|			strconv_pcdata_t strconv_pcdata = get_strconv_pcdata(optmsk);
 3301|       |
 3302|     60|			char_t ch = 0;
 3303|     60|			xml_node_struct* cursor = root;
 3304|     60|			char_t* mark = s;
 3305|     60|			char_t* merged_pcdata = s;
 3306|       |
 3307|   123k|			while (*s != 0)
  ------------------
  |  Branch (3307:11): [True: 123k, False: 49]
  ------------------
 3308|   123k|			{
 3309|   123k|				if (*s == '<')
  ------------------
  |  Branch (3309:9): [True: 64.4k, False: 59.4k]
  ------------------
 3310|  64.4k|				{
 3311|  64.4k|					++s;
 3312|       |
 3313|  85.5k|				LOC_TAG:
 3314|  85.5k|					if (PUGI_IMPL_IS_CHARTYPE(*s, ct_start_symbol)) // '<#...'
  ------------------
  |  | 1951|  85.5k|	#define PUGI_IMPL_IS_CHARTYPE(c, ct) PUGI_IMPL_IS_CHARTYPE_IMPL(c, ct, chartype_table)
  |  |  ------------------
  |  |  |  | 1948|  85.5k|	#define PUGI_IMPL_IS_CHARTYPE_IMPL(c, ct, table) (table[static_cast<unsigned char>(c)] & (ct))
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (1948:51): [True: 48.0k, False: 37.4k]
  |  |  |  |  ------------------
  |  |  ------------------
  ------------------
 3315|  48.0k|					{
 3316|  48.0k|						PUGI_IMPL_PUSHNODE(node_element); // Append a new node to the tree.
  ------------------
  |  | 2645|  48.0k|	#define PUGI_IMPL_PUSHNODE(TYPE)        { cursor = append_new_node(cursor, *alloc, TYPE); if (!cursor) PUGI_IMPL_THROW_ERROR(status_out_of_memory, s); }
  |  |  ------------------
  |  |  |  | 2651|      0|	#define PUGI_IMPL_THROW_ERROR(err, m)   return error_offset = m, error_status = err, static_cast<char_t*>(nullptr)
  |  |  ------------------
  |  |  |  Branch (2645:96): [True: 0, False: 48.0k]
  |  |  ------------------
  ------------------
 3317|       |
 3318|  48.0k|						cursor->name = s;
 3319|       |
 3320|  48.0k|						PUGI_IMPL_SCANWHILE_UNROLL(PUGI_IMPL_IS_CHARTYPE(ss, ct_symbol)); // Scan for a terminator.
  ------------------
  |  | 2649|  99.9k|	#define PUGI_IMPL_SCANWHILE_UNROLL(X)   { for (;;) { char_t ss = s[0]; if (PUGI_IMPL_UNLIKELY(!(X))) { break; } ss = s[1]; if (PUGI_IMPL_UNLIKELY(!(X))) { s += 1; break; } ss = s[2]; if (PUGI_IMPL_UNLIKELY(!(X))) { s += 2; break; } ss = s[3]; if (PUGI_IMPL_UNLIKELY(!(X))) { s += 3; break; } s += 4; } }
  |  |  ------------------
  |  |  |  |  104|  99.9k|#	define PUGI_IMPL_UNLIKELY(cond) __builtin_expect(cond, 0)
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (104:35): [True: 11.6k, False: 88.3k]
  |  |  |  |  ------------------
  |  |  ------------------
  |  |               	#define PUGI_IMPL_SCANWHILE_UNROLL(X)   { for (;;) { char_t ss = s[0]; if (PUGI_IMPL_UNLIKELY(!(X))) { break; } ss = s[1]; if (PUGI_IMPL_UNLIKELY(!(X))) { s += 1; break; } ss = s[2]; if (PUGI_IMPL_UNLIKELY(!(X))) { s += 2; break; } ss = s[3]; if (PUGI_IMPL_UNLIKELY(!(X))) { s += 3; break; } s += 4; } }
  |  |  ------------------
  |  |  |  |  104|  88.3k|#	define PUGI_IMPL_UNLIKELY(cond) __builtin_expect(cond, 0)
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (104:35): [True: 26.3k, False: 62.0k]
  |  |  |  |  ------------------
  |  |  ------------------
  |  |               	#define PUGI_IMPL_SCANWHILE_UNROLL(X)   { for (;;) { char_t ss = s[0]; if (PUGI_IMPL_UNLIKELY(!(X))) { break; } ss = s[1]; if (PUGI_IMPL_UNLIKELY(!(X))) { s += 1; break; } ss = s[2]; if (PUGI_IMPL_UNLIKELY(!(X))) { s += 2; break; } ss = s[3]; if (PUGI_IMPL_UNLIKELY(!(X))) { s += 3; break; } s += 4; } }
  |  |  ------------------
  |  |  |  |  104|  62.0k|#	define PUGI_IMPL_UNLIKELY(cond) __builtin_expect(cond, 0)
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (104:35): [True: 5.31k, False: 56.7k]
  |  |  |  |  ------------------
  |  |  ------------------
  |  |               	#define PUGI_IMPL_SCANWHILE_UNROLL(X)   { for (;;) { char_t ss = s[0]; if (PUGI_IMPL_UNLIKELY(!(X))) { break; } ss = s[1]; if (PUGI_IMPL_UNLIKELY(!(X))) { s += 1; break; } ss = s[2]; if (PUGI_IMPL_UNLIKELY(!(X))) { s += 2; break; } ss = s[3]; if (PUGI_IMPL_UNLIKELY(!(X))) { s += 3; break; } s += 4; } }
  |  |  ------------------
  |  |  |  |  104|  56.7k|#	define PUGI_IMPL_UNLIKELY(cond) __builtin_expect(cond, 0)
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (104:35): [True: 4.82k, False: 51.9k]
  |  |  |  |  ------------------
  |  |  ------------------
  ------------------
 3321|  48.0k|						PUGI_IMPL_ENDSEG(); // Save char in 'ch', terminate & step over.
  ------------------
  |  | 2650|  48.0k|	#define PUGI_IMPL_ENDSEG()              { ch = *s; *s = 0; ++s; }
  ------------------
 3322|       |
 3323|  48.0k|						if (ch == '>')
  ------------------
  |  Branch (3323:11): [True: 22.3k, False: 25.7k]
  ------------------
 3324|  22.3k|						{
 3325|       |							// end of tag
 3326|  22.3k|						}
 3327|  25.7k|						else if (PUGI_IMPL_IS_CHARTYPE(ch, ct_space))
  ------------------
  |  | 1951|  25.7k|	#define PUGI_IMPL_IS_CHARTYPE(c, ct) PUGI_IMPL_IS_CHARTYPE_IMPL(c, ct, chartype_table)
  |  |  ------------------
  |  |  |  | 1948|  25.7k|	#define PUGI_IMPL_IS_CHARTYPE_IMPL(c, ct, table) (table[static_cast<unsigned char>(c)] & (ct))
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (1948:51): [True: 25.7k, False: 8]
  |  |  |  |  ------------------
  |  |  ------------------
  ------------------
 3328|  25.7k|						{
 3329|  25.8k|						LOC_ATTRIBUTES:
 3330|  73.5k|							while (true)
  ------------------
  |  Branch (3330:15): [True: 73.5k, Folded]
  ------------------
 3331|  73.5k|							{
 3332|  73.5k|								PUGI_IMPL_SKIPWS(); // Eat any whitespace.
  ------------------
  |  | 2643|  73.5k|	#define PUGI_IMPL_SKIPWS()              { while (PUGI_IMPL_IS_CHARTYPE(*s, ct_space)) ++s; }
  ------------------
 3333|       |
 3334|  73.5k|								if (PUGI_IMPL_IS_CHARTYPE(*s, ct_start_symbol)) // <... #...
  ------------------
  |  | 1951|  73.5k|	#define PUGI_IMPL_IS_CHARTYPE(c, ct) PUGI_IMPL_IS_CHARTYPE_IMPL(c, ct, chartype_table)
  |  |  ------------------
  |  |  |  | 1948|  73.5k|	#define PUGI_IMPL_IS_CHARTYPE_IMPL(c, ct, table) (table[static_cast<unsigned char>(c)] & (ct))
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (1948:51): [True: 47.7k, False: 25.7k]
  |  |  |  |  ------------------
  |  |  ------------------
  ------------------
 3335|  47.7k|								{
 3336|  47.7k|									xml_attribute_struct* a = append_new_attribute(cursor, *alloc); // Make space for this attribute.
 3337|  47.7k|									if (!a) PUGI_IMPL_THROW_ERROR(status_out_of_memory, s);
  ------------------
  |  | 2651|      0|	#define PUGI_IMPL_THROW_ERROR(err, m)   return error_offset = m, error_status = err, static_cast<char_t*>(nullptr)
  ------------------
  |  Branch (3337:14): [True: 0, False: 47.7k]
  ------------------
 3338|       |
 3339|  47.7k|									a->name = s; // Save the offset.
 3340|       |
 3341|  47.7k|									PUGI_IMPL_SCANWHILE_UNROLL(PUGI_IMPL_IS_CHARTYPE(ss, ct_symbol)); // Scan for a terminator.
  ------------------
  |  | 2649|  91.4k|	#define PUGI_IMPL_SCANWHILE_UNROLL(X)   { for (;;) { char_t ss = s[0]; if (PUGI_IMPL_UNLIKELY(!(X))) { break; } ss = s[1]; if (PUGI_IMPL_UNLIKELY(!(X))) { s += 1; break; } ss = s[2]; if (PUGI_IMPL_UNLIKELY(!(X))) { s += 2; break; } ss = s[3]; if (PUGI_IMPL_UNLIKELY(!(X))) { s += 3; break; } s += 4; } }
  |  |  ------------------
  |  |  |  |  104|  91.4k|#	define PUGI_IMPL_UNLIKELY(cond) __builtin_expect(cond, 0)
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (104:35): [True: 16.7k, False: 74.6k]
  |  |  |  |  ------------------
  |  |  ------------------
  |  |               	#define PUGI_IMPL_SCANWHILE_UNROLL(X)   { for (;;) { char_t ss = s[0]; if (PUGI_IMPL_UNLIKELY(!(X))) { break; } ss = s[1]; if (PUGI_IMPL_UNLIKELY(!(X))) { s += 1; break; } ss = s[2]; if (PUGI_IMPL_UNLIKELY(!(X))) { s += 2; break; } ss = s[3]; if (PUGI_IMPL_UNLIKELY(!(X))) { s += 3; break; } s += 4; } }
  |  |  ------------------
  |  |  |  |  104|  74.6k|#	define PUGI_IMPL_UNLIKELY(cond) __builtin_expect(cond, 0)
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (104:35): [True: 12.4k, False: 62.2k]
  |  |  |  |  ------------------
  |  |  ------------------
  |  |               	#define PUGI_IMPL_SCANWHILE_UNROLL(X)   { for (;;) { char_t ss = s[0]; if (PUGI_IMPL_UNLIKELY(!(X))) { break; } ss = s[1]; if (PUGI_IMPL_UNLIKELY(!(X))) { s += 1; break; } ss = s[2]; if (PUGI_IMPL_UNLIKELY(!(X))) { s += 2; break; } ss = s[3]; if (PUGI_IMPL_UNLIKELY(!(X))) { s += 3; break; } s += 4; } }
  |  |  ------------------
  |  |  |  |  104|  62.2k|#	define PUGI_IMPL_UNLIKELY(cond) __builtin_expect(cond, 0)
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (104:35): [True: 16.5k, False: 45.7k]
  |  |  |  |  ------------------
  |  |  ------------------
  |  |               	#define PUGI_IMPL_SCANWHILE_UNROLL(X)   { for (;;) { char_t ss = s[0]; if (PUGI_IMPL_UNLIKELY(!(X))) { break; } ss = s[1]; if (PUGI_IMPL_UNLIKELY(!(X))) { s += 1; break; } ss = s[2]; if (PUGI_IMPL_UNLIKELY(!(X))) { s += 2; break; } ss = s[3]; if (PUGI_IMPL_UNLIKELY(!(X))) { s += 3; break; } s += 4; } }
  |  |  ------------------
  |  |  |  |  104|  45.7k|#	define PUGI_IMPL_UNLIKELY(cond) __builtin_expect(cond, 0)
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (104:35): [True: 2.04k, False: 43.6k]
  |  |  |  |  ------------------
  |  |  ------------------
  ------------------
 3342|  47.7k|									PUGI_IMPL_ENDSEG(); // Save char in 'ch', terminate & step over.
  ------------------
  |  | 2650|  47.7k|	#define PUGI_IMPL_ENDSEG()              { ch = *s; *s = 0; ++s; }
  ------------------
 3343|       |
 3344|  47.7k|									if (PUGI_IMPL_IS_CHARTYPE(ch, ct_space))
  ------------------
  |  | 1951|  47.7k|	#define PUGI_IMPL_IS_CHARTYPE(c, ct) PUGI_IMPL_IS_CHARTYPE_IMPL(c, ct, chartype_table)
  |  |  ------------------
  |  |  |  | 1948|  47.7k|	#define PUGI_IMPL_IS_CHARTYPE_IMPL(c, ct, table) (table[static_cast<unsigned char>(c)] & (ct))
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (1948:51): [True: 2, False: 47.7k]
  |  |  |  |  ------------------
  |  |  ------------------
  ------------------
 3345|      2|									{
 3346|      2|										PUGI_IMPL_SKIPWS(); // Eat any whitespace.
  ------------------
  |  | 2643|      2|	#define PUGI_IMPL_SKIPWS()              { while (PUGI_IMPL_IS_CHARTYPE(*s, ct_space)) ++s; }
  ------------------
 3347|       |
 3348|      2|										ch = *s;
 3349|      2|										++s;
 3350|      2|									}
 3351|       |
 3352|  47.7k|									if (ch == '=') // '<... #=...'
  ------------------
  |  Branch (3352:14): [True: 47.7k, False: 2]
  ------------------
 3353|  47.7k|									{
 3354|  47.7k|										PUGI_IMPL_SKIPWS(); // Eat any whitespace.
  ------------------
  |  | 2643|  47.7k|	#define PUGI_IMPL_SKIPWS()              { while (PUGI_IMPL_IS_CHARTYPE(*s, ct_space)) ++s; }
  ------------------
 3355|       |
 3356|  47.7k|										if (*s == '"' || *s == '\'') // '<... #="...'
  ------------------
  |  Branch (3356:15): [True: 47.7k, False: 1]
  |  Branch (3356:28): [True: 1, False: 0]
  ------------------
 3357|  47.7k|										{
 3358|  47.7k|											ch = *s; // Save quote char to avoid breaking on "''" -or- '""'.
 3359|  47.7k|											++s; // Step over the quote.
 3360|  47.7k|											a->value = s; // Save the offset.
 3361|       |
 3362|  47.7k|											s = strconv_attribute(s, ch);
 3363|       |
 3364|  47.7k|											if (!s) PUGI_IMPL_THROW_ERROR(status_bad_attribute, a->value);
  ------------------
  |  | 2651|      0|	#define PUGI_IMPL_THROW_ERROR(err, m)   return error_offset = m, error_status = err, static_cast<char_t*>(nullptr)
  ------------------
  |  Branch (3364:16): [True: 0, False: 47.7k]
  ------------------
 3365|       |
 3366|       |											// After this line the loop continues from the start;
 3367|       |											// Whitespaces, / and > are ok, symbols and EOF are wrong,
 3368|       |											// everything else will be detected
 3369|  47.7k|											if (PUGI_IMPL_IS_CHARTYPE(*s, ct_start_symbol)) PUGI_IMPL_THROW_ERROR(status_bad_attribute, s);
  ------------------
  |  | 1951|  47.7k|	#define PUGI_IMPL_IS_CHARTYPE(c, ct) PUGI_IMPL_IS_CHARTYPE_IMPL(c, ct, chartype_table)
  |  |  ------------------
  |  |  |  | 1948|  47.7k|	#define PUGI_IMPL_IS_CHARTYPE_IMPL(c, ct, table) (table[static_cast<unsigned char>(c)] & (ct))
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (1948:51): [True: 2, False: 47.7k]
  |  |  |  |  ------------------
  |  |  ------------------
  ------------------
              											if (PUGI_IMPL_IS_CHARTYPE(*s, ct_start_symbol)) PUGI_IMPL_THROW_ERROR(status_bad_attribute, s);
  ------------------
  |  | 2651|      2|	#define PUGI_IMPL_THROW_ERROR(err, m)   return error_offset = m, error_status = err, static_cast<char_t*>(nullptr)
  ------------------
 3370|  47.7k|										}
 3371|      0|										else PUGI_IMPL_THROW_ERROR(status_bad_attribute, s);
  ------------------
  |  | 2651|      0|	#define PUGI_IMPL_THROW_ERROR(err, m)   return error_offset = m, error_status = err, static_cast<char_t*>(nullptr)
  ------------------
 3372|  47.7k|									}
 3373|      2|									else PUGI_IMPL_THROW_ERROR(status_bad_attribute, s);
  ------------------
  |  | 2651|      2|	#define PUGI_IMPL_THROW_ERROR(err, m)   return error_offset = m, error_status = err, static_cast<char_t*>(nullptr)
  ------------------
 3374|  47.7k|								}
 3375|  25.7k|								else if (*s == '/')
  ------------------
  |  Branch (3375:18): [True: 10.4k, False: 15.3k]
  ------------------
 3376|  10.4k|								{
 3377|  10.4k|									++s;
 3378|       |
 3379|  10.4k|									if (*s == '>')
  ------------------
  |  Branch (3379:14): [True: 10.4k, False: 0]
  ------------------
 3380|  10.4k|									{
 3381|  10.4k|										PUGI_IMPL_POPNODE();
  ------------------
  |  | 2646|  10.4k|	#define PUGI_IMPL_POPNODE()             { cursor = cursor->parent; }
  ------------------
 3382|  10.4k|										s++;
 3383|  10.4k|										break;
 3384|  10.4k|									}
 3385|      0|									else if (*s == 0 && endch == '>')
  ------------------
  |  Branch (3385:19): [True: 0, False: 0]
  |  Branch (3385:30): [True: 0, False: 0]
  ------------------
 3386|      0|									{
 3387|      0|										PUGI_IMPL_POPNODE();
  ------------------
  |  | 2646|      0|	#define PUGI_IMPL_POPNODE()             { cursor = cursor->parent; }
  ------------------
 3388|      0|										break;
 3389|      0|									}
 3390|      0|									else PUGI_IMPL_THROW_ERROR(status_bad_start_element, s);
  ------------------
  |  | 2651|      0|	#define PUGI_IMPL_THROW_ERROR(err, m)   return error_offset = m, error_status = err, static_cast<char_t*>(nullptr)
  ------------------
 3391|  10.4k|								}
 3392|  15.3k|								else if (*s == '>')
  ------------------
  |  Branch (3392:18): [True: 15.3k, False: 0]
  ------------------
 3393|  15.3k|								{
 3394|  15.3k|									++s;
 3395|       |
 3396|  15.3k|									break;
 3397|  15.3k|								}
 3398|      0|								else if (*s == 0 && endch == '>')
  ------------------
  |  Branch (3398:18): [True: 0, False: 0]
  |  Branch (3398:29): [True: 0, False: 0]
  ------------------
 3399|      0|								{
 3400|      0|									break;
 3401|      0|								}
 3402|      0|								else PUGI_IMPL_THROW_ERROR(status_bad_start_element, s);
  ------------------
  |  | 2651|      0|	#define PUGI_IMPL_THROW_ERROR(err, m)   return error_offset = m, error_status = err, static_cast<char_t*>(nullptr)
  ------------------
 3403|  73.5k|							}
 3404|       |
 3405|       |							// !!!
 3406|  25.8k|						}
 3407|      8|						else if (ch == '/') // '<#.../'
  ------------------
  |  Branch (3407:16): [True: 6, False: 2]
  ------------------
 3408|      6|						{
 3409|      6|							if (!PUGI_IMPL_ENDSWITH(*s, '>')) PUGI_IMPL_THROW_ERROR(status_bad_start_element, s);
  ------------------
  |  | 2642|      6|	#define PUGI_IMPL_ENDSWITH(c, e)        ((c) == (e) || ((c) == 0 && endch == (e)))
  |  |  ------------------
  |  |  |  Branch (2642:43): [True: 6, False: 0]
  |  |  |  Branch (2642:58): [True: 0, False: 0]
  |  |  |  Branch (2642:70): [True: 0, False: 0]
  |  |  ------------------
  ------------------
              							if (!PUGI_IMPL_ENDSWITH(*s, '>')) PUGI_IMPL_THROW_ERROR(status_bad_start_element, s);
  ------------------
  |  | 2651|      0|	#define PUGI_IMPL_THROW_ERROR(err, m)   return error_offset = m, error_status = err, static_cast<char_t*>(nullptr)
  ------------------
 3410|       |
 3411|      6|							PUGI_IMPL_POPNODE(); // Pop.
  ------------------
  |  | 2646|      6|	#define PUGI_IMPL_POPNODE()             { cursor = cursor->parent; }
  ------------------
 3412|       |
 3413|      6|							s += (*s == '>');
 3414|      6|						}
 3415|      2|						else if (ch == 0)
  ------------------
  |  Branch (3415:16): [True: 0, False: 2]
  ------------------
 3416|      0|						{
 3417|       |							// we stepped over null terminator, backtrack & handle closing tag
 3418|      0|							--s;
 3419|       |
 3420|      0|							if (endch != '>') PUGI_IMPL_THROW_ERROR(status_bad_start_element, s);
  ------------------
  |  | 2651|      0|	#define PUGI_IMPL_THROW_ERROR(err, m)   return error_offset = m, error_status = err, static_cast<char_t*>(nullptr)
  ------------------
  |  Branch (3420:12): [True: 0, False: 0]
  ------------------
 3421|      0|						}
 3422|      2|						else PUGI_IMPL_THROW_ERROR(status_bad_start_element, s);
  ------------------
  |  | 2651|      2|	#define PUGI_IMPL_THROW_ERROR(err, m)   return error_offset = m, error_status = err, static_cast<char_t*>(nullptr)
  ------------------
 3423|  48.0k|					}
 3424|  37.4k|					else if (*s == '/')
  ------------------
  |  Branch (3424:15): [True: 37.3k, False: 77]
  ------------------
 3425|  37.3k|					{
 3426|  37.3k|						++s;
 3427|       |
 3428|  37.3k|						mark = s;
 3429|       |
 3430|  37.3k|						char_t* name = cursor->name;
 3431|  37.3k|						if (!name) PUGI_IMPL_THROW_ERROR(status_end_element_mismatch, mark);
  ------------------
  |  | 2651|      0|	#define PUGI_IMPL_THROW_ERROR(err, m)   return error_offset = m, error_status = err, static_cast<char_t*>(nullptr)
  ------------------
  |  Branch (3431:11): [True: 0, False: 37.3k]
  ------------------
 3432|       |
 3433|  37.3k|						while (PUGI_IMPL_IS_CHARTYPE(*s, ct_symbol))
 3434|   198k|						{
 3435|   198k|							if (*s++ != *name++) PUGI_IMPL_THROW_ERROR(status_end_element_mismatch, mark);
  ------------------
  |  | 2651|      0|	#define PUGI_IMPL_THROW_ERROR(err, m)   return error_offset = m, error_status = err, static_cast<char_t*>(nullptr)
  ------------------
  |  Branch (3435:12): [True: 0, False: 198k]
  ------------------
 3436|   198k|						}
 3437|       |
 3438|  37.3k|						if (*name)
  ------------------
  |  Branch (3438:11): [True: 0, False: 37.3k]
  ------------------
 3439|      0|						{
 3440|      0|							if (*s == 0 && name[0] == endch && name[1] == 0) PUGI_IMPL_THROW_ERROR(status_bad_end_element, s);
  ------------------
  |  | 2651|      0|	#define PUGI_IMPL_THROW_ERROR(err, m)   return error_offset = m, error_status = err, static_cast<char_t*>(nullptr)
  ------------------
  |  Branch (3440:12): [True: 0, False: 0]
  |  Branch (3440:23): [True: 0, False: 0]
  |  Branch (3440:43): [True: 0, False: 0]
  ------------------
 3441|      0|							else PUGI_IMPL_THROW_ERROR(status_end_element_mismatch, mark);
  ------------------
  |  | 2651|      0|	#define PUGI_IMPL_THROW_ERROR(err, m)   return error_offset = m, error_status = err, static_cast<char_t*>(nullptr)
  ------------------
 3442|      0|						}
 3443|       |
 3444|  37.3k|						PUGI_IMPL_POPNODE(); // Pop.
  ------------------
  |  | 2646|  37.3k|	#define PUGI_IMPL_POPNODE()             { cursor = cursor->parent; }
  ------------------
 3445|       |
 3446|  37.3k|						PUGI_IMPL_SKIPWS();
  ------------------
  |  | 2643|  37.3k|	#define PUGI_IMPL_SKIPWS()              { while (PUGI_IMPL_IS_CHARTYPE(*s, ct_space)) ++s; }
  ------------------
 3447|       |
 3448|  37.3k|						if (*s == 0)
  ------------------
  |  Branch (3448:11): [True: 0, False: 37.3k]
  ------------------
 3449|      0|						{
 3450|      0|							if (endch != '>') PUGI_IMPL_THROW_ERROR(status_bad_end_element, s);
  ------------------
  |  | 2651|      0|	#define PUGI_IMPL_THROW_ERROR(err, m)   return error_offset = m, error_status = err, static_cast<char_t*>(nullptr)
  ------------------
  |  Branch (3450:12): [True: 0, False: 0]
  ------------------
 3451|      0|						}
 3452|  37.3k|						else
 3453|  37.3k|						{
 3454|  37.3k|							if (*s != '>') PUGI_IMPL_THROW_ERROR(status_bad_end_element, s);
  ------------------
  |  | 2651|      0|	#define PUGI_IMPL_THROW_ERROR(err, m)   return error_offset = m, error_status = err, static_cast<char_t*>(nullptr)
  ------------------
  |  Branch (3454:12): [True: 0, False: 37.3k]
  ------------------
 3455|  37.3k|							++s;
 3456|  37.3k|						}
 3457|  37.3k|					}
 3458|     77|					else if (*s == '?') // '<?...'
  ------------------
  |  Branch (3458:15): [True: 52, False: 25]
  ------------------
 3459|     52|					{
 3460|     52|						s = parse_question(s, cursor, optmsk, endch);
 3461|     52|						if (!s) return s;
  ------------------
  |  Branch (3461:11): [True: 0, False: 52]
  ------------------
 3462|       |
 3463|     52|						assert(cursor);
  ------------------
  |  Branch (3463:7): [True: 52, False: 0]
  ------------------
 3464|     52|						if (PUGI_IMPL_NODETYPE(cursor) == node_declaration) goto LOC_ATTRIBUTES;
  ------------------
  |  |  492|     52|	#define PUGI_IMPL_NODETYPE(n) static_cast<xml_node_type>((n)->header & impl::xml_memory_page_type_mask)
  ------------------
  |  Branch (3464:11): [True: 52, False: 0]
  ------------------
 3465|     52|					}
 3466|     25|					else if (*s == '!') // '<!...'
  ------------------
  |  Branch (3466:15): [True: 25, False: 0]
  ------------------
 3467|     25|					{
 3468|     25|						s = parse_exclamation(s, cursor, optmsk, endch);
 3469|     25|						if (!s) return s;
  ------------------
  |  Branch (3469:11): [True: 0, False: 25]
  ------------------
 3470|     25|					}
 3471|      0|					else if (*s == 0 && endch == '?') PUGI_IMPL_THROW_ERROR(status_bad_pi, s);
  ------------------
  |  | 2651|      0|	#define PUGI_IMPL_THROW_ERROR(err, m)   return error_offset = m, error_status = err, static_cast<char_t*>(nullptr)
  ------------------
  |  Branch (3471:15): [True: 0, False: 0]
  |  Branch (3471:26): [True: 0, False: 0]
  ------------------
 3472|      0|					else PUGI_IMPL_THROW_ERROR(status_unrecognized_tag, s);
  ------------------
  |  | 2651|      0|	#define PUGI_IMPL_THROW_ERROR(err, m)   return error_offset = m, error_status = err, static_cast<char_t*>(nullptr)
  ------------------
 3473|  85.5k|				}
 3474|  59.4k|				else
 3475|  59.4k|				{
 3476|  59.4k|					mark = s; // Save this offset while searching for a terminator.
 3477|       |
 3478|  59.4k|					PUGI_IMPL_SKIPWS(); // Eat whitespace if no genuine PCDATA here.
  ------------------
  |  | 2643|   373k|	#define PUGI_IMPL_SKIPWS()              { while (PUGI_IMPL_IS_CHARTYPE(*s, ct_space)) ++s; }
  ------------------
 3479|       |
 3480|  59.4k|					if (*s == '<' || !*s)
  ------------------
  |  Branch (3480:10): [True: 38.3k, False: 21.1k]
  |  Branch (3480:23): [True: 37, False: 21.0k]
  ------------------
 3481|  38.4k|					{
 3482|       |						// We skipped some whitespace characters because otherwise we would take the tag branch instead of PCDATA one
 3483|  38.4k|						assert(mark != s);
  ------------------
  |  Branch (3483:7): [True: 38.4k, False: 0]
  ------------------
 3484|       |
 3485|  38.4k|						if (!PUGI_IMPL_OPTSET(parse_ws_pcdata | parse_ws_pcdata_single) || PUGI_IMPL_OPTSET(parse_trim_pcdata))
  ------------------
  |  | 2644|  76.8k|	#define PUGI_IMPL_OPTSET(OPT)           ( optmsk & (OPT) )
  ------------------
              						if (!PUGI_IMPL_OPTSET(parse_ws_pcdata | parse_ws_pcdata_single) || PUGI_IMPL_OPTSET(parse_trim_pcdata))
  ------------------
  |  | 2644|      0|	#define PUGI_IMPL_OPTSET(OPT)           ( optmsk & (OPT) )
  |  |  ------------------
  |  |  |  Branch (2644:42): [True: 0, False: 0]
  |  |  ------------------
  ------------------
  |  Branch (3485:11): [True: 38.4k, False: 0]
  ------------------
 3486|  38.4k|						{
 3487|  38.4k|							continue;
 3488|  38.4k|						}
 3489|      0|						else if (PUGI_IMPL_OPTSET(parse_ws_pcdata_single))
  ------------------
  |  | 2644|      0|	#define PUGI_IMPL_OPTSET(OPT)           ( optmsk & (OPT) )
  |  |  ------------------
  |  |  |  Branch (2644:42): [True: 0, False: 0]
  |  |  ------------------
  ------------------
 3490|      0|						{
 3491|      0|							if (s[0] != '<' || s[1] != '/' || cursor->first_child) continue;
  ------------------
  |  Branch (3491:12): [True: 0, False: 0]
  |  Branch (3491:27): [True: 0, False: 0]
  |  Branch (3491:42): [True: 0, False: 0]
  ------------------
 3492|      0|						}
 3493|  38.4k|					}
 3494|       |
 3495|  21.0k|					if (!PUGI_IMPL_OPTSET(parse_trim_pcdata))
  ------------------
  |  | 2644|  21.0k|	#define PUGI_IMPL_OPTSET(OPT)           ( optmsk & (OPT) )
  ------------------
  |  Branch (3495:10): [True: 21.0k, False: 0]
  ------------------
 3496|  21.0k|						s = mark;
 3497|       |
 3498|  21.0k|					if (cursor->parent || PUGI_IMPL_OPTSET(parse_fragment))
  ------------------
  |  | 2644|      6|	#define PUGI_IMPL_OPTSET(OPT)           ( optmsk & (OPT) )
  |  |  ------------------
  |  |  |  Branch (2644:42): [True: 0, False: 6]
  |  |  ------------------
  ------------------
  |  Branch (3498:10): [True: 21.0k, False: 6]
  ------------------
 3499|  21.0k|					{
 3500|  21.0k|						char_t* parsed_pcdata = s;
 3501|       |
 3502|  21.0k|						s = strconv_pcdata(s);
 3503|       |
 3504|  21.0k|						if (PUGI_IMPL_OPTSET(parse_embed_pcdata) && cursor->parent && !cursor->first_child && !cursor->value)
  ------------------
  |  | 2644|  42.1k|	#define PUGI_IMPL_OPTSET(OPT)           ( optmsk & (OPT) )
  |  |  ------------------
  |  |  |  Branch (2644:42): [True: 0, False: 21.0k]
  |  |  ------------------
  ------------------
  |  Branch (3504:51): [True: 0, False: 0]
  |  Branch (3504:69): [True: 0, False: 0]
  |  Branch (3504:93): [True: 0, False: 0]
  ------------------
 3505|      0|						{
 3506|      0|							cursor->value = parsed_pcdata; // Save the offset.
 3507|      0|						}
 3508|  21.0k|						else if (PUGI_IMPL_OPTSET(parse_merge_pcdata) && cursor->first_child && PUGI_IMPL_NODETYPE(cursor->first_child->prev_sibling_c) == node_pcdata)
  ------------------
  |  | 2644|  42.1k|	#define PUGI_IMPL_OPTSET(OPT)           ( optmsk & (OPT) )
  |  |  ------------------
  |  |  |  Branch (2644:42): [True: 0, False: 21.0k]
  |  |  ------------------
  ------------------
              						else if (PUGI_IMPL_OPTSET(parse_merge_pcdata) && cursor->first_child && PUGI_IMPL_NODETYPE(cursor->first_child->prev_sibling_c) == node_pcdata)
  ------------------
  |  |  492|      0|	#define PUGI_IMPL_NODETYPE(n) static_cast<xml_node_type>((n)->header & impl::xml_memory_page_type_mask)
  ------------------
  |  Branch (3508:56): [True: 0, False: 0]
  |  Branch (3508:79): [True: 0, False: 0]
  ------------------
 3509|      0|						{
 3510|      0|							assert(merged_pcdata >= cursor->first_child->prev_sibling_c->value);
  ------------------
  |  Branch (3510:8): [True: 0, False: 0]
  ------------------
 3511|       |
 3512|       |							// Catch up to the end of last parsed value; only needed for the first fragment.
 3513|      0|							merged_pcdata += strlength(merged_pcdata);
 3514|       |
 3515|      0|							size_t length = strlength(parsed_pcdata);
 3516|       |
 3517|       |							// Must use memmove instead of memcpy as this move may overlap
 3518|      0|							memmove(merged_pcdata, parsed_pcdata, (length + 1) * sizeof(char_t));
 3519|      0|							merged_pcdata += length;
 3520|      0|						}
 3521|  21.0k|						else
 3522|  21.0k|						{
 3523|  21.0k|							xml_node_struct* prev_cursor = cursor;
 3524|  21.0k|							PUGI_IMPL_PUSHNODE(node_pcdata); // Append a new node on the tree.
  ------------------
  |  | 2645|  21.0k|	#define PUGI_IMPL_PUSHNODE(TYPE)        { cursor = append_new_node(cursor, *alloc, TYPE); if (!cursor) PUGI_IMPL_THROW_ERROR(status_out_of_memory, s); }
  |  |  ------------------
  |  |  |  | 2651|      0|	#define PUGI_IMPL_THROW_ERROR(err, m)   return error_offset = m, error_status = err, static_cast<char_t*>(nullptr)
  |  |  ------------------
  |  |  |  Branch (2645:96): [True: 0, False: 21.0k]
  |  |  ------------------
  ------------------
 3525|       |
 3526|  21.0k|							cursor->value = parsed_pcdata; // Save the offset.
 3527|  21.0k|							merged_pcdata = parsed_pcdata; // Used for parse_merge_pcdata above, cheaper to save unconditionally
 3528|       |
 3529|  21.0k|							cursor = prev_cursor; // Pop since this is a standalone.
 3530|  21.0k|						}
 3531|       |
 3532|  21.0k|						if (!*s) break;
  ------------------
  |  Branch (3532:11): [True: 5, False: 21.0k]
  ------------------
 3533|  21.0k|					}
 3534|      6|					else
 3535|      6|					{
 3536|      6|						PUGI_IMPL_SCANFOR(*s == '<'); // '...<'
  ------------------
  |  | 2647|    653|	#define PUGI_IMPL_SCANFOR(X)            { while (*s != 0 && !(X)) ++s; }
  |  |  ------------------
  |  |  |  Branch (2647:51): [True: 653, False: 0]
  |  |  |  Branch (2647:62): [True: 647, False: 6]
  |  |  ------------------
  ------------------
 3537|      6|						if (!*s) break;
  ------------------
  |  Branch (3537:11): [True: 0, False: 6]
  ------------------
 3538|       |
 3539|      6|						++s;
 3540|      6|					}
 3541|       |
 3542|       |					// We're after '<'
 3543|  21.0k|					goto LOC_TAG;
 3544|  21.0k|				}
 3545|   123k|			}
 3546|       |
 3547|       |			// check that last tag is closed
 3548|     54|			if (cursor != root) PUGI_IMPL_THROW_ERROR(status_end_element_mismatch, s);
  ------------------
  |  | 2651|      5|	#define PUGI_IMPL_THROW_ERROR(err, m)   return error_offset = m, error_status = err, static_cast<char_t*>(nullptr)
  ------------------
  |  Branch (3548:8): [True: 5, False: 49]
  ------------------
 3549|       |
 3550|     49|			return s;
 3551|     54|		}
pugixml.cpp:_ZN4pugi4impl12_GLOBAL__N_121get_strconv_attributeEj:
 2933|     60|	{
 2934|     60|		PUGI_IMPL_STATIC_ASSERT(parse_escapes == 0x10 && parse_eol == 0x20 && parse_wconv_attribute == 0x40 && parse_wnorm_attribute == 0x80);
  ------------------
  |  |  110|     60|#define PUGI_IMPL_STATIC_ASSERT(cond) { static const char condition_failed[(cond) ? 1 : -1] = {0}; (void)condition_failed[0]; }
  ------------------
 2935|       |
 2936|     60|		switch ((optmask >> 4) & 15) // get bitmask for flags (wnorm wconv eol escapes); this simultaneously checks 4 options from assertion above
 2937|     60|		{
 2938|      0|		case 0:  return strconv_attribute_impl<opt_false>::parse_simple;
  ------------------
  |  Branch (2938:3): [True: 0, False: 60]
  ------------------
 2939|      0|		case 1:  return strconv_attribute_impl<opt_true>::parse_simple;
  ------------------
  |  Branch (2939:3): [True: 0, False: 60]
  ------------------
 2940|      0|		case 2:  return strconv_attribute_impl<opt_false>::parse_eol;
  ------------------
  |  Branch (2940:3): [True: 0, False: 60]
  ------------------
 2941|      0|		case 3:  return strconv_attribute_impl<opt_true>::parse_eol;
  ------------------
  |  Branch (2941:3): [True: 0, False: 60]
  ------------------
 2942|      0|		case 4:  return strconv_attribute_impl<opt_false>::parse_wconv;
  ------------------
  |  Branch (2942:3): [True: 0, False: 60]
  ------------------
 2943|      0|		case 5:  return strconv_attribute_impl<opt_true>::parse_wconv;
  ------------------
  |  Branch (2943:3): [True: 0, False: 60]
  ------------------
 2944|      0|		case 6:  return strconv_attribute_impl<opt_false>::parse_wconv;
  ------------------
  |  Branch (2944:3): [True: 0, False: 60]
  ------------------
 2945|     60|		case 7:  return strconv_attribute_impl<opt_true>::parse_wconv;
  ------------------
  |  Branch (2945:3): [True: 60, False: 0]
  ------------------
 2946|      0|		case 8:  return strconv_attribute_impl<opt_false>::parse_wnorm;
  ------------------
  |  Branch (2946:3): [True: 0, False: 60]
  ------------------
 2947|      0|		case 9:  return strconv_attribute_impl<opt_true>::parse_wnorm;
  ------------------
  |  Branch (2947:3): [True: 0, False: 60]
  ------------------
 2948|      0|		case 10: return strconv_attribute_impl<opt_false>::parse_wnorm;
  ------------------
  |  Branch (2948:3): [True: 0, False: 60]
  ------------------
 2949|      0|		case 11: return strconv_attribute_impl<opt_true>::parse_wnorm;
  ------------------
  |  Branch (2949:3): [True: 0, False: 60]
  ------------------
 2950|      0|		case 12: return strconv_attribute_impl<opt_false>::parse_wnorm;
  ------------------
  |  Branch (2950:3): [True: 0, False: 60]
  ------------------
 2951|      0|		case 13: return strconv_attribute_impl<opt_true>::parse_wnorm;
  ------------------
  |  Branch (2951:3): [True: 0, False: 60]
  ------------------
 2952|      0|		case 14: return strconv_attribute_impl<opt_false>::parse_wnorm;
  ------------------
  |  Branch (2952:3): [True: 0, False: 60]
  ------------------
 2953|      0|		case 15: return strconv_attribute_impl<opt_true>::parse_wnorm;
  ------------------
  |  Branch (2953:3): [True: 0, False: 60]
  ------------------
 2954|      0|		default: assert(false); return nullptr; // unreachable
  ------------------
  |  Branch (2954:3): [True: 0, False: 60]
  |  Branch (2954:12): [Folded, False: 0]
  ------------------
 2955|     60|		}
 2956|     60|	}
pugixml.cpp:_ZN4pugi4impl12_GLOBAL__N_13gapC2Ev:
 2464|  68.8k|		gap(): end(nullptr), size(0)
 2465|  68.8k|		{
 2466|  68.8k|		}
pugixml.cpp:_ZN4pugi4impl12_GLOBAL__N_13gap5flushEPc:
 2488|  68.8k|		{
 2489|  68.8k|			if (end)
  ------------------
  |  Branch (2489:8): [True: 230, False: 68.5k]
  ------------------
 2490|    230|			{
 2491|       |				// Move [old_gap_end, current_pos) to [old_gap_start, ...)
 2492|    230|				assert(s >= end);
  ------------------
  |  Branch (2492:5): [True: 230, False: 0]
  ------------------
 2493|    230|				memmove(end - size, end, (s - end) * sizeof(char_t));
 2494|       |
 2495|    230|				return s - size;
 2496|    230|			}
 2497|  68.5k|			else return s;
 2498|  68.8k|		}
pugixml.cpp:_ZN4pugi4impl12_GLOBAL__N_114strconv_escapeEPcRNS1_3gapE:
 2502|  1.26k|	{
 2503|  1.26k|		char_t* stre = s + 1;
 2504|       |
 2505|  1.26k|		switch (*stre)
 2506|  1.26k|		{
 2507|    395|			case '#':	// &#...
  ------------------
  |  Branch (2507:4): [True: 395, False: 866]
  ------------------
 2508|    395|			{
 2509|    395|				unsigned int ucsc = 0;
 2510|       |
 2511|    395|				if (stre[1] == 'x') // &#x... (hex code)
  ------------------
  |  Branch (2511:9): [True: 5, False: 390]
  ------------------
 2512|      5|				{
 2513|      5|					stre += 2;
 2514|       |
 2515|      5|					char_t ch = *stre;
 2516|       |
 2517|      5|					if (ch == ';') return stre;
  ------------------
  |  Branch (2517:10): [True: 0, False: 5]
  ------------------
 2518|       |
 2519|      5|					for (;;)
 2520|     15|					{
 2521|     15|						if (static_cast<unsigned int>(ch - '0') <= 9)
  ------------------
  |  Branch (2521:11): [True: 0, False: 15]
  ------------------
 2522|      0|							ucsc = 16 * ucsc + (ch - '0');
 2523|     15|						else if (static_cast<unsigned int>((ch | ' ') - 'a') <= 5)
  ------------------
  |  Branch (2523:16): [True: 10, False: 5]
  ------------------
 2524|     10|							ucsc = 16 * ucsc + ((ch | ' ') - 'a' + 10);
 2525|      5|						else if (ch == ';')
  ------------------
  |  Branch (2525:16): [True: 5, False: 0]
  ------------------
 2526|      5|							break;
 2527|      0|						else // cancel
 2528|      0|							return stre;
 2529|       |
 2530|     10|						ch = *++stre;
 2531|     10|					}
 2532|       |
 2533|      5|					++stre;
 2534|      5|				}
 2535|    390|				else	// &#... (dec code)
 2536|    390|				{
 2537|    390|					char_t ch = *++stre;
 2538|       |
 2539|    390|					if (ch == ';') return stre;
  ------------------
  |  Branch (2539:10): [True: 0, False: 390]
  ------------------
 2540|       |
 2541|    390|					for (;;)
 2542|    910|					{
 2543|    910|						if (static_cast<unsigned int>(ch - '0') <= 9)
  ------------------
  |  Branch (2543:11): [True: 520, False: 390]
  ------------------
 2544|    520|							ucsc = 10 * ucsc + (ch - '0');
 2545|    390|						else if (ch == ';')
  ------------------
  |  Branch (2545:16): [True: 260, False: 130]
  ------------------
 2546|    260|							break;
 2547|    130|						else // cancel
 2548|    130|							return stre;
 2549|       |
 2550|    520|						ch = *++stre;
 2551|    520|					}
 2552|       |
 2553|    260|					++stre;
 2554|    260|				}
 2555|       |
 2556|       |			#ifdef PUGIXML_WCHAR_MODE
 2557|       |				s = reinterpret_cast<char_t*>(wchar_writer::any(reinterpret_cast<wchar_writer::value_type>(s), ucsc));
 2558|       |			#else
 2559|    265|				s = reinterpret_cast<char_t*>(utf8_writer::any(reinterpret_cast<uint8_t*>(s), ucsc));
 2560|    265|			#endif
 2561|       |
 2562|    265|				g.push(s, stre - s);
 2563|    265|				return stre;
 2564|    395|			}
 2565|       |
 2566|      0|			case 'a':	// &a
  ------------------
  |  Branch (2566:4): [True: 0, False: 1.26k]
  ------------------
 2567|      0|			{
 2568|      0|				++stre;
 2569|       |
 2570|      0|				if (*stre == 'm') // &am
  ------------------
  |  Branch (2570:9): [True: 0, False: 0]
  ------------------
 2571|      0|				{
 2572|      0|					if (*++stre == 'p' && *++stre == ';') // &amp;
  ------------------
  |  Branch (2572:10): [True: 0, False: 0]
  |  Branch (2572:28): [True: 0, False: 0]
  ------------------
 2573|      0|					{
 2574|      0|						*s++ = '&';
 2575|      0|						++stre;
 2576|       |
 2577|      0|						g.push(s, stre - s);
 2578|      0|						return stre;
 2579|      0|					}
 2580|      0|				}
 2581|      0|				else if (*stre == 'p') // &ap
  ------------------
  |  Branch (2581:14): [True: 0, False: 0]
  ------------------
 2582|      0|				{
 2583|      0|					if (*++stre == 'o' && *++stre == 's' && *++stre == ';') // &apos;
  ------------------
  |  Branch (2583:10): [True: 0, False: 0]
  |  Branch (2583:28): [True: 0, False: 0]
  |  Branch (2583:46): [True: 0, False: 0]
  ------------------
 2584|      0|					{
 2585|      0|						*s++ = '\'';
 2586|      0|						++stre;
 2587|       |
 2588|      0|						g.push(s, stre - s);
 2589|      0|						return stre;
 2590|      0|					}
 2591|      0|				}
 2592|      0|				break;
 2593|      0|			}
 2594|       |
 2595|      0|			case 'g': // &g
  ------------------
  |  Branch (2595:4): [True: 0, False: 1.26k]
  ------------------
 2596|      0|			{
 2597|      0|				if (*++stre == 't' && *++stre == ';') // &gt;
  ------------------
  |  Branch (2597:9): [True: 0, False: 0]
  |  Branch (2597:27): [True: 0, False: 0]
  ------------------
 2598|      0|				{
 2599|      0|					*s++ = '>';
 2600|      0|					++stre;
 2601|       |
 2602|      0|					g.push(s, stre - s);
 2603|      0|					return stre;
 2604|      0|				}
 2605|      0|				break;
 2606|      0|			}
 2607|       |
 2608|    790|			case 'l': // &l
  ------------------
  |  Branch (2608:4): [True: 790, False: 471]
  ------------------
 2609|    790|			{
 2610|    790|				if (*++stre == 't' && *++stre == ';') // &lt;
  ------------------
  |  Branch (2610:9): [True: 595, False: 195]
  |  Branch (2610:27): [True: 275, False: 320]
  ------------------
 2611|    275|				{
 2612|    275|					*s++ = '<';
 2613|    275|					++stre;
 2614|       |
 2615|    275|					g.push(s, stre - s);
 2616|    275|					return stre;
 2617|    275|				}
 2618|    515|				break;
 2619|    790|			}
 2620|       |
 2621|    515|			case 'q': // &q
  ------------------
  |  Branch (2621:4): [True: 36, False: 1.22k]
  ------------------
 2622|     36|			{
 2623|     36|				if (*++stre == 'u' && *++stre == 'o' && *++stre == 't' && *++stre == ';') // &quot;
  ------------------
  |  Branch (2623:9): [True: 36, False: 0]
  |  Branch (2623:27): [True: 36, False: 0]
  |  Branch (2623:45): [True: 36, False: 0]
  |  Branch (2623:63): [True: 36, False: 0]
  ------------------
 2624|     36|				{
 2625|     36|					*s++ = '"';
 2626|     36|					++stre;
 2627|       |
 2628|     36|					g.push(s, stre - s);
 2629|     36|					return stre;
 2630|     36|				}
 2631|      0|				break;
 2632|     36|			}
 2633|       |
 2634|     40|			default:
  ------------------
  |  Branch (2634:4): [True: 40, False: 1.22k]
  ------------------
 2635|     40|				break;
 2636|  1.26k|		}
 2637|       |
 2638|    555|		return stre;
 2639|  1.26k|	}
pugixml.cpp:_ZN4pugi4impl12_GLOBAL__N_111utf8_writer3anyEPhj:
 1562|    265|		{
 1563|    265|			return (ch < 0x10000) ? low(result, ch) : high(result, ch);
  ------------------
  |  Branch (1563:11): [True: 265, False: 0]
  ------------------
 1564|    265|		}
pugixml.cpp:_ZN4pugi4impl12_GLOBAL__N_13gap4pushERPcm:
 2471|  3.22k|		{
 2472|  3.22k|			if (end) // there was a gap already; collapse it
  ------------------
  |  Branch (2472:8): [True: 2.99k, False: 230]
  ------------------
 2473|  2.99k|			{
 2474|       |				// Move [old_gap_end, new_gap_start) to [old_gap_start, ...)
 2475|  2.99k|				assert(s >= end);
  ------------------
  |  Branch (2475:5): [True: 2.99k, False: 0]
  ------------------
 2476|  2.99k|				memmove(end - size, end, (s - end) * sizeof(char_t));
 2477|  2.99k|			}
 2478|       |
 2479|  3.22k|			s += count; // end of current gap
 2480|       |
 2481|       |			// "merge" two gaps
 2482|  3.22k|			end = s;
 2483|  3.22k|			size += count;
 2484|  3.22k|		}
pugixml.cpp:_ZN4pugi4impl12_GLOBAL__N_122strconv_attribute_implINS1_8opt_trueEE11parse_wconvEPcc:
 2838|  47.7k|		{
 2839|  47.7k|			gap g;
 2840|       |
 2841|  54.1k|			while (true)
  ------------------
  |  Branch (2841:11): [True: 54.1k, Folded]
  ------------------
 2842|  54.1k|			{
 2843|  54.1k|				PUGI_IMPL_SCANWHILE_UNROLL(!PUGI_IMPL_IS_CHARTYPE(ss, ct_parse_attr_ws));
  ------------------
  |  | 2649|   185k|	#define PUGI_IMPL_SCANWHILE_UNROLL(X)   { for (;;) { char_t ss = s[0]; if (PUGI_IMPL_UNLIKELY(!(X))) { break; } ss = s[1]; if (PUGI_IMPL_UNLIKELY(!(X))) { s += 1; break; } ss = s[2]; if (PUGI_IMPL_UNLIKELY(!(X))) { s += 2; break; } ss = s[3]; if (PUGI_IMPL_UNLIKELY(!(X))) { s += 3; break; } s += 4; } }
  |  |  ------------------
  |  |  |  |  104|   185k|#	define PUGI_IMPL_UNLIKELY(cond) __builtin_expect(cond, 0)
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (104:35): [True: 17.6k, False: 167k]
  |  |  |  |  ------------------
  |  |  ------------------
  |  |               	#define PUGI_IMPL_SCANWHILE_UNROLL(X)   { for (;;) { char_t ss = s[0]; if (PUGI_IMPL_UNLIKELY(!(X))) { break; } ss = s[1]; if (PUGI_IMPL_UNLIKELY(!(X))) { s += 1; break; } ss = s[2]; if (PUGI_IMPL_UNLIKELY(!(X))) { s += 2; break; } ss = s[3]; if (PUGI_IMPL_UNLIKELY(!(X))) { s += 3; break; } s += 4; } }
  |  |  ------------------
  |  |  |  |  104|   167k|#	define PUGI_IMPL_UNLIKELY(cond) __builtin_expect(cond, 0)
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (104:35): [True: 20.3k, False: 147k]
  |  |  |  |  ------------------
  |  |  ------------------
  |  |               	#define PUGI_IMPL_SCANWHILE_UNROLL(X)   { for (;;) { char_t ss = s[0]; if (PUGI_IMPL_UNLIKELY(!(X))) { break; } ss = s[1]; if (PUGI_IMPL_UNLIKELY(!(X))) { s += 1; break; } ss = s[2]; if (PUGI_IMPL_UNLIKELY(!(X))) { s += 2; break; } ss = s[3]; if (PUGI_IMPL_UNLIKELY(!(X))) { s += 3; break; } s += 4; } }
  |  |  ------------------
  |  |  |  |  104|   147k|#	define PUGI_IMPL_UNLIKELY(cond) __builtin_expect(cond, 0)
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (104:35): [True: 8.48k, False: 138k]
  |  |  |  |  ------------------
  |  |  ------------------
  |  |               	#define PUGI_IMPL_SCANWHILE_UNROLL(X)   { for (;;) { char_t ss = s[0]; if (PUGI_IMPL_UNLIKELY(!(X))) { break; } ss = s[1]; if (PUGI_IMPL_UNLIKELY(!(X))) { s += 1; break; } ss = s[2]; if (PUGI_IMPL_UNLIKELY(!(X))) { s += 2; break; } ss = s[3]; if (PUGI_IMPL_UNLIKELY(!(X))) { s += 3; break; } s += 4; } }
  |  |  ------------------
  |  |  |  |  104|   138k|#	define PUGI_IMPL_UNLIKELY(cond) __builtin_expect(cond, 0)
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (104:35): [True: 7.69k, False: 130k]
  |  |  |  |  ------------------
  |  |  ------------------
  ------------------
 2844|       |
 2845|  54.1k|				if (*s == end_quote)
  ------------------
  |  Branch (2845:9): [True: 47.7k, False: 6.39k]
  ------------------
 2846|  47.7k|				{
 2847|  47.7k|					*g.flush(s) = 0;
 2848|       |
 2849|  47.7k|					return s + 1;
 2850|  47.7k|				}
 2851|  6.39k|				else if (PUGI_IMPL_IS_CHARTYPE(*s, ct_space))
  ------------------
  |  | 1951|  6.39k|	#define PUGI_IMPL_IS_CHARTYPE(c, ct) PUGI_IMPL_IS_CHARTYPE_IMPL(c, ct, chartype_table)
  |  |  ------------------
  |  |  |  | 1948|  6.39k|	#define PUGI_IMPL_IS_CHARTYPE_IMPL(c, ct, table) (table[static_cast<unsigned char>(c)] & (ct))
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (1948:51): [True: 3.57k, False: 2.82k]
  |  |  |  |  ------------------
  |  |  ------------------
  ------------------
 2852|  3.57k|				{
 2853|  3.57k|					if (*s == '\r')
  ------------------
  |  Branch (2853:10): [True: 782, False: 2.78k]
  ------------------
 2854|    782|					{
 2855|    782|						*s++ = ' ';
 2856|       |
 2857|    782|						if (*s == '\n') g.push(s, 1);
  ------------------
  |  Branch (2857:11): [True: 782, False: 0]
  ------------------
 2858|    782|					}
 2859|  2.78k|					else *s++ = ' ';
 2860|  3.57k|				}
 2861|  2.82k|				else if (opt_escape::value && *s == '&')
  ------------------
  |  Branch (2861:14): [True: 2.82k, Folded]
  |  Branch (2861:35): [True: 5, False: 2.82k]
  ------------------
 2862|      5|				{
 2863|      5|					s = strconv_escape(s, g);
 2864|      5|				}
 2865|  2.82k|				else if (!*s)
  ------------------
  |  Branch (2865:14): [True: 0, False: 2.82k]
  ------------------
 2866|      0|				{
 2867|      0|					return nullptr;
 2868|      0|				}
 2869|  2.82k|				else ++s;
 2870|  54.1k|			}
 2871|  47.7k|		}
pugixml.cpp:_ZN4pugi4impl12_GLOBAL__N_118get_strconv_pcdataEj:
 2764|     60|	{
 2765|     60|		PUGI_IMPL_STATIC_ASSERT(parse_escapes == 0x10 && parse_eol == 0x20 && parse_trim_pcdata == 0x0800);
  ------------------
  |  |  110|     60|#define PUGI_IMPL_STATIC_ASSERT(cond) { static const char condition_failed[(cond) ? 1 : -1] = {0}; (void)condition_failed[0]; }
  ------------------
 2766|       |
 2767|     60|		switch (((optmask >> 4) & 3) | ((optmask >> 9) & 4)) // get bitmask for flags (trim eol escapes); this simultaneously checks 3 options from assertion above
 2768|     60|		{
 2769|      0|		case 0: return strconv_pcdata_impl<opt_false, opt_false, opt_false>::parse;
  ------------------
  |  Branch (2769:3): [True: 0, False: 60]
  ------------------
 2770|      0|		case 1: return strconv_pcdata_impl<opt_false, opt_false, opt_true>::parse;
  ------------------
  |  Branch (2770:3): [True: 0, False: 60]
  ------------------
 2771|      0|		case 2: return strconv_pcdata_impl<opt_false, opt_true, opt_false>::parse;
  ------------------
  |  Branch (2771:3): [True: 0, False: 60]
  ------------------
 2772|     60|		case 3: return strconv_pcdata_impl<opt_false, opt_true, opt_true>::parse;
  ------------------
  |  Branch (2772:3): [True: 60, False: 0]
  ------------------
 2773|      0|		case 4: return strconv_pcdata_impl<opt_true, opt_false, opt_false>::parse;
  ------------------
  |  Branch (2773:3): [True: 0, False: 60]
  ------------------
 2774|      0|		case 5: return strconv_pcdata_impl<opt_true, opt_false, opt_true>::parse;
  ------------------
  |  Branch (2774:3): [True: 0, False: 60]
  ------------------
 2775|      0|		case 6: return strconv_pcdata_impl<opt_true, opt_true, opt_false>::parse;
  ------------------
  |  Branch (2775:3): [True: 0, False: 60]
  ------------------
 2776|      0|		case 7: return strconv_pcdata_impl<opt_true, opt_true, opt_true>::parse;
  ------------------
  |  Branch (2776:3): [True: 0, False: 60]
  ------------------
 2777|      0|		default: assert(false); return nullptr; // unreachable
  ------------------
  |  Branch (2777:3): [True: 0, False: 60]
  |  Branch (2777:12): [Folded, False: 0]
  ------------------
 2778|     60|		}
 2779|     60|	}
pugixml.cpp:_ZN4pugi4impl12_GLOBAL__N_119strconv_pcdata_implINS1_9opt_falseENS1_8opt_trueES4_E5parseEPc:
 2715|  21.0k|		{
 2716|  21.0k|			gap g;
 2717|       |
 2718|  21.0k|			char_t* begin = s;
 2719|       |
 2720|  25.6k|			while (true)
  ------------------
  |  Branch (2720:11): [True: 25.6k, Folded]
  ------------------
 2721|  25.6k|			{
 2722|  25.6k|				PUGI_IMPL_SCANWHILE_UNROLL(!PUGI_IMPL_IS_CHARTYPE(ss, ct_parse_pcdata));
  ------------------
  |  | 2649|  1.57M|	#define PUGI_IMPL_SCANWHILE_UNROLL(X)   { for (;;) { char_t ss = s[0]; if (PUGI_IMPL_UNLIKELY(!(X))) { break; } ss = s[1]; if (PUGI_IMPL_UNLIKELY(!(X))) { s += 1; break; } ss = s[2]; if (PUGI_IMPL_UNLIKELY(!(X))) { s += 2; break; } ss = s[3]; if (PUGI_IMPL_UNLIKELY(!(X))) { s += 3; break; } s += 4; } }
  |  |  ------------------
  |  |  |  |  104|  1.57M|#	define PUGI_IMPL_UNLIKELY(cond) __builtin_expect(cond, 0)
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (104:35): [True: 2.90k, False: 1.57M]
  |  |  |  |  ------------------
  |  |  ------------------
  |  |               	#define PUGI_IMPL_SCANWHILE_UNROLL(X)   { for (;;) { char_t ss = s[0]; if (PUGI_IMPL_UNLIKELY(!(X))) { break; } ss = s[1]; if (PUGI_IMPL_UNLIKELY(!(X))) { s += 1; break; } ss = s[2]; if (PUGI_IMPL_UNLIKELY(!(X))) { s += 2; break; } ss = s[3]; if (PUGI_IMPL_UNLIKELY(!(X))) { s += 3; break; } s += 4; } }
  |  |  ------------------
  |  |  |  |  104|  1.57M|#	define PUGI_IMPL_UNLIKELY(cond) __builtin_expect(cond, 0)
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (104:35): [True: 4.85k, False: 1.56M]
  |  |  |  |  ------------------
  |  |  ------------------
  |  |               	#define PUGI_IMPL_SCANWHILE_UNROLL(X)   { for (;;) { char_t ss = s[0]; if (PUGI_IMPL_UNLIKELY(!(X))) { break; } ss = s[1]; if (PUGI_IMPL_UNLIKELY(!(X))) { s += 1; break; } ss = s[2]; if (PUGI_IMPL_UNLIKELY(!(X))) { s += 2; break; } ss = s[3]; if (PUGI_IMPL_UNLIKELY(!(X))) { s += 3; break; } s += 4; } }
  |  |  ------------------
  |  |  |  |  104|  1.56M|#	define PUGI_IMPL_UNLIKELY(cond) __builtin_expect(cond, 0)
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (104:35): [True: 13.0k, False: 1.55M]
  |  |  |  |  ------------------
  |  |  ------------------
  |  |               	#define PUGI_IMPL_SCANWHILE_UNROLL(X)   { for (;;) { char_t ss = s[0]; if (PUGI_IMPL_UNLIKELY(!(X))) { break; } ss = s[1]; if (PUGI_IMPL_UNLIKELY(!(X))) { s += 1; break; } ss = s[2]; if (PUGI_IMPL_UNLIKELY(!(X))) { s += 2; break; } ss = s[3]; if (PUGI_IMPL_UNLIKELY(!(X))) { s += 3; break; } s += 4; } }
  |  |  ------------------
  |  |  |  |  104|  1.55M|#	define PUGI_IMPL_UNLIKELY(cond) __builtin_expect(cond, 0)
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (104:35): [True: 4.93k, False: 1.55M]
  |  |  |  |  ------------------
  |  |  ------------------
  ------------------
 2723|       |
 2724|  25.6k|				if (*s == '<') // PCDATA ends here
  ------------------
  |  Branch (2724:9): [True: 21.0k, False: 4.63k]
  ------------------
 2725|  21.0k|				{
 2726|  21.0k|					char_t* end = g.flush(s);
 2727|       |
 2728|  21.0k|					if (opt_trim::value)
  ------------------
  |  Branch (2728:10): [Folded, False: 21.0k]
  ------------------
 2729|      0|						while (end > begin && PUGI_IMPL_IS_CHARTYPE(end[-1], ct_space))
  ------------------
  |  | 1951|      0|	#define PUGI_IMPL_IS_CHARTYPE(c, ct) PUGI_IMPL_IS_CHARTYPE_IMPL(c, ct, chartype_table)
  |  |  ------------------
  |  |  |  | 1948|      0|	#define PUGI_IMPL_IS_CHARTYPE_IMPL(c, ct, table) (table[static_cast<unsigned char>(c)] & (ct))
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (1948:51): [True: 0, False: 0]
  |  |  |  |  ------------------
  |  |  ------------------
  ------------------
  |  Branch (2729:14): [True: 0, False: 0]
  ------------------
 2730|      0|							--end;
 2731|       |
 2732|  21.0k|					*end = 0;
 2733|       |
 2734|  21.0k|					return s + 1;
 2735|  21.0k|				}
 2736|  4.63k|				else if (opt_eol::value && *s == '\r') // Either a single 0x0d or 0x0d 0x0a pair
  ------------------
  |  Branch (2736:14): [True: 4.63k, Folded]
  |  Branch (2736:32): [True: 3.37k, False: 1.26k]
  ------------------
 2737|  3.37k|				{
 2738|  3.37k|					*s++ = '\n'; // replace first one with 0x0a
 2739|       |
 2740|  3.37k|					if (*s == '\n') g.push(s, 1);
  ------------------
  |  Branch (2740:10): [True: 1.86k, False: 1.51k]
  ------------------
 2741|  3.37k|				}
 2742|  1.26k|				else if (opt_escape::value && *s == '&')
  ------------------
  |  Branch (2742:14): [True: 1.26k, Folded]
  |  Branch (2742:35): [True: 1.25k, False: 5]
  ------------------
 2743|  1.25k|				{
 2744|  1.25k|					s = strconv_escape(s, g);
 2745|  1.25k|				}
 2746|      5|				else if (*s == 0)
  ------------------
  |  Branch (2746:14): [True: 5, False: 0]
  ------------------
 2747|      5|				{
 2748|      5|					char_t* end = g.flush(s);
 2749|       |
 2750|      5|					if (opt_trim::value)
  ------------------
  |  Branch (2750:10): [Folded, False: 5]
  ------------------
 2751|      0|						while (end > begin && PUGI_IMPL_IS_CHARTYPE(end[-1], ct_space))
  ------------------
  |  | 1951|      0|	#define PUGI_IMPL_IS_CHARTYPE(c, ct) PUGI_IMPL_IS_CHARTYPE_IMPL(c, ct, chartype_table)
  |  |  ------------------
  |  |  |  | 1948|      0|	#define PUGI_IMPL_IS_CHARTYPE_IMPL(c, ct, table) (table[static_cast<unsigned char>(c)] & (ct))
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (1948:51): [True: 0, False: 0]
  |  |  |  |  ------------------
  |  |  ------------------
  ------------------
  |  Branch (2751:14): [True: 0, False: 0]
  ------------------
 2752|      0|							--end;
 2753|       |
 2754|      5|					*end = 0;
 2755|       |
 2756|      5|					return s;
 2757|      5|				}
 2758|      0|				else ++s;
 2759|  25.6k|			}
 2760|  21.0k|		}
pugixml.cpp:_ZN4pugi4impl12_GLOBAL__N_110xml_parser14parse_questionEPcRPNS_15xml_node_structEjc:
 3204|     52|		{
 3205|       |			// load into registers
 3206|     52|			xml_node_struct* cursor = ref_cursor;
 3207|     52|			char_t ch = 0;
 3208|       |
 3209|       |			// parse node contents, starting with question mark
 3210|     52|			++s;
 3211|       |
 3212|       |			// read PI target
 3213|     52|			char_t* target = s;
 3214|       |
 3215|     52|			if (!PUGI_IMPL_IS_CHARTYPE(*s, ct_start_symbol)) PUGI_IMPL_THROW_ERROR(status_bad_pi, s);
  ------------------
  |  | 1951|     52|	#define PUGI_IMPL_IS_CHARTYPE(c, ct) PUGI_IMPL_IS_CHARTYPE_IMPL(c, ct, chartype_table)
  |  |  ------------------
  |  |  |  | 1948|     52|	#define PUGI_IMPL_IS_CHARTYPE_IMPL(c, ct, table) (table[static_cast<unsigned char>(c)] & (ct))
  |  |  ------------------
  ------------------
              			if (!PUGI_IMPL_IS_CHARTYPE(*s, ct_start_symbol)) PUGI_IMPL_THROW_ERROR(status_bad_pi, s);
  ------------------
  |  | 2651|      0|	#define PUGI_IMPL_THROW_ERROR(err, m)   return error_offset = m, error_status = err, static_cast<char_t*>(nullptr)
  ------------------
  |  Branch (3215:8): [True: 0, False: 52]
  ------------------
 3216|       |
 3217|     52|			PUGI_IMPL_SCANWHILE(PUGI_IMPL_IS_CHARTYPE(*s, ct_symbol));
  ------------------
  |  | 2648|    208|	#define PUGI_IMPL_SCANWHILE(X)          { while (X) ++s; }
  |  |  ------------------
  |  |  |  Branch (2648:51): [True: 156, False: 52]
  |  |  ------------------
  ------------------
 3218|     52|			PUGI_IMPL_CHECK_ERROR(status_bad_pi, s);
  ------------------
  |  | 2652|     52|	#define PUGI_IMPL_CHECK_ERROR(err, m)   { if (*s == 0) PUGI_IMPL_THROW_ERROR(err, m); }
  |  |  ------------------
  |  |  |  | 2651|      0|	#define PUGI_IMPL_THROW_ERROR(err, m)   return error_offset = m, error_status = err, static_cast<char_t*>(nullptr)
  |  |  ------------------
  |  |  |  Branch (2652:48): [True: 0, False: 52]
  |  |  ------------------
  ------------------
 3219|       |
 3220|       |			// determine node type; stricmp / strcasecmp is not portable
 3221|     52|			bool declaration = (target[0] | ' ') == 'x' && (target[1] | ' ') == 'm' && (target[2] | ' ') == 'l' && target + 3 == s;
  ------------------
  |  Branch (3221:23): [True: 52, False: 0]
  |  Branch (3221:51): [True: 52, False: 0]
  |  Branch (3221:79): [True: 52, False: 0]
  |  Branch (3221:107): [True: 52, False: 0]
  ------------------
 3222|       |
 3223|     52|			if (declaration ? PUGI_IMPL_OPTSET(parse_declaration) : PUGI_IMPL_OPTSET(parse_pi))
  ------------------
  |  | 2644|     52|	#define PUGI_IMPL_OPTSET(OPT)           ( optmsk & (OPT) )
  ------------------
              			if (declaration ? PUGI_IMPL_OPTSET(parse_declaration) : PUGI_IMPL_OPTSET(parse_pi))
  ------------------
  |  | 2644|      0|	#define PUGI_IMPL_OPTSET(OPT)           ( optmsk & (OPT) )
  ------------------
  |  Branch (3223:8): [True: 52, False: 0]
  |  Branch (3223:8): [True: 52, False: 0]
  ------------------
 3224|     52|			{
 3225|     52|				if (declaration)
  ------------------
  |  Branch (3225:9): [True: 52, False: 0]
  ------------------
 3226|     52|				{
 3227|       |					// disallow non top-level declarations
 3228|     52|					if (cursor->parent) PUGI_IMPL_THROW_ERROR(status_bad_pi, s);
  ------------------
  |  | 2651|      0|	#define PUGI_IMPL_THROW_ERROR(err, m)   return error_offset = m, error_status = err, static_cast<char_t*>(nullptr)
  ------------------
  |  Branch (3228:10): [True: 0, False: 52]
  ------------------
 3229|       |
 3230|     52|					PUGI_IMPL_PUSHNODE(node_declaration);
  ------------------
  |  | 2645|     52|	#define PUGI_IMPL_PUSHNODE(TYPE)        { cursor = append_new_node(cursor, *alloc, TYPE); if (!cursor) PUGI_IMPL_THROW_ERROR(status_out_of_memory, s); }
  |  |  ------------------
  |  |  |  | 2651|      0|	#define PUGI_IMPL_THROW_ERROR(err, m)   return error_offset = m, error_status = err, static_cast<char_t*>(nullptr)
  |  |  ------------------
  |  |  |  Branch (2645:96): [True: 0, False: 52]
  |  |  ------------------
  ------------------
 3231|     52|				}
 3232|      0|				else
 3233|      0|				{
 3234|      0|					PUGI_IMPL_PUSHNODE(node_pi);
  ------------------
  |  | 2645|      0|	#define PUGI_IMPL_PUSHNODE(TYPE)        { cursor = append_new_node(cursor, *alloc, TYPE); if (!cursor) PUGI_IMPL_THROW_ERROR(status_out_of_memory, s); }
  |  |  ------------------
  |  |  |  | 2651|      0|	#define PUGI_IMPL_THROW_ERROR(err, m)   return error_offset = m, error_status = err, static_cast<char_t*>(nullptr)
  |  |  ------------------
  |  |  |  Branch (2645:96): [True: 0, False: 0]
  |  |  ------------------
  ------------------
 3235|      0|				}
 3236|       |
 3237|     52|				cursor->name = target;
 3238|       |
 3239|     52|				PUGI_IMPL_ENDSEG();
  ------------------
  |  | 2650|     52|	#define PUGI_IMPL_ENDSEG()              { ch = *s; *s = 0; ++s; }
  ------------------
 3240|       |
 3241|       |				// parse value/attributes
 3242|     52|				if (ch == '?')
  ------------------
  |  Branch (3242:9): [True: 0, False: 52]
  ------------------
 3243|      0|				{
 3244|       |					// empty node
 3245|      0|					if (!PUGI_IMPL_ENDSWITH(*s, '>')) PUGI_IMPL_THROW_ERROR(status_bad_pi, s);
  ------------------
  |  | 2642|      0|	#define PUGI_IMPL_ENDSWITH(c, e)        ((c) == (e) || ((c) == 0 && endch == (e)))
  |  |  ------------------
  |  |  |  Branch (2642:43): [True: 0, False: 0]
  |  |  |  Branch (2642:58): [True: 0, False: 0]
  |  |  |  Branch (2642:70): [True: 0, False: 0]
  |  |  ------------------
  ------------------
              					if (!PUGI_IMPL_ENDSWITH(*s, '>')) PUGI_IMPL_THROW_ERROR(status_bad_pi, s);
  ------------------
  |  | 2651|      0|	#define PUGI_IMPL_THROW_ERROR(err, m)   return error_offset = m, error_status = err, static_cast<char_t*>(nullptr)
  ------------------
 3246|      0|					s += (*s == '>');
 3247|       |
 3248|      0|					PUGI_IMPL_POPNODE();
  ------------------
  |  | 2646|      0|	#define PUGI_IMPL_POPNODE()             { cursor = cursor->parent; }
  ------------------
 3249|      0|				}
 3250|     52|				else if (PUGI_IMPL_IS_CHARTYPE(ch, ct_space))
  ------------------
  |  | 1951|     52|	#define PUGI_IMPL_IS_CHARTYPE(c, ct) PUGI_IMPL_IS_CHARTYPE_IMPL(c, ct, chartype_table)
  |  |  ------------------
  |  |  |  | 1948|     52|	#define PUGI_IMPL_IS_CHARTYPE_IMPL(c, ct, table) (table[static_cast<unsigned char>(c)] & (ct))
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (1948:51): [True: 52, False: 0]
  |  |  |  |  ------------------
  |  |  ------------------
  ------------------
 3251|     52|				{
 3252|     52|					PUGI_IMPL_SKIPWS();
  ------------------
  |  | 2643|     52|	#define PUGI_IMPL_SKIPWS()              { while (PUGI_IMPL_IS_CHARTYPE(*s, ct_space)) ++s; }
  ------------------
 3253|       |
 3254|       |					// scan for tag end
 3255|     52|					char_t* value = s;
 3256|       |
 3257|     52|					PUGI_IMPL_SCANFOR(s[0] == '?' && PUGI_IMPL_ENDSWITH(s[1], '>'));
  ------------------
  |  | 2647|  1.22k|	#define PUGI_IMPL_SCANFOR(X)            { while (*s != 0 && !(X)) ++s; }
  |  |  ------------------
  |  |  |  Branch (2647:51): [True: 1.11k, False: 0]
  |  |  |  Branch (2647:64): [True: 0, False: 0]
  |  |  |  Branch (2647:64): [True: 0, False: 0]
  |  |  |  Branch (2647:64): [True: 52, False: 0]
  |  |  |  Branch (2647:64): [True: 52, False: 1.06k]
  |  |  ------------------
  ------------------
 3258|     52|					PUGI_IMPL_CHECK_ERROR(status_bad_pi, s);
  ------------------
  |  | 2652|     52|	#define PUGI_IMPL_CHECK_ERROR(err, m)   { if (*s == 0) PUGI_IMPL_THROW_ERROR(err, m); }
  |  |  ------------------
  |  |  |  | 2651|      0|	#define PUGI_IMPL_THROW_ERROR(err, m)   return error_offset = m, error_status = err, static_cast<char_t*>(nullptr)
  |  |  ------------------
  |  |  |  Branch (2652:48): [True: 0, False: 52]
  |  |  ------------------
  ------------------
 3259|       |
 3260|     52|					if (declaration)
  ------------------
  |  Branch (3260:10): [True: 52, False: 0]
  ------------------
 3261|     52|					{
 3262|       |						// replace ending ? with / so that 'element' terminates properly
 3263|     52|						*s = '/';
 3264|       |
 3265|       |						// we exit from this function with cursor at node_declaration, which is a signal to parse() to go to LOC_ATTRIBUTES
 3266|     52|						s = value;
 3267|     52|					}
 3268|      0|					else
 3269|      0|					{
 3270|       |						// store value and step over >
 3271|      0|						cursor->value = value;
 3272|       |
 3273|      0|						PUGI_IMPL_POPNODE();
  ------------------
  |  | 2646|      0|	#define PUGI_IMPL_POPNODE()             { cursor = cursor->parent; }
  ------------------
 3274|       |
 3275|      0|						PUGI_IMPL_ENDSEG();
  ------------------
  |  | 2650|      0|	#define PUGI_IMPL_ENDSEG()              { ch = *s; *s = 0; ++s; }
  ------------------
 3276|       |
 3277|      0|						s += (*s == '>');
 3278|      0|					}
 3279|     52|				}
 3280|      0|				else PUGI_IMPL_THROW_ERROR(status_bad_pi, s);
  ------------------
  |  | 2651|      0|	#define PUGI_IMPL_THROW_ERROR(err, m)   return error_offset = m, error_status = err, static_cast<char_t*>(nullptr)
  ------------------
 3281|     52|			}
 3282|      0|			else
 3283|      0|			{
 3284|       |				// scan for tag end
 3285|      0|				PUGI_IMPL_SCANFOR(s[0] == '?' && PUGI_IMPL_ENDSWITH(s[1], '>'));
  ------------------
  |  | 2647|      0|	#define PUGI_IMPL_SCANFOR(X)            { while (*s != 0 && !(X)) ++s; }
  |  |  ------------------
  |  |  |  Branch (2647:51): [True: 0, False: 0]
  |  |  |  Branch (2647:64): [True: 0, False: 0]
  |  |  |  Branch (2647:64): [True: 0, False: 0]
  |  |  |  Branch (2647:64): [True: 0, False: 0]
  |  |  |  Branch (2647:64): [True: 0, False: 0]
  |  |  ------------------
  ------------------
 3286|      0|				PUGI_IMPL_CHECK_ERROR(status_bad_pi, s);
  ------------------
  |  | 2652|      0|	#define PUGI_IMPL_CHECK_ERROR(err, m)   { if (*s == 0) PUGI_IMPL_THROW_ERROR(err, m); }
  |  |  ------------------
  |  |  |  | 2651|      0|	#define PUGI_IMPL_THROW_ERROR(err, m)   return error_offset = m, error_status = err, static_cast<char_t*>(nullptr)
  |  |  ------------------
  |  |  |  Branch (2652:48): [True: 0, False: 0]
  |  |  ------------------
  ------------------
 3287|       |
 3288|      0|				s += (s[1] == '>' ? 2 : 1);
  ------------------
  |  Branch (3288:11): [True: 0, False: 0]
  ------------------
 3289|      0|			}
 3290|       |
 3291|       |			// store from registers
 3292|     52|			ref_cursor = cursor;
 3293|       |
 3294|     52|			return s;
 3295|     52|		}
pugixml.cpp:_ZN4pugi4impl12_GLOBAL__N_110xml_parser17parse_exclamationEPcPNS_15xml_node_structEjc:
 3095|     25|		{
 3096|       |			// parse node contents, starting with exclamation mark
 3097|     25|			++s;
 3098|       |
 3099|     25|			if (*s == '-') // '<!-...'
  ------------------
  |  Branch (3099:8): [True: 25, False: 0]
  ------------------
 3100|     25|			{
 3101|     25|				++s;
 3102|       |
 3103|     25|				if (*s == '-') // '<!--...'
  ------------------
  |  Branch (3103:9): [True: 25, False: 0]
  ------------------
 3104|     25|				{
 3105|     25|					++s;
 3106|       |
 3107|     25|					if (PUGI_IMPL_OPTSET(parse_comments))
  ------------------
  |  | 2644|     25|	#define PUGI_IMPL_OPTSET(OPT)           ( optmsk & (OPT) )
  |  |  ------------------
  |  |  |  Branch (2644:42): [True: 25, False: 0]
  |  |  ------------------
  ------------------
 3108|     25|					{
 3109|     25|						PUGI_IMPL_PUSHNODE(node_comment); // Append a new node on the tree.
  ------------------
  |  | 2645|     25|	#define PUGI_IMPL_PUSHNODE(TYPE)        { cursor = append_new_node(cursor, *alloc, TYPE); if (!cursor) PUGI_IMPL_THROW_ERROR(status_out_of_memory, s); }
  |  |  ------------------
  |  |  |  | 2651|      0|	#define PUGI_IMPL_THROW_ERROR(err, m)   return error_offset = m, error_status = err, static_cast<char_t*>(nullptr)
  |  |  ------------------
  |  |  |  Branch (2645:96): [True: 0, False: 25]
  |  |  ------------------
  ------------------
 3110|     25|						cursor->value = s; // Save the offset.
 3111|     25|					}
 3112|       |
 3113|     25|					if (PUGI_IMPL_OPTSET(parse_eol) && PUGI_IMPL_OPTSET(parse_comments))
  ------------------
  |  | 2644|     50|	#define PUGI_IMPL_OPTSET(OPT)           ( optmsk & (OPT) )
  |  |  ------------------
  |  |  |  Branch (2644:42): [True: 25, False: 0]
  |  |  ------------------
  ------------------
              					if (PUGI_IMPL_OPTSET(parse_eol) && PUGI_IMPL_OPTSET(parse_comments))
  ------------------
  |  | 2644|     25|	#define PUGI_IMPL_OPTSET(OPT)           ( optmsk & (OPT) )
  |  |  ------------------
  |  |  |  Branch (2644:42): [True: 25, False: 0]
  |  |  ------------------
  ------------------
 3114|     25|					{
 3115|     25|						s = strconv_comment(s, endch);
 3116|       |
 3117|     25|						if (!s) PUGI_IMPL_THROW_ERROR(status_bad_comment, cursor->value);
  ------------------
  |  | 2651|      0|	#define PUGI_IMPL_THROW_ERROR(err, m)   return error_offset = m, error_status = err, static_cast<char_t*>(nullptr)
  ------------------
  |  Branch (3117:11): [True: 0, False: 25]
  ------------------
 3118|     25|					}
 3119|      0|					else
 3120|      0|					{
 3121|       |						// Scan for terminating '-->'.
 3122|      0|						PUGI_IMPL_SCANFOR(s[0] == '-' && s[1] == '-' && PUGI_IMPL_ENDSWITH(s[2], '>'));
  ------------------
  |  | 2647|      0|	#define PUGI_IMPL_SCANFOR(X)            { while (*s != 0 && !(X)) ++s; }
  |  |  ------------------
  |  |  |  Branch (2647:51): [True: 0, False: 0]
  |  |  |  Branch (2647:64): [True: 0, False: 0]
  |  |  |  Branch (2647:64): [True: 0, False: 0]
  |  |  |  Branch (2647:64): [True: 0, False: 0]
  |  |  |  Branch (2647:64): [True: 0, False: 0]
  |  |  |  Branch (2647:64): [True: 0, False: 0]
  |  |  ------------------
  ------------------
 3123|      0|						PUGI_IMPL_CHECK_ERROR(status_bad_comment, s);
  ------------------
  |  | 2652|      0|	#define PUGI_IMPL_CHECK_ERROR(err, m)   { if (*s == 0) PUGI_IMPL_THROW_ERROR(err, m); }
  |  |  ------------------
  |  |  |  | 2651|      0|	#define PUGI_IMPL_THROW_ERROR(err, m)   return error_offset = m, error_status = err, static_cast<char_t*>(nullptr)
  |  |  ------------------
  |  |  |  Branch (2652:48): [True: 0, False: 0]
  |  |  ------------------
  ------------------
 3124|       |
 3125|      0|						if (PUGI_IMPL_OPTSET(parse_comments))
  ------------------
  |  | 2644|      0|	#define PUGI_IMPL_OPTSET(OPT)           ( optmsk & (OPT) )
  |  |  ------------------
  |  |  |  Branch (2644:42): [True: 0, False: 0]
  |  |  ------------------
  ------------------
 3126|      0|							*s = 0; // Zero-terminate this segment at the first terminating '-'.
 3127|       |
 3128|      0|						s += (s[2] == '>' ? 3 : 2); // Step over the '\0->'.
  ------------------
  |  Branch (3128:13): [True: 0, False: 0]
  ------------------
 3129|      0|					}
 3130|     25|				}
 3131|      0|				else PUGI_IMPL_THROW_ERROR(status_bad_comment, s);
  ------------------
  |  | 2651|      0|	#define PUGI_IMPL_THROW_ERROR(err, m)   return error_offset = m, error_status = err, static_cast<char_t*>(nullptr)
  ------------------
 3132|     25|			}
 3133|      0|			else if (*s == '[')
  ------------------
  |  Branch (3133:13): [True: 0, False: 0]
  ------------------
 3134|      0|			{
 3135|       |				// '<![CDATA[...'
 3136|      0|				if (*++s=='C' && *++s=='D' && *++s=='A' && *++s=='T' && *++s=='A' && *++s == '[')
  ------------------
  |  Branch (3136:9): [True: 0, False: 0]
  |  Branch (3136:22): [True: 0, False: 0]
  |  Branch (3136:35): [True: 0, False: 0]
  |  Branch (3136:48): [True: 0, False: 0]
  |  Branch (3136:61): [True: 0, False: 0]
  |  Branch (3136:74): [True: 0, False: 0]
  ------------------
 3137|      0|				{
 3138|      0|					++s;
 3139|       |
 3140|      0|					if (PUGI_IMPL_OPTSET(parse_cdata))
  ------------------
  |  | 2644|      0|	#define PUGI_IMPL_OPTSET(OPT)           ( optmsk & (OPT) )
  |  |  ------------------
  |  |  |  Branch (2644:42): [True: 0, False: 0]
  |  |  ------------------
  ------------------
 3141|      0|					{
 3142|      0|						PUGI_IMPL_PUSHNODE(node_cdata); // Append a new node on the tree.
  ------------------
  |  | 2645|      0|	#define PUGI_IMPL_PUSHNODE(TYPE)        { cursor = append_new_node(cursor, *alloc, TYPE); if (!cursor) PUGI_IMPL_THROW_ERROR(status_out_of_memory, s); }
  |  |  ------------------
  |  |  |  | 2651|      0|	#define PUGI_IMPL_THROW_ERROR(err, m)   return error_offset = m, error_status = err, static_cast<char_t*>(nullptr)
  |  |  ------------------
  |  |  |  Branch (2645:96): [True: 0, False: 0]
  |  |  ------------------
  ------------------
 3143|      0|						cursor->value = s; // Save the offset.
 3144|       |
 3145|      0|						if (PUGI_IMPL_OPTSET(parse_eol))
  ------------------
  |  | 2644|      0|	#define PUGI_IMPL_OPTSET(OPT)           ( optmsk & (OPT) )
  |  |  ------------------
  |  |  |  Branch (2644:42): [True: 0, False: 0]
  |  |  ------------------
  ------------------
 3146|      0|						{
 3147|      0|							s = strconv_cdata(s, endch);
 3148|       |
 3149|      0|							if (!s) PUGI_IMPL_THROW_ERROR(status_bad_cdata, cursor->value);
  ------------------
  |  | 2651|      0|	#define PUGI_IMPL_THROW_ERROR(err, m)   return error_offset = m, error_status = err, static_cast<char_t*>(nullptr)
  ------------------
  |  Branch (3149:12): [True: 0, False: 0]
  ------------------
 3150|      0|						}
 3151|      0|						else
 3152|      0|						{
 3153|       |							// Scan for terminating ']]>'.
 3154|      0|							PUGI_IMPL_SCANFOR(s[0] == ']' && s[1] == ']' && PUGI_IMPL_ENDSWITH(s[2], '>'));
  ------------------
  |  | 2647|      0|	#define PUGI_IMPL_SCANFOR(X)            { while (*s != 0 && !(X)) ++s; }
  |  |  ------------------
  |  |  |  Branch (2647:51): [True: 0, False: 0]
  |  |  |  Branch (2647:64): [True: 0, False: 0]
  |  |  |  Branch (2647:64): [True: 0, False: 0]
  |  |  |  Branch (2647:64): [True: 0, False: 0]
  |  |  |  Branch (2647:64): [True: 0, False: 0]
  |  |  |  Branch (2647:64): [True: 0, False: 0]
  |  |  ------------------
  ------------------
 3155|      0|							PUGI_IMPL_CHECK_ERROR(status_bad_cdata, s);
  ------------------
  |  | 2652|      0|	#define PUGI_IMPL_CHECK_ERROR(err, m)   { if (*s == 0) PUGI_IMPL_THROW_ERROR(err, m); }
  |  |  ------------------
  |  |  |  | 2651|      0|	#define PUGI_IMPL_THROW_ERROR(err, m)   return error_offset = m, error_status = err, static_cast<char_t*>(nullptr)
  |  |  ------------------
  |  |  |  Branch (2652:48): [True: 0, False: 0]
  |  |  ------------------
  ------------------
 3156|       |
 3157|      0|							*s++ = 0; // Zero-terminate this segment.
 3158|      0|						}
 3159|      0|					}
 3160|      0|					else // Flagged for discard, but we still have to scan for the terminator.
 3161|      0|					{
 3162|       |						// Scan for terminating ']]>'.
 3163|      0|						PUGI_IMPL_SCANFOR(s[0] == ']' && s[1] == ']' && PUGI_IMPL_ENDSWITH(s[2], '>'));
  ------------------
  |  | 2647|      0|	#define PUGI_IMPL_SCANFOR(X)            { while (*s != 0 && !(X)) ++s; }
  |  |  ------------------
  |  |  |  Branch (2647:51): [True: 0, False: 0]
  |  |  |  Branch (2647:64): [True: 0, False: 0]
  |  |  |  Branch (2647:64): [True: 0, False: 0]
  |  |  |  Branch (2647:64): [True: 0, False: 0]
  |  |  |  Branch (2647:64): [True: 0, False: 0]
  |  |  |  Branch (2647:64): [True: 0, False: 0]
  |  |  ------------------
  ------------------
 3164|      0|						PUGI_IMPL_CHECK_ERROR(status_bad_cdata, s);
  ------------------
  |  | 2652|      0|	#define PUGI_IMPL_CHECK_ERROR(err, m)   { if (*s == 0) PUGI_IMPL_THROW_ERROR(err, m); }
  |  |  ------------------
  |  |  |  | 2651|      0|	#define PUGI_IMPL_THROW_ERROR(err, m)   return error_offset = m, error_status = err, static_cast<char_t*>(nullptr)
  |  |  ------------------
  |  |  |  Branch (2652:48): [True: 0, False: 0]
  |  |  ------------------
  ------------------
 3165|       |
 3166|      0|						++s;
 3167|      0|					}
 3168|       |
 3169|      0|					s += (s[1] == '>' ? 2 : 1); // Step over the last ']>'.
  ------------------
  |  Branch (3169:12): [True: 0, False: 0]
  ------------------
 3170|      0|				}
 3171|      0|				else PUGI_IMPL_THROW_ERROR(status_bad_cdata, s);
  ------------------
  |  | 2651|      0|	#define PUGI_IMPL_THROW_ERROR(err, m)   return error_offset = m, error_status = err, static_cast<char_t*>(nullptr)
  ------------------
 3172|      0|			}
 3173|      0|			else if (s[0] == 'D' && s[1] == 'O' && s[2] == 'C' && s[3] == 'T' && s[4] == 'Y' && s[5] == 'P' && PUGI_IMPL_ENDSWITH(s[6], 'E'))
  ------------------
  |  | 2642|      0|	#define PUGI_IMPL_ENDSWITH(c, e)        ((c) == (e) || ((c) == 0 && endch == (e)))
  |  |  ------------------
  |  |  |  Branch (2642:43): [True: 0, False: 0]
  |  |  |  Branch (2642:58): [True: 0, False: 0]
  |  |  |  Branch (2642:70): [True: 0, False: 0]
  |  |  ------------------
  ------------------
  |  Branch (3173:13): [True: 0, False: 0]
  |  Branch (3173:28): [True: 0, False: 0]
  |  Branch (3173:43): [True: 0, False: 0]
  |  Branch (3173:58): [True: 0, False: 0]
  |  Branch (3173:73): [True: 0, False: 0]
  |  Branch (3173:88): [True: 0, False: 0]
  ------------------
 3174|      0|			{
 3175|      0|				s -= 2;
 3176|       |
 3177|      0|				if (cursor->parent) PUGI_IMPL_THROW_ERROR(status_bad_doctype, s);
  ------------------
  |  | 2651|      0|	#define PUGI_IMPL_THROW_ERROR(err, m)   return error_offset = m, error_status = err, static_cast<char_t*>(nullptr)
  ------------------
  |  Branch (3177:9): [True: 0, False: 0]
  ------------------
 3178|       |
 3179|      0|				char_t* mark = s + 9;
 3180|       |
 3181|      0|				s = parse_doctype_group(s, endch);
 3182|      0|				if (!s) return s;
  ------------------
  |  Branch (3182:9): [True: 0, False: 0]
  ------------------
 3183|       |
 3184|      0|				assert((*s == 0 && endch == '>') || *s == '>');
  ------------------
  |  Branch (3184:5): [True: 0, False: 0]
  |  Branch (3184:5): [True: 0, False: 0]
  |  Branch (3184:5): [True: 0, False: 0]
  |  Branch (3184:5): [True: 0, False: 0]
  ------------------
 3185|      0|				if (*s) *s++ = 0;
  ------------------
  |  Branch (3185:9): [True: 0, False: 0]
  ------------------
 3186|       |
 3187|      0|				if (PUGI_IMPL_OPTSET(parse_doctype))
  ------------------
  |  | 2644|      0|	#define PUGI_IMPL_OPTSET(OPT)           ( optmsk & (OPT) )
  |  |  ------------------
  |  |  |  Branch (2644:42): [True: 0, False: 0]
  |  |  ------------------
  ------------------
 3188|      0|				{
 3189|      0|					while (PUGI_IMPL_IS_CHARTYPE(*mark, ct_space)) ++mark;
 3190|       |
 3191|      0|					PUGI_IMPL_PUSHNODE(node_doctype);
  ------------------
  |  | 2645|      0|	#define PUGI_IMPL_PUSHNODE(TYPE)        { cursor = append_new_node(cursor, *alloc, TYPE); if (!cursor) PUGI_IMPL_THROW_ERROR(status_out_of_memory, s); }
  |  |  ------------------
  |  |  |  | 2651|      0|	#define PUGI_IMPL_THROW_ERROR(err, m)   return error_offset = m, error_status = err, static_cast<char_t*>(nullptr)
  |  |  ------------------
  |  |  |  Branch (2645:96): [True: 0, False: 0]
  |  |  ------------------
  ------------------
 3192|       |
 3193|      0|					cursor->value = mark;
 3194|      0|				}
 3195|      0|			}
 3196|      0|			else if (*s == 0 && endch == '-') PUGI_IMPL_THROW_ERROR(status_bad_comment, s);
  ------------------
  |  | 2651|      0|	#define PUGI_IMPL_THROW_ERROR(err, m)   return error_offset = m, error_status = err, static_cast<char_t*>(nullptr)
  ------------------
  |  Branch (3196:13): [True: 0, False: 0]
  |  Branch (3196:24): [True: 0, False: 0]
  ------------------
 3197|      0|			else if (*s == 0 && endch == '[') PUGI_IMPL_THROW_ERROR(status_bad_cdata, s);
  ------------------
  |  | 2651|      0|	#define PUGI_IMPL_THROW_ERROR(err, m)   return error_offset = m, error_status = err, static_cast<char_t*>(nullptr)
  ------------------
  |  Branch (3197:13): [True: 0, False: 0]
  |  Branch (3197:24): [True: 0, False: 0]
  ------------------
 3198|      0|			else PUGI_IMPL_THROW_ERROR(status_unrecognized_tag, s);
  ------------------
  |  | 2651|      0|	#define PUGI_IMPL_THROW_ERROR(err, m)   return error_offset = m, error_status = err, static_cast<char_t*>(nullptr)
  ------------------
 3199|       |
 3200|     25|			return s;
 3201|     25|		}
pugixml.cpp:_ZN4pugi4impl12_GLOBAL__N_115strconv_commentEPcc:
 2655|     25|	{
 2656|     25|		gap g;
 2657|       |
 2658|     43|		while (true)
  ------------------
  |  Branch (2658:10): [True: 43, Folded]
  ------------------
 2659|     43|		{
 2660|     43|			PUGI_IMPL_SCANWHILE_UNROLL(!PUGI_IMPL_IS_CHARTYPE(ss, ct_parse_comment));
  ------------------
  |  | 2649|    300|	#define PUGI_IMPL_SCANWHILE_UNROLL(X)   { for (;;) { char_t ss = s[0]; if (PUGI_IMPL_UNLIKELY(!(X))) { break; } ss = s[1]; if (PUGI_IMPL_UNLIKELY(!(X))) { s += 1; break; } ss = s[2]; if (PUGI_IMPL_UNLIKELY(!(X))) { s += 2; break; } ss = s[3]; if (PUGI_IMPL_UNLIKELY(!(X))) { s += 3; break; } s += 4; } }
  |  |  ------------------
  |  |  |  |  104|    300|#	define PUGI_IMPL_UNLIKELY(cond) __builtin_expect(cond, 0)
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (104:35): [True: 24, False: 276]
  |  |  |  |  ------------------
  |  |  ------------------
  |  |               	#define PUGI_IMPL_SCANWHILE_UNROLL(X)   { for (;;) { char_t ss = s[0]; if (PUGI_IMPL_UNLIKELY(!(X))) { break; } ss = s[1]; if (PUGI_IMPL_UNLIKELY(!(X))) { s += 1; break; } ss = s[2]; if (PUGI_IMPL_UNLIKELY(!(X))) { s += 2; break; } ss = s[3]; if (PUGI_IMPL_UNLIKELY(!(X))) { s += 3; break; } s += 4; } }
  |  |  ------------------
  |  |  |  |  104|    276|#	define PUGI_IMPL_UNLIKELY(cond) __builtin_expect(cond, 0)
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (104:35): [True: 10, False: 266]
  |  |  |  |  ------------------
  |  |  ------------------
  |  |               	#define PUGI_IMPL_SCANWHILE_UNROLL(X)   { for (;;) { char_t ss = s[0]; if (PUGI_IMPL_UNLIKELY(!(X))) { break; } ss = s[1]; if (PUGI_IMPL_UNLIKELY(!(X))) { s += 1; break; } ss = s[2]; if (PUGI_IMPL_UNLIKELY(!(X))) { s += 2; break; } ss = s[3]; if (PUGI_IMPL_UNLIKELY(!(X))) { s += 3; break; } s += 4; } }
  |  |  ------------------
  |  |  |  |  104|    266|#	define PUGI_IMPL_UNLIKELY(cond) __builtin_expect(cond, 0)
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (104:35): [True: 6, False: 260]
  |  |  |  |  ------------------
  |  |  ------------------
  |  |               	#define PUGI_IMPL_SCANWHILE_UNROLL(X)   { for (;;) { char_t ss = s[0]; if (PUGI_IMPL_UNLIKELY(!(X))) { break; } ss = s[1]; if (PUGI_IMPL_UNLIKELY(!(X))) { s += 1; break; } ss = s[2]; if (PUGI_IMPL_UNLIKELY(!(X))) { s += 2; break; } ss = s[3]; if (PUGI_IMPL_UNLIKELY(!(X))) { s += 3; break; } s += 4; } }
  |  |  ------------------
  |  |  |  |  104|    260|#	define PUGI_IMPL_UNLIKELY(cond) __builtin_expect(cond, 0)
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (104:35): [True: 3, False: 257]
  |  |  |  |  ------------------
  |  |  ------------------
  ------------------
 2661|       |
 2662|     43|			if (*s == '\r') // Either a single 0x0d or 0x0d 0x0a pair
  ------------------
  |  Branch (2662:8): [True: 0, False: 43]
  ------------------
 2663|      0|			{
 2664|      0|				*s++ = '\n'; // replace first one with 0x0a
 2665|       |
 2666|      0|				if (*s == '\n') g.push(s, 1);
  ------------------
  |  Branch (2666:9): [True: 0, False: 0]
  ------------------
 2667|      0|			}
 2668|     43|			else if (s[0] == '-' && s[1] == '-' && PUGI_IMPL_ENDSWITH(s[2], '>')) // comment ends here
  ------------------
  |  | 2642|     25|	#define PUGI_IMPL_ENDSWITH(c, e)        ((c) == (e) || ((c) == 0 && endch == (e)))
  |  |  ------------------
  |  |  |  Branch (2642:43): [True: 25, False: 0]
  |  |  |  Branch (2642:58): [True: 0, False: 0]
  |  |  |  Branch (2642:70): [True: 0, False: 0]
  |  |  ------------------
  ------------------
  |  Branch (2668:13): [True: 25, False: 18]
  |  Branch (2668:28): [True: 25, False: 0]
  ------------------
 2669|     25|			{
 2670|     25|				*g.flush(s) = 0;
 2671|       |
 2672|     25|				return s + (s[2] == '>' ? 3 : 2);
  ------------------
  |  Branch (2672:17): [True: 25, False: 0]
  ------------------
 2673|     25|			}
 2674|     18|			else if (*s == 0)
  ------------------
  |  Branch (2674:13): [True: 0, False: 18]
  ------------------
 2675|      0|			{
 2676|      0|				return nullptr;
 2677|      0|			}
 2678|     18|			else ++s;
 2679|     43|		}
 2680|     25|	}
pugixml.cpp:_ZN4pugi4impl12_GLOBAL__N_110xml_parser25has_element_node_siblingsEPNS_15xml_node_structE:
 3567|     49|		{
 3568|     97|			while (node)
  ------------------
  |  Branch (3568:11): [True: 96, False: 1]
  ------------------
 3569|     96|			{
 3570|     96|				if (PUGI_IMPL_NODETYPE(node) == node_element) return true;
  ------------------
  |  |  492|     96|	#define PUGI_IMPL_NODETYPE(n) static_cast<xml_node_type>((n)->header & impl::xml_memory_page_type_mask)
  ------------------
  |  Branch (3570:9): [True: 48, False: 48]
  ------------------
 3571|       |
 3572|     48|				node = node->next_sibling;
 3573|     48|			}
 3574|       |
 3575|      1|			return false;
 3576|     49|		}
pugixml.cpp:_ZN4pugi4impl12_GLOBAL__N_112auto_deleterIvED2Ev:
  312|     60|		{
  313|     60|			if (data) deleter(data);
  ------------------
  |  Branch (313:8): [True: 0, False: 60]
  ------------------
  314|     60|		}
pugixml.cpp:_ZN4pugi4impl12_GLOBAL__N_115xml_memory_page9constructEPv:
  499|    348|		{
  500|    348|			xml_memory_page* result = static_cast<xml_memory_page*>(memory);
  501|       |
  502|    348|			result->allocator = nullptr;
  503|    348|			result->prev = nullptr;
  504|    348|			result->next = nullptr;
  505|    348|			result->busy_size = 0;
  506|    348|			result->freed_size = 0;
  507|       |
  508|       |		#ifdef PUGIXML_COMPACT
  509|       |			result->compact_string_base = nullptr;
  510|       |			result->compact_shared_parent = nullptr;
  511|       |			result->compact_page_marker = nullptr;
  512|       |		#endif
  513|       |
  514|    348|			return result;
  515|    348|		}
pugixml.cpp:_ZN4pugi4impl12_GLOBAL__N_119xml_document_structC2EPNS1_15xml_memory_pageE:
 1182|    120|		xml_document_struct(xml_memory_page* page): xml_node_struct(page, node_document), xml_allocator(page), buffer(nullptr), extra_buffers(nullptr)
 1183|    120|		{
 1184|    120|		}
pugixml.cpp:_ZN4pugi4impl12_GLOBAL__N_113xml_allocatorC2EPNS1_15xml_memory_pageE:
  548|    120|		xml_allocator(xml_memory_page* root): _root(root), _busy_size(root->busy_size)
  549|    120|		{
  550|       |		#ifdef PUGIXML_COMPACT
  551|       |			_hash = nullptr;
  552|       |		#endif
  553|    120|		}
pugixml.cpp:_ZN4pugi4impl12_GLOBAL__N_113xml_allocator15deallocate_pageEPNS1_15xml_memory_pageE:
  574|    228|		{
  575|    228|			xml_memory::deallocate(page);
  576|    228|		}
pugixml.cpp:_ZN4pugi4impl12_GLOBAL__N_116default_allocateEm:
  205|    288|	{
  206|    288|		return malloc(size);
  207|    288|	}
pugixml.cpp:_ZN4pugi4impl12_GLOBAL__N_118default_deallocateEPv:
  210|    288|	{
  211|    288|		free(ptr);
  212|    288|	}
pugixml.cpp:_ZN4pugi4impl12_GLOBAL__N_112get_documentINS_15xml_node_structEEERNS1_19xml_document_structEPKT_:
 1203|     48|	{
 1204|     48|		assert(object);
  ------------------
  |  Branch (1204:3): [True: 48, False: 0]
  ------------------
 1205|       |
 1206|     48|		return *static_cast<xml_document_struct*>(PUGI_IMPL_GETPAGE(object)->allocator);
  ------------------
  |  |  491|     48|	#define PUGI_IMPL_GETPAGE(n) PUGI_IMPL_GETPAGE_IMPL((n)->header)
  |  |  ------------------
  |  |  |  |  488|     48|	#define PUGI_IMPL_GETPAGE_IMPL(header) static_cast<impl::xml_memory_page*>(const_cast<void*>(static_cast<const void*>(reinterpret_cast<const char*>(&header) - (header >> 8))))
  |  |  ------------------
  ------------------
 1207|     48|	}

_ZNK4pugi16xml_object_rangeINS_17xml_node_iteratorEE5beginEv:
  337|  71.4k|		It begin() const { return _begin; }
_ZNK4pugi16xml_object_rangeINS_17xml_node_iteratorEE3endEv:
  338|  71.4k|		It end() const { return _end; }
_ZNK4pugi8xml_node9find_nodeIN6Assimp27find_node_by_name_predicateEEES0_T_:
  708|      4|		{
  709|      4|			if (!_root) return xml_node();
  ------------------
  |  Branch (709:8): [True: 0, False: 4]
  ------------------
  710|       |
  711|      4|			xml_node cur = first_child();
  712|       |
  713|      8|			while (cur._root && cur._root != _root)
  ------------------
  |  Branch (713:11): [True: 8, False: 0]
  |  Branch (713:24): [True: 8, False: 0]
  ------------------
  714|      8|			{
  715|      8|				if (pred(cur)) return cur;
  ------------------
  |  Branch (715:9): [True: 4, False: 4]
  ------------------
  716|       |
  717|      4|				if (cur.first_child()) cur = cur.first_child();
  ------------------
  |  Branch (717:9): [True: 0, False: 4]
  ------------------
  718|      4|				else if (cur.next_sibling()) cur = cur.next_sibling();
  ------------------
  |  Branch (718:14): [True: 4, False: 0]
  ------------------
  719|      0|				else
  720|      0|				{
  721|      0|					while (!cur.next_sibling() && cur._root != _root) cur = cur.parent();
  ------------------
  |  Branch (721:13): [True: 0, False: 0]
  |  Branch (721:13): [True: 0, False: 0]
  |  Branch (721:36): [True: 0, False: 0]
  ------------------
  722|       |
  723|      0|					if (cur._root != _root) cur = cur.next_sibling();
  ------------------
  |  Branch (723:10): [True: 0, False: 0]
  ------------------
  724|      0|				}
  725|      4|			}
  726|       |
  727|      0|			return xml_node();
  728|      4|		}
_ZNK4pugi16xml_object_rangeINS_22xml_attribute_iteratorEE5beginEv:
  337|  1.20k|		It begin() const { return _begin; }
_ZNK4pugi16xml_object_rangeINS_22xml_attribute_iteratorEE3endEv:
  338|  1.20k|		It end() const { return _end; }
_ZN4pugi16xml_object_rangeINS_17xml_node_iteratorEEC2ES1_S1_:
  333|  71.4k|		xml_object_range(It b, It e): _begin(b), _end(e)
  334|  71.4k|		{
  335|  71.4k|		}
_ZN4pugi16xml_object_rangeINS_22xml_attribute_iteratorEEC2ES1_S1_:
  333|  1.20k|		xml_object_range(It b, It e): _begin(b), _end(e)
  334|  1.20k|		{
  335|  1.20k|		}

_ZN9rapidjson19MemoryPoolAllocatorINS_12CrtAllocatorEEC2EmPS1_:
  171|    102|        chunk_capacity_(chunkSize),
  172|    102|        baseAllocator_(baseAllocator ? baseAllocator : RAPIDJSON_NEW(BaseAllocator)()),
  ------------------
  |  |  712|    102|#define RAPIDJSON_NEW(TypeName) new TypeName
  ------------------
  |  Branch (172:24): [True: 0, False: 102]
  ------------------
  173|    102|        shared_(static_cast<SharedData*>(baseAllocator_ ? baseAllocator_->Malloc(SIZEOF_SHARED_DATA + SIZEOF_CHUNK_HEADER) : 0))
  ------------------
  |  Branch (173:42): [True: 102, False: 0]
  ------------------
  174|    102|    {
  175|    102|        RAPIDJSON_ASSERT(baseAllocator_ != 0);
  ------------------
  |  |  437|    102|#define RAPIDJSON_ASSERT(x) assert(x)
  ------------------
  |  Branch (175:9): [True: 102, False: 0]
  ------------------
  176|    102|        RAPIDJSON_ASSERT(shared_ != 0);
  ------------------
  |  |  437|    102|#define RAPIDJSON_ASSERT(x) assert(x)
  ------------------
  |  Branch (176:9): [True: 102, False: 0]
  ------------------
  177|    102|        if (baseAllocator) {
  ------------------
  |  Branch (177:13): [True: 0, False: 102]
  ------------------
  178|      0|            shared_->ownBaseAllocator = 0;
  179|      0|        }
  180|    102|        else {
  181|    102|            shared_->ownBaseAllocator = baseAllocator_;
  182|    102|        }
  183|    102|        shared_->chunkHead = GetChunkHead(shared_);
  184|    102|        shared_->chunkHead->capacity = 0;
  185|    102|        shared_->chunkHead->size = 0;
  186|    102|        shared_->chunkHead->next = 0;
  187|    102|        shared_->ownBuffer = true;
  188|    102|        shared_->refcount = 1;
  189|    102|    }
_ZN9rapidjson12CrtAllocator6MallocEm:
   86|    127|    void* Malloc(size_t size) { 
   87|    127|        if (size) //  behavior of malloc(0) is implementation defined.
  ------------------
  |  Branch (87:13): [True: 127, False: 0]
  ------------------
   88|    127|            return RAPIDJSON_MALLOC(size);
  ------------------
  |  |  696|    127|#define RAPIDJSON_MALLOC(size) std::malloc(size)
  ------------------
   89|      0|        else
   90|      0|            return NULL; // standardize to returning NULL.
   91|    127|    }
_ZN9rapidjson19MemoryPoolAllocatorINS_12CrtAllocatorEE12GetChunkHeadEPNS2_10SharedDataE:
  151|    102|    {
  152|    102|        return reinterpret_cast<ChunkHeader*>(reinterpret_cast<uint8_t*>(shared) + SIZEOF_SHARED_DATA);
  153|    102|    }
_ZN9rapidjson12CrtAllocator4FreeEPv:
  100|    433|    static void Free(void *ptr) RAPIDJSON_NOEXCEPT { RAPIDJSON_FREE(ptr); }
  ------------------
  |  |  704|    433|#define RAPIDJSON_FREE(ptr) std::free(ptr)
  ------------------
_ZN9rapidjson7ReallocINS_13GenericMemberINS_4UTF8IcEENS_19MemoryPoolAllocatorINS_12CrtAllocatorEEEEES6_EEPT_RT0_S9_mm:
  436|  3.55k|{
  437|  3.55k|    RAPIDJSON_NOEXCEPT_ASSERT(old_n <= (std::numeric_limits<size_t>::max)() / sizeof(T) && new_n <= (std::numeric_limits<size_t>::max)() / sizeof(T));
  ------------------
  |  |  687|  3.55k|#define RAPIDJSON_NOEXCEPT_ASSERT(x) RAPIDJSON_ASSERT(x)
  |  |  ------------------
  |  |  |  |  437|  3.55k|#define RAPIDJSON_ASSERT(x) assert(x)
  |  |  ------------------
  ------------------
  |  Branch (437:5): [True: 3.55k, False: 0]
  |  Branch (437:5): [True: 3.55k, False: 0]
  |  Branch (437:5): [True: 3.55k, False: 0]
  ------------------
  438|  3.55k|    return static_cast<T*>(a.Realloc(old_p, old_n * sizeof(T), new_n * sizeof(T)));
  439|  3.55k|}
_ZN9rapidjson19MemoryPoolAllocatorINS_12CrtAllocatorEE7ReallocEPvmm:
  337|  3.55k|    void* Realloc(void* originalPtr, size_t originalSize, size_t newSize) {
  338|  3.55k|        if (originalPtr == 0)
  ------------------
  |  Branch (338:13): [True: 3.55k, False: 0]
  ------------------
  339|  3.55k|            return Malloc(newSize);
  340|       |
  341|      0|        RAPIDJSON_NOEXCEPT_ASSERT(shared_->refcount > 0);
  ------------------
  |  |  687|      0|#define RAPIDJSON_NOEXCEPT_ASSERT(x) RAPIDJSON_ASSERT(x)
  |  |  ------------------
  |  |  |  |  437|      0|#define RAPIDJSON_ASSERT(x) assert(x)
  |  |  ------------------
  ------------------
  |  Branch (341:9): [True: 0, False: 0]
  ------------------
  342|      0|        if (newSize == 0)
  ------------------
  |  Branch (342:13): [True: 0, False: 0]
  ------------------
  343|      0|            return NULL;
  344|       |
  345|      0|        originalSize = RAPIDJSON_ALIGN(originalSize);
  ------------------
  |  |  307|      0|#define RAPIDJSON_ALIGN(x) (((x) + static_cast<size_t>(7u)) & ~static_cast<size_t>(7u))
  ------------------
  346|      0|        newSize = RAPIDJSON_ALIGN(newSize);
  ------------------
  |  |  307|      0|#define RAPIDJSON_ALIGN(x) (((x) + static_cast<size_t>(7u)) & ~static_cast<size_t>(7u))
  ------------------
  347|       |
  348|       |        // Do not shrink if new size is smaller than original
  349|      0|        if (originalSize >= newSize)
  ------------------
  |  Branch (349:13): [True: 0, False: 0]
  ------------------
  350|      0|            return originalPtr;
  351|       |
  352|       |        // Simply expand it if it is the last allocation and there is sufficient space
  353|      0|        if (originalPtr == GetChunkBuffer(shared_) + shared_->chunkHead->size - originalSize) {
  ------------------
  |  Branch (353:13): [True: 0, False: 0]
  ------------------
  354|      0|            size_t increment = static_cast<size_t>(newSize - originalSize);
  355|      0|            if (shared_->chunkHead->size + increment <= shared_->chunkHead->capacity) {
  ------------------
  |  Branch (355:17): [True: 0, False: 0]
  ------------------
  356|      0|                shared_->chunkHead->size += increment;
  357|      0|                return originalPtr;
  358|      0|            }
  359|      0|        }
  360|       |
  361|       |        // Realloc process: allocate and copy memory, do not free original buffer.
  362|      0|        if (void* newBuffer = Malloc(newSize)) {
  ------------------
  |  Branch (362:19): [True: 0, False: 0]
  ------------------
  363|      0|            if (originalSize)
  ------------------
  |  Branch (363:17): [True: 0, False: 0]
  ------------------
  364|      0|                std::memcpy(newBuffer, originalPtr, originalSize);
  365|      0|            return newBuffer;
  366|      0|        }
  367|      0|        else
  368|      0|            return NULL;
  369|      0|    }
_ZN9rapidjson19MemoryPoolAllocatorINS_12CrtAllocatorEE6MallocEm:
  321|  5.84k|    void* Malloc(size_t size) {
  322|  5.84k|        RAPIDJSON_NOEXCEPT_ASSERT(shared_->refcount > 0);
  ------------------
  |  |  687|  5.84k|#define RAPIDJSON_NOEXCEPT_ASSERT(x) RAPIDJSON_ASSERT(x)
  |  |  ------------------
  |  |  |  |  437|  5.84k|#define RAPIDJSON_ASSERT(x) assert(x)
  |  |  ------------------
  ------------------
  |  Branch (322:9): [True: 5.84k, False: 0]
  ------------------
  323|  5.84k|        if (!size)
  ------------------
  |  Branch (323:13): [True: 0, False: 5.84k]
  ------------------
  324|      0|            return NULL;
  325|       |
  326|  5.84k|        size = RAPIDJSON_ALIGN(size);
  ------------------
  |  |  307|  5.84k|#define RAPIDJSON_ALIGN(x) (((x) + static_cast<size_t>(7u)) & ~static_cast<size_t>(7u))
  ------------------
  327|  5.84k|        if (RAPIDJSON_UNLIKELY(shared_->chunkHead->size + size > shared_->chunkHead->capacity))
  ------------------
  |  |  505|  5.84k|#define RAPIDJSON_UNLIKELY(x) __builtin_expect(!!(x), 0)
  |  |  ------------------
  |  |  |  Branch (505:31): [True: 25, False: 5.81k]
  |  |  ------------------
  ------------------
  328|     25|            if (!AddChunk(chunk_capacity_ > size ? chunk_capacity_ : size))
  ------------------
  |  Branch (328:17): [True: 0, False: 25]
  |  Branch (328:27): [True: 23, False: 2]
  ------------------
  329|      0|                return NULL;
  330|       |
  331|  5.84k|        void *buffer = GetChunkBuffer(shared_) + shared_->chunkHead->size;
  332|  5.84k|        shared_->chunkHead->size += size;
  333|  5.84k|        return buffer;
  334|  5.84k|    }
_ZN9rapidjson19MemoryPoolAllocatorINS_12CrtAllocatorEE8AddChunkEm:
  390|     25|    bool AddChunk(size_t capacity) {
  391|     25|        if (!baseAllocator_)
  ------------------
  |  Branch (391:13): [True: 0, False: 25]
  ------------------
  392|      0|            shared_->ownBaseAllocator = baseAllocator_ = RAPIDJSON_NEW(BaseAllocator)();
  ------------------
  |  |  712|      0|#define RAPIDJSON_NEW(TypeName) new TypeName
  ------------------
  393|     25|        if (ChunkHeader* chunk = static_cast<ChunkHeader*>(baseAllocator_->Malloc(SIZEOF_CHUNK_HEADER + capacity))) {
  ------------------
  |  Branch (393:26): [True: 25, False: 0]
  ------------------
  394|     25|            chunk->capacity = capacity;
  395|     25|            chunk->size = 0;
  396|     25|            chunk->next = shared_->chunkHead;
  397|     25|            shared_->chunkHead = chunk;
  398|     25|            return true;
  399|     25|        }
  400|      0|        else
  401|      0|            return false;
  402|     25|    }
_ZN9rapidjson19MemoryPoolAllocatorINS_12CrtAllocatorEE14GetChunkBufferEPNS2_10SharedDataE:
  155|  5.84k|    {
  156|  5.84k|        return reinterpret_cast<uint8_t*>(shared->chunkHead) + SIZEOF_CHUNK_HEADER;
  157|  5.84k|    }
_ZN9rapidjson19MemoryPoolAllocatorINS_12CrtAllocatorEED2Ev:
  259|    102|    ~MemoryPoolAllocator() RAPIDJSON_NOEXCEPT {
  260|    102|        if (!shared_) {
  ------------------
  |  Branch (260:13): [True: 0, False: 102]
  ------------------
  261|       |            // do nothing if moved
  262|      0|            return;
  263|      0|        }
  264|    102|        if (shared_->refcount > 1) {
  ------------------
  |  Branch (264:13): [True: 0, False: 102]
  ------------------
  265|      0|            --shared_->refcount;
  266|      0|            return;
  267|      0|        }
  268|    102|        Clear();
  269|    102|        BaseAllocator *a = shared_->ownBaseAllocator;
  270|    102|        if (shared_->ownBuffer) {
  ------------------
  |  Branch (270:13): [True: 102, False: 0]
  ------------------
  271|    102|            baseAllocator_->Free(shared_);
  272|    102|        }
  273|    102|        RAPIDJSON_DELETE(a);
  ------------------
  |  |  716|    102|#define RAPIDJSON_DELETE(x) delete x
  ------------------
  274|    102|    }
_ZN9rapidjson19MemoryPoolAllocatorINS_12CrtAllocatorEE5ClearEv:
  277|    102|    void Clear() RAPIDJSON_NOEXCEPT {
  278|    102|        RAPIDJSON_NOEXCEPT_ASSERT(shared_->refcount > 0);
  ------------------
  |  |  687|    102|#define RAPIDJSON_NOEXCEPT_ASSERT(x) RAPIDJSON_ASSERT(x)
  |  |  ------------------
  |  |  |  |  437|    102|#define RAPIDJSON_ASSERT(x) assert(x)
  |  |  ------------------
  ------------------
  |  Branch (278:9): [True: 102, False: 0]
  ------------------
  279|    127|        for (;;) {
  280|    127|            ChunkHeader* c = shared_->chunkHead;
  281|    127|            if (!c->next) {
  ------------------
  |  Branch (281:17): [True: 102, False: 25]
  ------------------
  282|    102|                break;
  283|    102|            }
  284|     25|            shared_->chunkHead = c->next;
  285|     25|            baseAllocator_->Free(c);
  286|     25|        }
  287|    102|        shared_->chunkHead->size = 0;
  288|    102|    }
_ZN9rapidjson12CrtAllocator7ReallocEPvmm:
   92|    290|    void* Realloc(void* originalPtr, size_t originalSize, size_t newSize) {
   93|    290|        (void)originalSize;
   94|    290|        if (newSize == 0) {
  ------------------
  |  Branch (94:13): [True: 0, False: 290]
  ------------------
   95|      0|            RAPIDJSON_FREE(originalPtr);
  ------------------
  |  |  704|      0|#define RAPIDJSON_FREE(ptr) std::free(ptr)
  ------------------
   96|      0|            return NULL;
   97|      0|        }
   98|    290|        return RAPIDJSON_REALLOC(originalPtr, newSize);
  ------------------
  |  |  700|    290|#define RAPIDJSON_REALLOC(ptr, new_size) std::realloc(ptr, new_size)
  ------------------
   99|    290|    }
_ZN9rapidjson6MallocINS_13GenericMemberINS_4UTF8IcEENS_19MemoryPoolAllocatorINS_12CrtAllocatorEEEEES6_EEPT_RT0_m:
  443|  3.55k|{
  444|       |    return Realloc<T, A>(a, NULL, 0, n);
  445|  3.55k|}

_ZN9rapidjson15GenericDocumentINS_4UTF8IcEENS_19MemoryPoolAllocatorINS_12CrtAllocatorEEES4_EC2EPS5_mPS4_:
 2527|    102|        allocator_(allocator), ownAllocator_(0), stack_(stackAllocator, stackCapacity), parseResult_()
 2528|    102|    {
 2529|    102|        if (!allocator_)
  ------------------
  |  Branch (2529:13): [True: 102, False: 0]
  ------------------
 2530|    102|            ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator)();
  ------------------
  |  |  712|    102|#define RAPIDJSON_NEW(TypeName) new TypeName
  ------------------
 2531|    102|    }
_ZN9rapidjson12GenericValueINS_4UTF8IcEENS_19MemoryPoolAllocatorINS_12CrtAllocatorEEEEC2Ev:
  690|    226|    GenericValue() RAPIDJSON_NOEXCEPT : data_() { data_.f.flags = kNullFlag; }
_ZN9rapidjson12GenericValueINS_4UTF8IcEENS_19MemoryPoolAllocatorINS_12CrtAllocatorEEEED2Ev:
  880|  1.33k|    ~GenericValue() {
  881|       |        // With RAPIDJSON_USE_MEMBERSMAP, the maps need to be destroyed to release
  882|       |        // their Allocator if it's refcounted (e.g. MemoryPoolAllocator).
  883|  1.33k|        if (Allocator::kNeedFree || (RAPIDJSON_USE_MEMBERSMAP+0 &&
  ------------------
  |  |  180|      0|#define RAPIDJSON_USE_MEMBERSMAP 0 // not by default
  ------------------
  |  Branch (883:13): [Folded, False: 0]
  |  Branch (883:38): [Folded, False: 0]
  ------------------
  884|      0|                                     internal::IsRefCounted<Allocator>::Value)) {
  ------------------
  |  Branch (884:38): [True: 0, Folded]
  ------------------
  885|      0|            switch(data_.f.flags) {
  886|      0|            case kArrayFlag:
  ------------------
  |  Branch (886:13): [True: 0, False: 0]
  ------------------
  887|      0|                {
  888|      0|                    GenericValue* e = GetElementsPointer();
  889|      0|                    for (GenericValue* v = e; v != e + data_.a.size; ++v)
  ------------------
  |  Branch (889:47): [True: 0, False: 0]
  ------------------
  890|      0|                        v->~GenericValue();
  891|      0|                    if (Allocator::kNeedFree) { // Shortcut by Allocator's trait
  ------------------
  |  Branch (891:25): [Folded, False: 0]
  ------------------
  892|      0|                        Allocator::Free(e);
  893|      0|                    }
  894|      0|                }
  895|      0|                break;
  896|       |
  897|      0|            case kObjectFlag:
  ------------------
  |  Branch (897:13): [True: 0, False: 0]
  ------------------
  898|      0|                DoFreeMembers();
  899|      0|                break;
  900|       |
  901|      0|            case kCopyStringFlag:
  ------------------
  |  Branch (901:13): [True: 0, False: 0]
  ------------------
  902|      0|                if (Allocator::kNeedFree) { // Shortcut by Allocator's trait
  ------------------
  |  Branch (902:21): [Folded, False: 0]
  ------------------
  903|      0|                    Allocator::Free(const_cast<Ch*>(GetStringPointer()));
  904|      0|                }
  905|      0|                break;
  906|       |
  907|      0|            default:
  ------------------
  |  Branch (907:13): [True: 0, False: 0]
  ------------------
  908|      0|                break;  // Do nothing for other types.
  909|      0|            }
  910|      0|        }
  911|  1.33k|    }
_ZN9rapidjson15GenericDocumentINS_4UTF8IcEENS_19MemoryPoolAllocatorINS_12CrtAllocatorEEES4_E12GetAllocatorEv:
 2795|  5.87k|    Allocator& GetAllocator() {
 2796|  5.87k|        RAPIDJSON_ASSERT(allocator_);
  ------------------
  |  |  437|  5.87k|#define RAPIDJSON_ASSERT(x) assert(x)
  ------------------
  |  Branch (2796:9): [True: 5.87k, False: 0]
  ------------------
 2797|  5.87k|        return *allocator_;
 2798|  5.87k|    }
_ZN9rapidjson12GenericValueINS_4UTF8IcEENS_19MemoryPoolAllocatorINS_12CrtAllocatorEEEEC2ENS_4TypeE:
  720|   267k|    explicit GenericValue(Type type) RAPIDJSON_NOEXCEPT : data_() {
  721|   267k|        static const uint16_t defaultFlags[] = {
  722|   267k|            kNullFlag, kFalseFlag, kTrueFlag, kObjectFlag, kArrayFlag, kShortStringFlag,
  723|   267k|            kNumberAnyFlag
  724|   267k|        };
  725|   267k|        RAPIDJSON_NOEXCEPT_ASSERT(type >= kNullType && type <= kNumberType);
  ------------------
  |  |  687|   267k|#define RAPIDJSON_NOEXCEPT_ASSERT(x) RAPIDJSON_ASSERT(x)
  |  |  ------------------
  |  |  |  |  437|   267k|#define RAPIDJSON_ASSERT(x) assert(x)
  |  |  ------------------
  ------------------
  |  Branch (725:9): [True: 267k, False: 0]
  |  Branch (725:9): [True: 267k, False: 0]
  |  Branch (725:9): [True: 267k, False: 0]
  ------------------
  726|   267k|        data_.f.flags = defaultFlags[type];
  727|       |
  728|       |        // Use ShortString to store empty string.
  729|   267k|        if (type == kStringType)
  ------------------
  |  Branch (729:13): [True: 0, False: 267k]
  ------------------
  730|      0|            data_.ss.SetLength(0);
  731|   267k|    }
_ZN9rapidjson16GenericStringRefIcEC2ERKS1_:
  414|  1.08k|    GenericStringRef(const GenericStringRef& rhs) : s(rhs.s), length(rhs.length) {}
_ZN9rapidjson12GenericValueINS_4UTF8IcEENS_19MemoryPoolAllocatorINS_12CrtAllocatorEEEEC2ENS_16GenericStringRefIcEE:
  840|  1.08k|    explicit GenericValue(StringRefType s) RAPIDJSON_NOEXCEPT : data_() { SetStringRaw(s); }
_ZN9rapidjson12GenericValueINS_4UTF8IcEENS_19MemoryPoolAllocatorINS_12CrtAllocatorEEEE12SetStringRawENS_16GenericStringRefIcEE:
 2435|  14.6k|    void SetStringRaw(StringRefType s) RAPIDJSON_NOEXCEPT {
 2436|  14.6k|        data_.f.flags = kConstStringFlag;
 2437|  14.6k|        SetStringPointer(s);
 2438|  14.6k|        data_.s.length = s.length;
 2439|  14.6k|    }
_ZN9rapidjson12GenericValueINS_4UTF8IcEENS_19MemoryPoolAllocatorINS_12CrtAllocatorEEEE16SetStringPointerEPKc:
 2115|  14.6k|    RAPIDJSON_FORCEINLINE const Ch* SetStringPointer(const Ch* str) { return RAPIDJSON_SETPOINTER(Ch, data_.s.str, str); }
  ------------------
  |  |  346|  14.6k|#define RAPIDJSON_SETPOINTER(type, p, x) (p = reinterpret_cast<type *>((reinterpret_cast<uintptr_t>(p) & static_cast<uintptr_t>(RAPIDJSON_UINT64_C2(0xFFFF0000, 0x00000000))) | reinterpret_cast<uintptr_t>(reinterpret_cast<const void*>(x))))
  |  |  ------------------
  |  |  |  |  320|  14.6k|#define RAPIDJSON_UINT64_C2(high32, low32) ((static_cast<uint64_t>(high32) << 32) | static_cast<uint64_t>(low32))
  |  |  ------------------
  ------------------
_ZNK9rapidjson16GenericStringRefIcEcvPKcEv:
  417|  14.6k|    operator const Ch *() const { return s; }
_ZNK9rapidjson12GenericValueINS_4UTF8IcEENS_19MemoryPoolAllocatorINS_12CrtAllocatorEEEE8IsObjectEv:
 1116|  8.77k|    bool IsObject() const { return data_.f.flags == kObjectFlag; }
_ZNK9rapidjson12GenericValueINS_4UTF8IcEENS_19MemoryPoolAllocatorINS_12CrtAllocatorEEEE8IsStringEv:
 1124|  19.3k|    bool IsString() const { return (data_.f.flags & kStringFlag) != 0; }
_ZNK9rapidjson12GenericValueINS_4UTF8IcEENS_19MemoryPoolAllocatorINS_12CrtAllocatorEEEE17GetMembersPointerEv:
 2118|  6.57k|    RAPIDJSON_FORCEINLINE Member* GetMembersPointer() const { return RAPIDJSON_GETPOINTER(Member, data_.o.members); }
  ------------------
  |  |  347|  6.57k|#define RAPIDJSON_GETPOINTER(type, p) (reinterpret_cast<type *>(reinterpret_cast<uintptr_t>(p) & static_cast<uintptr_t>(RAPIDJSON_UINT64_C2(0x0000FFFF, 0xFFFFFFFF))))
  |  |  ------------------
  |  |  |  |  320|  6.57k|#define RAPIDJSON_UINT64_C2(high32, low32) ((static_cast<uint64_t>(high32) << 32) | static_cast<uint64_t>(low32))
  |  |  ------------------
  ------------------
_ZN9rapidjson12GenericValueINS_4UTF8IcEENS_19MemoryPoolAllocatorINS_12CrtAllocatorEEEE9RawAssignERS6_:
 2459|     44|    void RawAssign(GenericValue& rhs) RAPIDJSON_NOEXCEPT {
 2460|     44|        data_ = rhs.data_;
 2461|       |        // data_.f.flags = rhs.data_.f.flags;
 2462|     44|        rhs.data_.f.flags = kNullFlag;
 2463|     44|    }
_ZNK9rapidjson12GenericValueINS_4UTF8IcEENS_19MemoryPoolAllocatorINS_12CrtAllocatorEEEE7IsArrayEv:
 1117|    877|    bool IsArray()  const { return data_.f.flags == kArrayFlag; }
_ZN9rapidjson16GenericStringRefIcEC2EPKcj:
  412|  13.5k|        : s(RAPIDJSON_LIKELY(str) ? str : emptyString), length(len) { RAPIDJSON_ASSERT(str != 0 || len == 0u); }
  ------------------
  |  |  492|  13.5k|#define RAPIDJSON_LIKELY(x) __builtin_expect(!!(x), 1)
  |  |  ------------------
  |  |  |  Branch (492:29): [True: 13.5k, False: 0]
  |  |  ------------------
  ------------------
                      : s(RAPIDJSON_LIKELY(str) ? str : emptyString), length(len) { RAPIDJSON_ASSERT(str != 0 || len == 0u); }
  ------------------
  |  |  437|  13.5k|#define RAPIDJSON_ASSERT(x) assert(x)
  ------------------
  |  Branch (412:71): [True: 13.5k, False: 0]
  |  Branch (412:71): [True: 0, False: 0]
  |  Branch (412:71): [True: 13.5k, False: 0]
  ------------------
_ZN9rapidjson15GenericDocumentINS_4UTF8IcEENS_19MemoryPoolAllocatorINS_12CrtAllocatorEEES4_ED2Ev:
 2548|    102|    ~GenericDocument() {
 2549|       |        // Clear the ::ValueType before ownAllocator is destroyed, ~ValueType()
 2550|       |        // runs last and may access its elements or members which would be freed
 2551|       |        // with an allocator like MemoryPoolAllocator (CrtAllocator does not
 2552|       |        // free its data when destroyed, but MemoryPoolAllocator does).
 2553|    102|        if (ownAllocator_) {
  ------------------
  |  Branch (2553:13): [True: 102, False: 0]
  ------------------
 2554|    102|            ValueType::SetNull();
 2555|    102|        }
 2556|    102|        Destroy();
 2557|    102|    }
_ZN9rapidjson12GenericValueINS_4UTF8IcEENS_19MemoryPoolAllocatorINS_12CrtAllocatorEEEE7SetNullEv:
 1169|    102|    GenericValue& SetNull() { this->~GenericValue(); new (this) GenericValue(); return *this; }
_ZN9rapidjson15GenericDocumentINS_4UTF8IcEENS_19MemoryPoolAllocatorINS_12CrtAllocatorEEES4_E7DestroyEv:
 2877|    102|    void Destroy() {
 2878|    102|        RAPIDJSON_DELETE(ownAllocator_);
  ------------------
  |  |  716|    102|#define RAPIDJSON_DELETE(x) delete x
  ------------------
 2879|    102|    }
_ZNK9rapidjson12GenericValueINS_4UTF8IcEENS_19MemoryPoolAllocatorINS_12CrtAllocatorEEEE9GetStringEv:
 1853|  2.35k|    const Ch* GetString() const { RAPIDJSON_ASSERT(IsString()); return DataString(data_); }
  ------------------
  |  |  437|  2.35k|#define RAPIDJSON_ASSERT(x) assert(x)
  ------------------
  |  Branch (1853:35): [True: 2.35k, False: 0]
  ------------------
_ZN9rapidjson12GenericValueINS_4UTF8IcEENS_19MemoryPoolAllocatorINS_12CrtAllocatorEEEE10DataStringERKNS6_4DataE:
 2107|  2.35k|    static RAPIDJSON_FORCEINLINE const Ch* DataString(const Data& data) {
 2108|  2.35k|        return (data.f.flags & kInlineStrFlag) ? data.ss.str : RAPIDJSON_GETPOINTER(Ch, data.s.str);
  ------------------
  |  |  347|  2.35k|#define RAPIDJSON_GETPOINTER(type, p) (reinterpret_cast<type *>(reinterpret_cast<uintptr_t>(p) & static_cast<uintptr_t>(RAPIDJSON_UINT64_C2(0x0000FFFF, 0xFFFFFFFF))))
  |  |  ------------------
  |  |  |  |  320|  2.35k|#define RAPIDJSON_UINT64_C2(high32, low32) ((static_cast<uint64_t>(high32) << 32) | static_cast<uint64_t>(low32))
  |  |  ------------------
  ------------------
  |  Branch (2108:16): [True: 0, False: 2.35k]
  ------------------
 2109|  2.35k|    }
_ZNK9rapidjson12GenericValueINS_4UTF8IcEENS_19MemoryPoolAllocatorINS_12CrtAllocatorEEEE15GetStringLengthEv:
 1858|  7.90k|    SizeType GetStringLength() const { RAPIDJSON_ASSERT(IsString()); return DataStringLength(data_); }
  ------------------
  |  |  437|  7.90k|#define RAPIDJSON_ASSERT(x) assert(x)
  ------------------
  |  Branch (1858:40): [True: 7.90k, False: 0]
  ------------------
_ZN9rapidjson12GenericValueINS_4UTF8IcEENS_19MemoryPoolAllocatorINS_12CrtAllocatorEEEE16DataStringLengthERKNS6_4DataE:
 2110|  7.90k|    static RAPIDJSON_FORCEINLINE SizeType DataStringLength(const Data& data) {
 2111|  7.90k|        return (data.f.flags & kInlineStrFlag) ? data.ss.GetLength() : data.s.length;
  ------------------
  |  Branch (2111:16): [True: 0, False: 7.90k]
  ------------------
 2112|  7.90k|    }
_ZNK9rapidjson12GenericValueINS_4UTF8IcEENS_19MemoryPoolAllocatorINS_12CrtAllocatorEEEE18GetElementsPointerEv:
 2116|    509|    RAPIDJSON_FORCEINLINE GenericValue* GetElementsPointer() const { return RAPIDJSON_GETPOINTER(GenericValue, data_.a.elements); }
  ------------------
  |  |  347|    509|#define RAPIDJSON_GETPOINTER(type, p) (reinterpret_cast<type *>(reinterpret_cast<uintptr_t>(p) & static_cast<uintptr_t>(RAPIDJSON_UINT64_C2(0x0000FFFF, 0xFFFFFFFF))))
  |  |  ------------------
  |  |  |  |  320|    509|#define RAPIDJSON_UINT64_C2(high32, low32) ((static_cast<uint64_t>(high32) << 32) | static_cast<uint64_t>(low32))
  |  |  ------------------
  ------------------
_ZNK9rapidjson12GenericValueINS_4UTF8IcEENS_19MemoryPoolAllocatorINS_12CrtAllocatorEEEE5IsIntEv:
 1119|     69|    bool IsInt()    const { return (data_.f.flags & kIntFlag) != 0; }
_ZNK9rapidjson12GenericValueINS_4UTF8IcEENS_19MemoryPoolAllocatorINS_12CrtAllocatorEEEE6IsUintEv:
 1120|    113|    bool IsUint()   const { return (data_.f.flags & kUintFlag) != 0; }
_ZN9rapidjson12GenericValueINS_4UTF8IcEENS_19MemoryPoolAllocatorINS_12CrtAllocatorEEEE10FindMemberEPKc:
 1337|  1.08k|    MemberIterator FindMember(const Ch* name) {
 1338|  1.08k|        GenericValue n(StringRef(name));
 1339|  1.08k|        return FindMember(n);
 1340|  1.08k|    }
_ZN9rapidjson9StringRefIcEENS_16GenericStringRefIT_EEPKS2_:
  454|  1.08k|inline GenericStringRef<CharType> StringRef(const CharType* str) {
  455|  1.08k|    return GenericStringRef<CharType>(str);
  456|  1.08k|}
_ZN9rapidjson16GenericStringRefIcEC2EPKc:
  400|  1.08k|        : s(str), length(NotNullStrLen(str)) {}
_ZN9rapidjson16GenericStringRefIcE13NotNullStrLenEPKc:
  423|  1.08k|    SizeType NotNullStrLen(const CharType* str) {
  424|  1.08k|        RAPIDJSON_ASSERT(str != 0);
  ------------------
  |  |  437|  1.08k|#define RAPIDJSON_ASSERT(x) assert(x)
  ------------------
  |  Branch (424:9): [True: 1.08k, False: 0]
  ------------------
  425|  1.08k|        return internal::StrLen(str);
  426|  1.08k|    }
_ZN9rapidjson12GenericValueINS_4UTF8IcEENS_19MemoryPoolAllocatorINS_12CrtAllocatorEEEE10FindMemberIS5_EEPNS_13GenericMemberIS2_S5_EERKNS0_IS2_T_EE:
 1358|  1.08k|    MemberIterator FindMember(const GenericValue<Encoding, SourceAllocator>& name) {
 1359|  1.08k|        RAPIDJSON_ASSERT(IsObject());
  ------------------
  |  |  437|  1.08k|#define RAPIDJSON_ASSERT(x) assert(x)
  ------------------
  |  Branch (1359:9): [True: 1.08k, False: 0]
  ------------------
 1360|  1.08k|        RAPIDJSON_ASSERT(name.IsString());
  ------------------
  |  |  437|  1.08k|#define RAPIDJSON_ASSERT(x) assert(x)
  ------------------
  |  Branch (1360:9): [True: 1.08k, False: 0]
  ------------------
 1361|  1.08k|        return DoFindMember(name);
 1362|  1.08k|    }
_ZN9rapidjson12GenericValueINS_4UTF8IcEENS_19MemoryPoolAllocatorINS_12CrtAllocatorEEEE12DoFindMemberIS5_EEPNS_13GenericMemberIS2_S5_EERKNS0_IS2_T_EE:
 2282|  1.08k|    MemberIterator DoFindMember(const GenericValue<Encoding, SourceAllocator>& name) {
 2283|  1.08k|        MemberIterator member = MemberBegin();
 2284|  4.37k|        for ( ; member != MemberEnd(); ++member)
  ------------------
  |  Branch (2284:17): [True: 3.90k, False: 466]
  ------------------
 2285|  3.90k|            if (name.StringEqual(member->name))
  ------------------
  |  Branch (2285:17): [True: 616, False: 3.29k]
  ------------------
 2286|    616|                break;
 2287|  1.08k|        return member;
 2288|  1.08k|    }
_ZN9rapidjson12GenericValueINS_4UTF8IcEENS_19MemoryPoolAllocatorINS_12CrtAllocatorEEEE11MemberBeginEv:
 1274|  1.09k|    MemberIterator MemberBegin()            { RAPIDJSON_ASSERT(IsObject()); return MemberIterator(GetMembersPointer()); }
  ------------------
  |  |  437|  1.09k|#define RAPIDJSON_ASSERT(x) assert(x)
  ------------------
  |  Branch (1274:47): [True: 1.09k, False: 0]
  ------------------
_ZNK9rapidjson12GenericValueINS_4UTF8IcEENS_19MemoryPoolAllocatorINS_12CrtAllocatorEEEE11StringEqualIS5_EEbRKNS0_IS2_T_EE:
 2466|  3.90k|    bool StringEqual(const GenericValue<Encoding, SourceAllocator>& rhs) const {
 2467|  3.90k|        RAPIDJSON_ASSERT(IsString());
  ------------------
  |  |  437|  3.90k|#define RAPIDJSON_ASSERT(x) assert(x)
  ------------------
  |  Branch (2467:9): [True: 3.90k, False: 0]
  ------------------
 2468|  3.90k|        RAPIDJSON_ASSERT(rhs.IsString());
  ------------------
  |  |  437|  3.90k|#define RAPIDJSON_ASSERT(x) assert(x)
  ------------------
  |  Branch (2468:9): [True: 3.90k, False: 0]
  ------------------
 2469|       |
 2470|  3.90k|        const SizeType len1 = GetStringLength();
 2471|  3.90k|        const SizeType len2 = rhs.GetStringLength();
 2472|  3.90k|        if(len1 != len2) { return false; }
  ------------------
  |  Branch (2472:12): [True: 2.83k, False: 1.07k]
  ------------------
 2473|       |
 2474|  1.07k|        const Ch* const str1 = GetString();
 2475|  1.07k|        const Ch* const str2 = rhs.GetString();
 2476|  1.07k|        if(str1 == str2) { return true; } // fast path for constant string
  ------------------
  |  Branch (2476:12): [True: 0, False: 1.07k]
  ------------------
 2477|       |
 2478|  1.07k|        return (std::memcmp(str1, str2, sizeof(Ch) * len1) == 0);
 2479|  1.07k|    }
_ZN9rapidjson12GenericValueINS_4UTF8IcEENS_19MemoryPoolAllocatorINS_12CrtAllocatorEEEE9MemberEndEv:
 1277|  5.48k|    MemberIterator MemberEnd()              { RAPIDJSON_ASSERT(IsObject()); return MemberIterator(GetMembersPointer() + data_.o.size); }
  ------------------
  |  |  437|  5.48k|#define RAPIDJSON_ASSERT(x) assert(x)
  ------------------
  |  Branch (1277:47): [True: 5.48k, False: 0]
  ------------------
_ZNK9rapidjson12GenericValueINS_4UTF8IcEENS_19MemoryPoolAllocatorINS_12CrtAllocatorEEEE4SizeEv:
 1643|    182|    SizeType Size() const { RAPIDJSON_ASSERT(IsArray()); return data_.a.size; }
  ------------------
  |  |  437|    182|#define RAPIDJSON_ASSERT(x) assert(x)
  ------------------
  |  Branch (1643:29): [True: 182, False: 0]
  ------------------
_ZN9rapidjson12GenericValueINS_4UTF8IcEENS_19MemoryPoolAllocatorINS_12CrtAllocatorEEEEixEj:
 1668|    509|    GenericValue& operator[](SizeType index) {
 1669|    509|        RAPIDJSON_ASSERT(IsArray());
  ------------------
  |  |  437|    509|#define RAPIDJSON_ASSERT(x) assert(x)
  ------------------
  |  Branch (1669:9): [True: 509, False: 0]
  ------------------
 1670|    509|        RAPIDJSON_ASSERT(index < data_.a.size);
  ------------------
  |  |  437|    509|#define RAPIDJSON_ASSERT(x) assert(x)
  ------------------
  |  Branch (1670:9): [True: 509, False: 0]
  ------------------
 1671|    509|        return GetElementsPointer()[index];
 1672|    509|    }
_ZNK9rapidjson12GenericValueINS_4UTF8IcEENS_19MemoryPoolAllocatorINS_12CrtAllocatorEEEE8IsNumberEv:
 1118|    394|    bool IsNumber() const { return (data_.f.flags & kNumberFlag) != 0; }
_ZNK9rapidjson12GenericValueINS_4UTF8IcEENS_19MemoryPoolAllocatorINS_12CrtAllocatorEEEE9GetDoubleEv:
 1825|    197|    double GetDouble() const {
 1826|    197|        RAPIDJSON_ASSERT(IsNumber());
  ------------------
  |  |  437|    197|#define RAPIDJSON_ASSERT(x) assert(x)
  ------------------
  |  Branch (1826:9): [True: 197, False: 0]
  ------------------
 1827|    197|        if ((data_.f.flags & kDoubleFlag) != 0)                return data_.n.d;   // exact type, no conversion.
  ------------------
  |  Branch (1827:13): [True: 41, False: 156]
  ------------------
 1828|    156|        if ((data_.f.flags & kIntFlag) != 0)                   return data_.n.i.i; // int -> double
  ------------------
  |  Branch (1828:13): [True: 156, False: 0]
  ------------------
 1829|      0|        if ((data_.f.flags & kUintFlag) != 0)                  return data_.n.u.u; // unsigned -> double
  ------------------
  |  Branch (1829:13): [True: 0, False: 0]
  ------------------
 1830|      0|        if ((data_.f.flags & kInt64Flag) != 0)                 return static_cast<double>(data_.n.i64); // int64_t -> double (may lose precision)
  ------------------
  |  Branch (1830:13): [True: 0, False: 0]
  ------------------
 1831|      0|        RAPIDJSON_ASSERT((data_.f.flags & kUint64Flag) != 0);  return static_cast<double>(data_.n.u64); // uint64_t -> double (may lose precision)
  ------------------
  |  |  437|      0|#define RAPIDJSON_ASSERT(x) assert(x)
  ------------------
  |  Branch (1831:9): [True: 0, False: 0]
  ------------------
 1832|      0|    }
_ZNK9rapidjson12GenericValueINS_4UTF8IcEENS_19MemoryPoolAllocatorINS_12CrtAllocatorEEEE6GetIntEv:
 1817|     69|    int GetInt() const          { RAPIDJSON_ASSERT(data_.f.flags & kIntFlag);   return data_.n.i.i;   }
  ------------------
  |  |  437|     69|#define RAPIDJSON_ASSERT(x) assert(x)
  ------------------
  |  Branch (1817:35): [True: 69, False: 0]
  ------------------
_ZNK9rapidjson12GenericValueINS_4UTF8IcEENS_19MemoryPoolAllocatorINS_12CrtAllocatorEEEE6IsBoolEv:
 1115|     16|    bool IsBool()   const { return (data_.f.flags & kBoolFlag) != 0; }
_ZNK9rapidjson12GenericValueINS_4UTF8IcEENS_19MemoryPoolAllocatorINS_12CrtAllocatorEEEE7GetBoolEv:
 1176|      8|    bool GetBool() const { RAPIDJSON_ASSERT(IsBool()); return data_.f.flags == kTrueFlag; }
  ------------------
  |  |  437|      8|#define RAPIDJSON_ASSERT(x) assert(x)
  ------------------
  |  Branch (1176:28): [True: 8, False: 0]
  ------------------
_ZNK9rapidjson12GenericValueINS_4UTF8IcEENS_19MemoryPoolAllocatorINS_12CrtAllocatorEEEE8IsUint64Ev:
 1122|     43|    bool IsUint64() const { return (data_.f.flags & kUint64Flag) != 0; }
_ZNK9rapidjson12GenericValueINS_4UTF8IcEENS_19MemoryPoolAllocatorINS_12CrtAllocatorEEEE9GetUint64Ev:
 1820|     43|    uint64_t GetUint64() const  { RAPIDJSON_ASSERT(data_.f.flags & kUint64Flag); return data_.n.u64; }
  ------------------
  |  |  437|     43|#define RAPIDJSON_ASSERT(x) assert(x)
  ------------------
  |  Branch (1820:35): [True: 43, False: 0]
  ------------------
_ZN9rapidjson12GenericValueINS_4UTF8IcEENS_19MemoryPoolAllocatorINS_12CrtAllocatorEEEEC2Ej:
  798|   814k|    explicit GenericValue(unsigned u) RAPIDJSON_NOEXCEPT : data_() {
  799|   814k|        data_.n.u64 = u; 
  800|   814k|        data_.f.flags = (u & 0x80000000) ? kNumberUintFlag : (kNumberUintFlag | kIntFlag | kInt64Flag);
  ------------------
  |  Branch (800:25): [True: 946, False: 813k]
  ------------------
  801|   814k|    }
_ZN9rapidjson12GenericValueINS_4UTF8IcEENS_19MemoryPoolAllocatorINS_12CrtAllocatorEEEEC2Ei:
  792|    155|    explicit GenericValue(int i) RAPIDJSON_NOEXCEPT : data_() {
  793|    155|        data_.n.i64 = i;
  794|    155|        data_.f.flags = (i >= 0) ? (kNumberIntFlag | kUintFlag | kUint64Flag) : kNumberIntFlag;
  ------------------
  |  Branch (794:25): [True: 0, False: 155]
  ------------------
  795|    155|    }
_ZN9rapidjson12GenericValueINS_4UTF8IcEENS_19MemoryPoolAllocatorINS_12CrtAllocatorEEEE18SetElementsPointerEPS6_:
 2117|  2.29k|    RAPIDJSON_FORCEINLINE GenericValue* SetElementsPointer(GenericValue* elements) { return RAPIDJSON_SETPOINTER(GenericValue, data_.a.elements, elements); }
  ------------------
  |  |  346|  2.29k|#define RAPIDJSON_SETPOINTER(type, p, x) (p = reinterpret_cast<type *>((reinterpret_cast<uintptr_t>(p) & static_cast<uintptr_t>(RAPIDJSON_UINT64_C2(0xFFFF0000, 0x00000000))) | reinterpret_cast<uintptr_t>(reinterpret_cast<const void*>(x))))
  |  |  ------------------
  |  |  |  |  320|  2.29k|#define RAPIDJSON_UINT64_C2(high32, low32) ((static_cast<uint64_t>(high32) << 32) | static_cast<uint64_t>(low32))
  |  |  ------------------
  ------------------
_ZN9rapidjson12GenericValueINS_4UTF8IcEENS_19MemoryPoolAllocatorINS_12CrtAllocatorEEEEC2Ed:
  831|  6.78k|    explicit GenericValue(double d) RAPIDJSON_NOEXCEPT : data_() { data_.n.d = d; data_.f.flags = kNumberDoubleFlag; }
_ZN9rapidjson12GenericValueINS_4UTF8IcEENS_19MemoryPoolAllocatorINS_12CrtAllocatorEEEEC2El:
  804|     12|    explicit GenericValue(int64_t i64) RAPIDJSON_NOEXCEPT : data_() {
  805|     12|        data_.n.i64 = i64;
  806|     12|        data_.f.flags = kNumberInt64Flag;
  807|     12|        if (i64 >= 0) {
  ------------------
  |  Branch (807:13): [True: 0, False: 12]
  ------------------
  808|      0|            data_.f.flags |= kNumberUint64Flag;
  809|      0|            if (!(static_cast<uint64_t>(i64) & RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0x00000000)))
  ------------------
  |  |  320|      0|#define RAPIDJSON_UINT64_C2(high32, low32) ((static_cast<uint64_t>(high32) << 32) | static_cast<uint64_t>(low32))
  ------------------
  |  Branch (809:17): [True: 0, False: 0]
  ------------------
  810|      0|                data_.f.flags |= kUintFlag;
  811|      0|            if (!(static_cast<uint64_t>(i64) & RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0x80000000)))
  ------------------
  |  |  320|      0|#define RAPIDJSON_UINT64_C2(high32, low32) ((static_cast<uint64_t>(high32) << 32) | static_cast<uint64_t>(low32))
  ------------------
  |  Branch (811:17): [True: 0, False: 0]
  ------------------
  812|      0|                data_.f.flags |= kIntFlag;
  813|      0|        }
  814|     12|        else if (i64 >= static_cast<int64_t>(RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0x80000000)))
  ------------------
  |  |  320|     12|#define RAPIDJSON_UINT64_C2(high32, low32) ((static_cast<uint64_t>(high32) << 32) | static_cast<uint64_t>(low32))
  ------------------
  |  Branch (814:18): [True: 0, False: 12]
  ------------------
  815|      0|            data_.f.flags |= kIntFlag;
  816|     12|    }
_ZN9rapidjson12GenericValueINS_4UTF8IcEENS_19MemoryPoolAllocatorINS_12CrtAllocatorEEEEC2Em:
  819|  7.06k|    explicit GenericValue(uint64_t u64) RAPIDJSON_NOEXCEPT : data_() {
  820|  7.06k|        data_.n.u64 = u64;
  821|  7.06k|        data_.f.flags = kNumberUint64Flag;
  822|  7.06k|        if (!(u64 & RAPIDJSON_UINT64_C2(0x80000000, 0x00000000)))
  ------------------
  |  |  320|  7.06k|#define RAPIDJSON_UINT64_C2(high32, low32) ((static_cast<uint64_t>(high32) << 32) | static_cast<uint64_t>(low32))
  ------------------
  |  Branch (822:13): [True: 3.76k, False: 3.29k]
  ------------------
  823|  3.76k|            data_.f.flags |= kInt64Flag;
  824|  7.06k|        if (!(u64 & RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0x00000000)))
  ------------------
  |  |  320|  7.06k|#define RAPIDJSON_UINT64_C2(high32, low32) ((static_cast<uint64_t>(high32) << 32) | static_cast<uint64_t>(low32))
  ------------------
  |  Branch (824:13): [True: 0, False: 7.06k]
  ------------------
  825|      0|            data_.f.flags |= kUintFlag;
  826|  7.06k|        if (!(u64 & RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0x80000000)))
  ------------------
  |  |  320|  7.06k|#define RAPIDJSON_UINT64_C2(high32, low32) ((static_cast<uint64_t>(high32) << 32) | static_cast<uint64_t>(low32))
  ------------------
  |  Branch (826:13): [True: 0, False: 7.06k]
  ------------------
  827|      0|            data_.f.flags |= kIntFlag;
  828|  7.06k|    }
_ZN9rapidjson15GenericDocumentINS_4UTF8IcEENS_19MemoryPoolAllocatorINS_12CrtAllocatorEEES4_E11ParseInsituEPc:
 2694|    102|    GenericDocument& ParseInsitu(Ch* str) {
 2695|    102|        return ParseInsitu<kParseDefaultFlags>(str);
 2696|    102|    }
_ZN9rapidjson15GenericDocumentINS_4UTF8IcEENS_19MemoryPoolAllocatorINS_12CrtAllocatorEEES4_E11ParseInsituILj0EEERS6_Pc:
 2685|    102|    GenericDocument& ParseInsitu(Ch* str) {
 2686|    102|        GenericInsituStringStream<Encoding> s(str);
 2687|    102|        return ParseStream<parseFlags | kParseInsituFlag>(s);
 2688|    102|    }
_ZN9rapidjson15GenericDocumentINS_4UTF8IcEENS_19MemoryPoolAllocatorINS_12CrtAllocatorEEES4_E11ParseStreamILj1ENS_25GenericInsituStringStreamIS2_EEEERS6_RT0_:
 2661|    102|    GenericDocument& ParseStream(InputStream& is) {
 2662|    102|        return ParseStream<parseFlags, Encoding, InputStream>(is);
 2663|    102|    }
_ZN9rapidjson15GenericDocumentINS_4UTF8IcEENS_19MemoryPoolAllocatorINS_12CrtAllocatorEEES4_E11ParseStreamILj1ES2_NS_25GenericInsituStringStreamIS2_EEEERS6_RT1_:
 2642|    102|    GenericDocument& ParseStream(InputStream& is) {
 2643|    102|        GenericReader<SourceEncoding, Encoding, StackAllocator> reader(
 2644|    102|            stack_.HasAllocator() ? &stack_.GetAllocator() : 0);
  ------------------
  |  Branch (2644:13): [True: 0, False: 102]
  ------------------
 2645|    102|        ClearStackOnExit scope(*this);
 2646|    102|        parseResult_ = reader.template Parse<parseFlags>(is, *this);
 2647|    102|        if (parseResult_) {
  ------------------
  |  Branch (2647:13): [True: 22, False: 80]
  ------------------
 2648|     22|            RAPIDJSON_ASSERT(stack_.GetSize() == sizeof(ValueType)); // Got one and only one root object
  ------------------
  |  |  437|     22|#define RAPIDJSON_ASSERT(x) assert(x)
  ------------------
  |  Branch (2648:13): [True: 22, False: 0]
  ------------------
 2649|     22|            ValueType::operator=(*stack_.template Pop<ValueType>(1));// Move value from stack to document
 2650|     22|        }
 2651|    102|        return *this;
 2652|    102|    }
_ZN9rapidjson15GenericDocumentINS_4UTF8IcEENS_19MemoryPoolAllocatorINS_12CrtAllocatorEEES4_E10ClearStackEv:
 2868|    102|    void ClearStack() {
 2869|    102|        if (Allocator::kNeedFree)
  ------------------
  |  Branch (2869:13): [Folded, False: 102]
  ------------------
 2870|      0|            while (stack_.GetSize() > 0)    // Here assumes all elements in stack array are GenericValue (Member is actually 2 GenericValue objects)
  ------------------
  |  Branch (2870:20): [True: 0, False: 0]
  ------------------
 2871|      0|                (stack_.template Pop<ValueType>(1))->~ValueType();
 2872|    102|        else
 2873|    102|            stack_.Clear();
 2874|    102|        stack_.ShrinkToFit();
 2875|    102|    }
_ZN9rapidjson15GenericDocumentINS_4UTF8IcEENS_19MemoryPoolAllocatorINS_12CrtAllocatorEEES4_E11StartObjectEv:
 2844|  3.57k|    bool StartObject() { new (stack_.template Push<ValueType>()) ValueType(kObjectType); return true; }
_ZN9rapidjson15GenericDocumentINS_4UTF8IcEENS_19MemoryPoolAllocatorINS_12CrtAllocatorEEES4_E10StartArrayEv:
 2854|   263k|    bool StartArray() { new (stack_.template Push<ValueType>()) ValueType(kArrayType); return true; }
_ZN9rapidjson15GenericDocumentINS_4UTF8IcEENS_19MemoryPoolAllocatorINS_12CrtAllocatorEEES4_E3KeyEPKcjb:
 2846|  11.5k|    bool Key(const Ch* str, SizeType length, bool copy) { return String(str, length, copy); }
_ZN9rapidjson15GenericDocumentINS_4UTF8IcEENS_19MemoryPoolAllocatorINS_12CrtAllocatorEEES4_E6StringEPKcjb:
 2836|  13.5k|    bool String(const Ch* str, SizeType length, bool copy) { 
 2837|  13.5k|        if (copy) 
  ------------------
  |  Branch (2837:13): [True: 0, False: 13.5k]
  ------------------
 2838|      0|            new (stack_.template Push<ValueType>()) ValueType(str, length, GetAllocator());
 2839|  13.5k|        else
 2840|  13.5k|            new (stack_.template Push<ValueType>()) ValueType(str, length);
 2841|  13.5k|        return true;
 2842|  13.5k|    }
_ZN9rapidjson9StringRefIcEENS_16GenericStringRefIT_EEPKS2_m:
  474|  13.5k|inline GenericStringRef<CharType> StringRef(const CharType* str, size_t length) {
  475|  13.5k|    return GenericStringRef<CharType>(str, SizeType(length));
  476|  13.5k|}
_ZN9rapidjson15GenericDocumentINS_4UTF8IcEENS_19MemoryPoolAllocatorINS_12CrtAllocatorEEES4_E9EndObjectEj:
 2848|  3.57k|    bool EndObject(SizeType memberCount) {
 2849|  3.57k|        typename ValueType::Member* members = stack_.template Pop<typename ValueType::Member>(memberCount);
 2850|  3.57k|        stack_.template Top<ValueType>()->SetObjectRaw(members, memberCount, GetAllocator());
 2851|  3.57k|        return true;
 2852|  3.57k|    }
_ZN9rapidjson12GenericValueINS_4UTF8IcEENS_19MemoryPoolAllocatorINS_12CrtAllocatorEEEE12SetObjectRawEPNS_13GenericMemberIS2_S5_EEjRS5_:
 2415|  3.57k|    void SetObjectRaw(Member* members, SizeType count, Allocator& allocator) {
 2416|  3.57k|        data_.f.flags = kObjectFlag;
 2417|  3.57k|        if (count) {
  ------------------
  |  Branch (2417:13): [True: 3.55k, False: 14]
  ------------------
 2418|  3.55k|            Member* m = DoAllocMembers(count, allocator);
 2419|  3.55k|            SetMembersPointer(m);
 2420|  3.55k|            std::memcpy(static_cast<void*>(m), members, count * sizeof(Member));
 2421|       |#if RAPIDJSON_USE_MEMBERSMAP
 2422|       |            Map* &map = GetMap(m);
 2423|       |            MapIterator* mit = GetMapIterators(map);
 2424|       |            for (SizeType i = 0; i < count; i++) {
 2425|       |                new (&mit[i]) MapIterator(map->insert(MapPair(m[i].name.data_, i)));
 2426|       |            }
 2427|       |#endif
 2428|  3.55k|        }
 2429|     14|        else
 2430|     14|            SetMembersPointer(0);
 2431|  3.57k|        data_.o.size = data_.o.capacity = count;
 2432|  3.57k|    }
_ZN9rapidjson12GenericValueINS_4UTF8IcEENS_19MemoryPoolAllocatorINS_12CrtAllocatorEEEE14DoAllocMembersEjRS5_:
 2268|  3.55k|    RAPIDJSON_FORCEINLINE Member* DoAllocMembers(SizeType capacity, Allocator& allocator) {
 2269|  3.55k|        return Malloc<Member>(allocator, capacity);
 2270|  3.55k|    }
_ZN9rapidjson12GenericValueINS_4UTF8IcEENS_19MemoryPoolAllocatorINS_12CrtAllocatorEEEE17SetMembersPointerEPNS_13GenericMemberIS2_S5_EE:
 2119|  3.57k|    RAPIDJSON_FORCEINLINE Member* SetMembersPointer(Member* members) { return RAPIDJSON_SETPOINTER(Member, data_.o.members, members); }
  ------------------
  |  |  346|  3.57k|#define RAPIDJSON_SETPOINTER(type, p, x) (p = reinterpret_cast<type *>((reinterpret_cast<uintptr_t>(p) & static_cast<uintptr_t>(RAPIDJSON_UINT64_C2(0xFFFF0000, 0x00000000))) | reinterpret_cast<uintptr_t>(reinterpret_cast<const void*>(x))))
  |  |  ------------------
  |  |  |  |  320|  3.57k|#define RAPIDJSON_UINT64_C2(high32, low32) ((static_cast<uint64_t>(high32) << 32) | static_cast<uint64_t>(low32))
  |  |  ------------------
  ------------------
_ZN9rapidjson15GenericDocumentINS_4UTF8IcEENS_19MemoryPoolAllocatorINS_12CrtAllocatorEEES4_E8EndArrayEj:
 2856|  2.29k|    bool EndArray(SizeType elementCount) {
 2857|  2.29k|        ValueType* elements = stack_.template Pop<ValueType>(elementCount);
 2858|  2.29k|        stack_.template Top<ValueType>()->SetArrayRaw(elements, elementCount, GetAllocator());
 2859|  2.29k|        return true;
 2860|  2.29k|    }
_ZN9rapidjson12GenericValueINS_4UTF8IcEENS_19MemoryPoolAllocatorINS_12CrtAllocatorEEEE11SetArrayRawEPS6_jRS5_:
 2402|  2.29k|    void SetArrayRaw(GenericValue* values, SizeType count, Allocator& allocator) {
 2403|  2.29k|        data_.f.flags = kArrayFlag;
 2404|  2.29k|        if (count) {
  ------------------
  |  Branch (2404:13): [True: 2.28k, False: 16]
  ------------------
 2405|  2.28k|            GenericValue* e = static_cast<GenericValue*>(allocator.Malloc(count * sizeof(GenericValue)));
 2406|  2.28k|            SetElementsPointer(e);
 2407|  2.28k|            std::memcpy(static_cast<void*>(e), values, count * sizeof(GenericValue));
 2408|  2.28k|        }
 2409|     16|        else
 2410|     16|            SetElementsPointer(0);
 2411|  2.29k|        data_.a.size = data_.a.capacity = count;
 2412|  2.29k|    }
_ZN9rapidjson15GenericDocumentINS_4UTF8IcEENS_19MemoryPoolAllocatorINS_12CrtAllocatorEEES4_E4BoolEb:
 2821|    143|    bool Bool(bool b) { new (stack_.template Push<ValueType>()) ValueType(b); return true; }
_ZN9rapidjson15GenericDocumentINS_4UTF8IcEENS_19MemoryPoolAllocatorINS_12CrtAllocatorEEES4_E6DoubleEd:
 2826|  6.78k|    bool Double(double d) { new (stack_.template Push<ValueType>()) ValueType(d); return true; }
_ZN9rapidjson15GenericDocumentINS_4UTF8IcEENS_19MemoryPoolAllocatorINS_12CrtAllocatorEEES4_E5Int64El:
 2824|     12|    bool Int64(int64_t i) { new (stack_.template Push<ValueType>()) ValueType(i); return true; }
_ZN9rapidjson15GenericDocumentINS_4UTF8IcEENS_19MemoryPoolAllocatorINS_12CrtAllocatorEEES4_E6Uint64Em:
 2825|  7.06k|    bool Uint64(uint64_t i) { new (stack_.template Push<ValueType>()) ValueType(i); return true; }
_ZN9rapidjson15GenericDocumentINS_4UTF8IcEENS_19MemoryPoolAllocatorINS_12CrtAllocatorEEES4_E3IntEi:
 2822|    155|    bool Int(int i) { new (stack_.template Push<ValueType>()) ValueType(i); return true; }
_ZN9rapidjson15GenericDocumentINS_4UTF8IcEENS_19MemoryPoolAllocatorINS_12CrtAllocatorEEES4_E4UintEj:
 2823|   814k|    bool Uint(unsigned i) { new (stack_.template Push<ValueType>()) ValueType(i); return true; }
_ZN9rapidjson12GenericValueINS_4UTF8IcEENS_19MemoryPoolAllocatorINS_12CrtAllocatorEEEEaSERS6_:
  921|     22|    GenericValue& operator=(GenericValue& rhs) RAPIDJSON_NOEXCEPT {
  922|     22|        if (RAPIDJSON_LIKELY(this != &rhs)) {
  ------------------
  |  |  492|     22|#define RAPIDJSON_LIKELY(x) __builtin_expect(!!(x), 1)
  |  |  ------------------
  |  |  |  Branch (492:29): [True: 22, False: 0]
  |  |  ------------------
  ------------------
  923|       |            // Can't destroy "this" before assigning "rhs", otherwise "rhs"
  924|       |            // could be used after free if it's an sub-Value of "this",
  925|       |            // hence the temporary danse.
  926|     22|            GenericValue temp;
  927|     22|            temp.RawAssign(rhs);
  928|     22|            this->~GenericValue();
  929|     22|            RawAssign(temp);
  930|     22|        }
  931|     22|        return *this;
  932|     22|    }
_ZNK9rapidjson15GenericDocumentINS_4UTF8IcEENS_19MemoryPoolAllocatorINS_12CrtAllocatorEEES4_E13HasParseErrorEv:
 2771|    102|    bool HasParseError() const { return parseResult_.IsError(); }
_ZNK9rapidjson15GenericDocumentINS_4UTF8IcEENS_19MemoryPoolAllocatorINS_12CrtAllocatorEEES4_E14GetErrorOffsetEv:
 2777|     80|    size_t GetErrorOffset() const { return parseResult_.Offset(); }
_ZNK9rapidjson15GenericDocumentINS_4UTF8IcEENS_19MemoryPoolAllocatorINS_12CrtAllocatorEEES4_E13GetParseErrorEv:
 2774|     80|    ParseErrorCode GetParseError() const { return parseResult_.Code(); }
_ZN9rapidjson12GenericValueINS_4UTF8IcEENS_19MemoryPoolAllocatorINS_12CrtAllocatorEEEEC2IbEET_PNS_8internal8EnableIfINS9_15RemoveSfinaeTagIPFRNS9_9SfinaeTagENS9_6IsSameIbS8_EEEE4TypeEvE4TypeE:
  785|    143|        : data_() {
  786|       |            // safe-guard against failing SFINAE
  787|    143|            RAPIDJSON_STATIC_ASSERT((internal::IsSame<bool,T>::Value));
  ------------------
  |  |  447|    143|   static_assert(x, RAPIDJSON_STRINGIFY(x))
  ------------------
  788|    143|            data_.f.flags = b ? kTrueFlag : kFalseFlag;
  ------------------
  |  Branch (788:29): [True: 41, False: 102]
  ------------------
  789|    143|    }
_ZNK9rapidjson12GenericValueINS_4UTF8IcEENS_19MemoryPoolAllocatorINS_12CrtAllocatorEEEE7GetUintEv:
 1818|    112|    unsigned GetUint() const    { RAPIDJSON_ASSERT(data_.f.flags & kUintFlag);  return data_.n.u.u;   }
  ------------------
  |  |  437|    112|#define RAPIDJSON_ASSERT(x) assert(x)
  ------------------
  |  Branch (1818:35): [True: 112, False: 0]
  ------------------
_ZN9rapidjson15GenericDocumentINS_4UTF8IcEENS_19MemoryPoolAllocatorINS_12CrtAllocatorEEES4_E16ClearStackOnExitC2ERS6_:
 2806|    102|        explicit ClearStackOnExit(GenericDocument& d) : d_(d) {}
_ZN9rapidjson12GenericValueINS_4UTF8IcEENS_19MemoryPoolAllocatorINS_12CrtAllocatorEEEEC2EPKcj:
  837|  13.5k|    GenericValue(const Ch* s, SizeType length) RAPIDJSON_NOEXCEPT : data_() { SetStringRaw(StringRef(s, length)); }
_ZN9rapidjson15GenericDocumentINS_4UTF8IcEENS_19MemoryPoolAllocatorINS_12CrtAllocatorEEES4_E16ClearStackOnExitD2Ev:
 2807|    102|        ~ClearStackOnExit() { d_.ClearStack(); }

_ZN9rapidjson10TranscoderINS_4UTF8IcEES2_E9TranscodeINS_25GenericInsituStringStreamIS2_EES6_EEbRT_RT0_:
  693|   242k|    static RAPIDJSON_FORCEINLINE bool Transcode(InputStream& is, OutputStream& os) {
  694|   242k|        os.Put(is.Take());  // Just copy one code unit. This semantic is different from primary template class.
  695|   242k|        return true;
  696|   242k|    }

_ZN9rapidjson16GetParseError_EnENS_14ParseErrorCodeE:
   36|     80|inline const RAPIDJSON_ERROR_CHARTYPE* GetParseError_En(ParseErrorCode parseErrorCode) {
   37|     80|    switch (parseErrorCode) {
   38|      0|        case kParseErrorNone:                           return RAPIDJSON_ERROR_STRING("No error.");
  ------------------
  |  |   52|      0|#define RAPIDJSON_ERROR_STRING(x) x
  ------------------
  |  Branch (38:9): [True: 0, False: 80]
  ------------------
   39|       |
   40|     14|        case kParseErrorDocumentEmpty:                  return RAPIDJSON_ERROR_STRING("The document is empty.");
  ------------------
  |  |   52|     14|#define RAPIDJSON_ERROR_STRING(x) x
  ------------------
  |  Branch (40:9): [True: 14, False: 66]
  ------------------
   41|      0|        case kParseErrorDocumentRootNotSingular:        return RAPIDJSON_ERROR_STRING("The document root must not be followed by other values.");
  ------------------
  |  |   52|      0|#define RAPIDJSON_ERROR_STRING(x) x
  ------------------
  |  Branch (41:9): [True: 0, False: 80]
  ------------------
   42|       |
   43|     60|        case kParseErrorValueInvalid:                   return RAPIDJSON_ERROR_STRING("Invalid value.");
  ------------------
  |  |   52|     60|#define RAPIDJSON_ERROR_STRING(x) x
  ------------------
  |  Branch (43:9): [True: 60, False: 20]
  ------------------
   44|       |
   45|      0|        case kParseErrorObjectMissName:                 return RAPIDJSON_ERROR_STRING("Missing a name for object member.");
  ------------------
  |  |   52|      0|#define RAPIDJSON_ERROR_STRING(x) x
  ------------------
  |  Branch (45:9): [True: 0, False: 80]
  ------------------
   46|      0|        case kParseErrorObjectMissColon:                return RAPIDJSON_ERROR_STRING("Missing a colon after a name of object member.");
  ------------------
  |  |   52|      0|#define RAPIDJSON_ERROR_STRING(x) x
  ------------------
  |  Branch (46:9): [True: 0, False: 80]
  ------------------
   47|      0|        case kParseErrorObjectMissCommaOrCurlyBracket:  return RAPIDJSON_ERROR_STRING("Missing a comma or '}' after an object member.");
  ------------------
  |  |   52|      0|#define RAPIDJSON_ERROR_STRING(x) x
  ------------------
  |  Branch (47:9): [True: 0, False: 80]
  ------------------
   48|       |
   49|      6|        case kParseErrorArrayMissCommaOrSquareBracket:  return RAPIDJSON_ERROR_STRING("Missing a comma or ']' after an array element.");
  ------------------
  |  |   52|      6|#define RAPIDJSON_ERROR_STRING(x) x
  ------------------
  |  Branch (49:9): [True: 6, False: 74]
  ------------------
   50|       |
   51|      0|        case kParseErrorStringUnicodeEscapeInvalidHex:  return RAPIDJSON_ERROR_STRING("Incorrect hex digit after \\u escape in string.");
  ------------------
  |  |   52|      0|#define RAPIDJSON_ERROR_STRING(x) x
  ------------------
  |  Branch (51:9): [True: 0, False: 80]
  ------------------
   52|      0|        case kParseErrorStringUnicodeSurrogateInvalid:  return RAPIDJSON_ERROR_STRING("The surrogate pair in string is invalid.");
  ------------------
  |  |   52|      0|#define RAPIDJSON_ERROR_STRING(x) x
  ------------------
  |  Branch (52:9): [True: 0, False: 80]
  ------------------
   53|      0|        case kParseErrorStringEscapeInvalid:            return RAPIDJSON_ERROR_STRING("Invalid escape character in string.");
  ------------------
  |  |   52|      0|#define RAPIDJSON_ERROR_STRING(x) x
  ------------------
  |  Branch (53:9): [True: 0, False: 80]
  ------------------
   54|      0|        case kParseErrorStringMissQuotationMark:        return RAPIDJSON_ERROR_STRING("Missing a closing quotation mark in string.");
  ------------------
  |  |   52|      0|#define RAPIDJSON_ERROR_STRING(x) x
  ------------------
  |  Branch (54:9): [True: 0, False: 80]
  ------------------
   55|      0|        case kParseErrorStringInvalidEncoding:          return RAPIDJSON_ERROR_STRING("Invalid encoding in string.");
  ------------------
  |  |   52|      0|#define RAPIDJSON_ERROR_STRING(x) x
  ------------------
  |  Branch (55:9): [True: 0, False: 80]
  ------------------
   56|       |
   57|      0|        case kParseErrorNumberTooBig:                   return RAPIDJSON_ERROR_STRING("Number too big to be stored in double.");
  ------------------
  |  |   52|      0|#define RAPIDJSON_ERROR_STRING(x) x
  ------------------
  |  Branch (57:9): [True: 0, False: 80]
  ------------------
   58|      0|        case kParseErrorNumberMissFraction:             return RAPIDJSON_ERROR_STRING("Miss fraction part in number.");
  ------------------
  |  |   52|      0|#define RAPIDJSON_ERROR_STRING(x) x
  ------------------
  |  Branch (58:9): [True: 0, False: 80]
  ------------------
   59|      0|        case kParseErrorNumberMissExponent:             return RAPIDJSON_ERROR_STRING("Miss exponent in number.");
  ------------------
  |  |   52|      0|#define RAPIDJSON_ERROR_STRING(x) x
  ------------------
  |  Branch (59:9): [True: 0, False: 80]
  ------------------
   60|       |
   61|      0|        case kParseErrorTermination:                    return RAPIDJSON_ERROR_STRING("Terminate parsing due to Handler error.");
  ------------------
  |  |   52|      0|#define RAPIDJSON_ERROR_STRING(x) x
  ------------------
  |  Branch (61:9): [True: 0, False: 80]
  ------------------
   62|      0|        case kParseErrorUnspecificSyntaxError:          return RAPIDJSON_ERROR_STRING("Unspecific syntax error.");
  ------------------
  |  |   52|      0|#define RAPIDJSON_ERROR_STRING(x) x
  ------------------
  |  Branch (62:9): [True: 0, False: 80]
  ------------------
   63|       |
   64|      0|        default:                                        return RAPIDJSON_ERROR_STRING("Unknown error.");
  ------------------
  |  |   52|      0|#define RAPIDJSON_ERROR_STRING(x) x
  ------------------
  |  Branch (64:9): [True: 0, False: 80]
  ------------------
   65|     80|    }
   66|     80|}

_ZN9rapidjson11ParseResultC2Ev:
  111|    204|    ParseResult() : code_(kParseErrorNone), offset_(0) {}
_ZNK9rapidjson11ParseResult4CodeEv:
  116|     80|    ParseErrorCode Code() const { return code_; }
_ZNK9rapidjson11ParseResult6OffsetEv:
  118|     80|    size_t Offset() const { return offset_; }
_ZNK9rapidjson11ParseResultcvMS0_KFbvEEv:
  121|    102|    operator BooleanType() const { return !IsError() ? &ParseResult::IsError : NULL; }
  ------------------
  |  Branch (121:43): [True: 22, False: 80]
  ------------------
_ZNK9rapidjson11ParseResult7IsErrorEv:
  123|  3.08M|    bool IsError() const { return code_ != kParseErrorNone; }
_ZN9rapidjson11ParseResult5ClearEv:
  134|    102|    void Clear() { Set(kParseErrorNone); }
_ZN9rapidjson11ParseResult3SetENS_14ParseErrorCodeEm:
  136|    182|    void Set(ParseErrorCode code, size_t offset = 0) { code_ = code; offset_ = offset; }

_ZN9rapidjson8internal5Pow10Ei:
   28|  6.78k|inline double Pow10(int n) {
   29|  6.78k|    static const double e[] = { // 1e-0...1e308: 309 * 8 bytes = 2472 bytes
   30|  6.78k|        1e+0,  
   31|  6.78k|        1e+1,  1e+2,  1e+3,  1e+4,  1e+5,  1e+6,  1e+7,  1e+8,  1e+9,  1e+10, 1e+11, 1e+12, 1e+13, 1e+14, 1e+15, 1e+16, 1e+17, 1e+18, 1e+19, 1e+20, 
   32|  6.78k|        1e+21, 1e+22, 1e+23, 1e+24, 1e+25, 1e+26, 1e+27, 1e+28, 1e+29, 1e+30, 1e+31, 1e+32, 1e+33, 1e+34, 1e+35, 1e+36, 1e+37, 1e+38, 1e+39, 1e+40,
   33|  6.78k|        1e+41, 1e+42, 1e+43, 1e+44, 1e+45, 1e+46, 1e+47, 1e+48, 1e+49, 1e+50, 1e+51, 1e+52, 1e+53, 1e+54, 1e+55, 1e+56, 1e+57, 1e+58, 1e+59, 1e+60,
   34|  6.78k|        1e+61, 1e+62, 1e+63, 1e+64, 1e+65, 1e+66, 1e+67, 1e+68, 1e+69, 1e+70, 1e+71, 1e+72, 1e+73, 1e+74, 1e+75, 1e+76, 1e+77, 1e+78, 1e+79, 1e+80,
   35|  6.78k|        1e+81, 1e+82, 1e+83, 1e+84, 1e+85, 1e+86, 1e+87, 1e+88, 1e+89, 1e+90, 1e+91, 1e+92, 1e+93, 1e+94, 1e+95, 1e+96, 1e+97, 1e+98, 1e+99, 1e+100,
   36|  6.78k|        1e+101,1e+102,1e+103,1e+104,1e+105,1e+106,1e+107,1e+108,1e+109,1e+110,1e+111,1e+112,1e+113,1e+114,1e+115,1e+116,1e+117,1e+118,1e+119,1e+120,
   37|  6.78k|        1e+121,1e+122,1e+123,1e+124,1e+125,1e+126,1e+127,1e+128,1e+129,1e+130,1e+131,1e+132,1e+133,1e+134,1e+135,1e+136,1e+137,1e+138,1e+139,1e+140,
   38|  6.78k|        1e+141,1e+142,1e+143,1e+144,1e+145,1e+146,1e+147,1e+148,1e+149,1e+150,1e+151,1e+152,1e+153,1e+154,1e+155,1e+156,1e+157,1e+158,1e+159,1e+160,
   39|  6.78k|        1e+161,1e+162,1e+163,1e+164,1e+165,1e+166,1e+167,1e+168,1e+169,1e+170,1e+171,1e+172,1e+173,1e+174,1e+175,1e+176,1e+177,1e+178,1e+179,1e+180,
   40|  6.78k|        1e+181,1e+182,1e+183,1e+184,1e+185,1e+186,1e+187,1e+188,1e+189,1e+190,1e+191,1e+192,1e+193,1e+194,1e+195,1e+196,1e+197,1e+198,1e+199,1e+200,
   41|  6.78k|        1e+201,1e+202,1e+203,1e+204,1e+205,1e+206,1e+207,1e+208,1e+209,1e+210,1e+211,1e+212,1e+213,1e+214,1e+215,1e+216,1e+217,1e+218,1e+219,1e+220,
   42|  6.78k|        1e+221,1e+222,1e+223,1e+224,1e+225,1e+226,1e+227,1e+228,1e+229,1e+230,1e+231,1e+232,1e+233,1e+234,1e+235,1e+236,1e+237,1e+238,1e+239,1e+240,
   43|  6.78k|        1e+241,1e+242,1e+243,1e+244,1e+245,1e+246,1e+247,1e+248,1e+249,1e+250,1e+251,1e+252,1e+253,1e+254,1e+255,1e+256,1e+257,1e+258,1e+259,1e+260,
   44|  6.78k|        1e+261,1e+262,1e+263,1e+264,1e+265,1e+266,1e+267,1e+268,1e+269,1e+270,1e+271,1e+272,1e+273,1e+274,1e+275,1e+276,1e+277,1e+278,1e+279,1e+280,
   45|  6.78k|        1e+281,1e+282,1e+283,1e+284,1e+285,1e+286,1e+287,1e+288,1e+289,1e+290,1e+291,1e+292,1e+293,1e+294,1e+295,1e+296,1e+297,1e+298,1e+299,1e+300,
   46|  6.78k|        1e+301,1e+302,1e+303,1e+304,1e+305,1e+306,1e+307,1e+308
   47|  6.78k|    };
   48|  6.78k|    RAPIDJSON_ASSERT(n >= 0 && n <= 308);
  ------------------
  |  |  437|  6.78k|#define RAPIDJSON_ASSERT(x) assert(x)
  ------------------
  |  Branch (48:5): [True: 6.78k, False: 0]
  |  Branch (48:5): [True: 6.78k, False: 0]
  |  Branch (48:5): [True: 6.78k, False: 0]
  ------------------
   49|  6.78k|    return e[n];
   50|  6.78k|}

_ZN9rapidjson8internal5StackINS_12CrtAllocatorEEC2EPS2_m:
   41|    204|    Stack(Allocator* allocator, size_t stackCapacity) : allocator_(allocator), ownAllocator_(0), stack_(0), stackTop_(0), stackEnd_(0), initialCapacity_(stackCapacity) {
   42|    204|    }
_ZN9rapidjson8internal5StackINS_12CrtAllocatorEED2Ev:
   62|    204|    ~Stack() {
   63|    204|        Destroy();
   64|    204|    }
_ZN9rapidjson8internal5StackINS_12CrtAllocatorEE7DestroyEv:
  208|    204|    void Destroy() {
  209|    204|        Allocator::Free(stack_);
  210|    204|        RAPIDJSON_DELETE(ownAllocator_); // Only delete if it is owned by the stack
  ------------------
  |  |  716|    204|#define RAPIDJSON_DELETE(x) delete x
  ------------------
  211|    204|    }
_ZNK9rapidjson8internal5StackINS_12CrtAllocatorEE7GetSizeEv:
  178|  12.3k|    size_t GetSize() const { return static_cast<size_t>(stackTop_ - stack_); }
_ZNK9rapidjson8internal5StackINS_12CrtAllocatorEE11GetCapacityEv:
  179|    546|    size_t GetCapacity() const { return static_cast<size_t>(stackEnd_ - stack_); }
_ZN9rapidjson8internal5StackINS_12CrtAllocatorEE6ResizeEm:
  201|    290|    void Resize(size_t newCapacity) {
  202|    290|        const size_t size = GetSize();  // Backup the current size
  203|    290|        stack_ = static_cast<char*>(allocator_->Realloc(stack_, GetCapacity(), newCapacity));
  204|    290|        stackTop_ = stack_ + size;
  205|    290|        stackEnd_ = stack_ + newCapacity;
  206|    290|    }
_ZNK9rapidjson8internal5StackINS_12CrtAllocatorEE5EmptyEv:
  177|    102|    bool Empty() const { return stackTop_ == stack_; }
_ZNK9rapidjson8internal5StackINS_12CrtAllocatorEE12HasAllocatorEv:
  168|    102|    bool HasAllocator() const {
  169|    102|        return allocator_ != 0;
  170|    102|    }
_ZN9rapidjson8internal5StackINS_12CrtAllocatorEE5ClearEv:
   99|    204|    void Clear() { stackTop_ = stack_; }
_ZN9rapidjson8internal5StackINS_12CrtAllocatorEE11ShrinkToFitEv:
  101|    102|    void ShrinkToFit() { 
  102|    102|        if (Empty()) {
  ------------------
  |  Branch (102:13): [True: 102, False: 0]
  ------------------
  103|       |            // If the stack is empty, completely deallocate the memory.
  104|    102|            Allocator::Free(stack_); // NOLINT (+clang-analyzer-unix.Malloc)
  105|    102|            stack_ = 0;
  106|    102|            stackTop_ = 0;
  107|    102|            stackEnd_ = 0;
  108|    102|        }
  109|      0|        else
  110|      0|            Resize(GetSize());
  111|    102|    }
_ZN9rapidjson8internal5StackINS_12CrtAllocatorEE4PushINS_12GenericValueINS_4UTF8IcEENS_19MemoryPoolAllocatorIS2_EEEEEEPT_m:
  123|  1.10M|    RAPIDJSON_FORCEINLINE T* Push(size_t count = 1) {
  124|  1.10M|        Reserve<T>(count);
  125|  1.10M|        return PushUnsafe<T>(count);
  126|  1.10M|    }
_ZN9rapidjson8internal5StackINS_12CrtAllocatorEE7ReserveINS_12GenericValueINS_4UTF8IcEENS_19MemoryPoolAllocatorIS2_EEEEEEvm:
  116|  1.10M|    RAPIDJSON_FORCEINLINE void Reserve(size_t count = 1) {
  117|       |         // Expand the stack if needed
  118|  1.10M|        if (RAPIDJSON_UNLIKELY(static_cast<std::ptrdiff_t>(sizeof(T) * count) > (stackEnd_ - stackTop_)))
  ------------------
  |  |  505|  1.10M|#define RAPIDJSON_UNLIKELY(x) __builtin_expect(!!(x), 0)
  |  |  ------------------
  |  |  |  Branch (505:31): [True: 290, False: 1.10M]
  |  |  ------------------
  ------------------
  119|    290|            Expand<T>(count);
  120|  1.10M|    }
_ZN9rapidjson8internal5StackINS_12CrtAllocatorEE6ExpandINS_12GenericValueINS_4UTF8IcEENS_19MemoryPoolAllocatorIS2_EEEEEEvm:
  183|    290|    void Expand(size_t count) {
  184|       |        // Only expand the capacity if the current stack exists. Otherwise just create a stack with initial capacity.
  185|    290|        size_t newCapacity;
  186|    290|        if (stack_ == 0) {
  ------------------
  |  Branch (186:13): [True: 34, False: 256]
  ------------------
  187|     34|            if (!allocator_)
  ------------------
  |  Branch (187:17): [True: 34, False: 0]
  ------------------
  188|     34|                ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator)();
  ------------------
  |  |  712|     34|#define RAPIDJSON_NEW(TypeName) new TypeName
  ------------------
  189|     34|            newCapacity = initialCapacity_;
  190|    256|        } else {
  191|    256|            newCapacity = GetCapacity();
  192|    256|            newCapacity += (newCapacity + 1) / 2;
  193|    256|        }
  194|    290|        size_t newSize = GetSize() + sizeof(T) * count;
  195|    290|        if (newCapacity < newSize)
  ------------------
  |  Branch (195:13): [True: 0, False: 290]
  ------------------
  196|      0|            newCapacity = newSize;
  197|       |
  198|    290|        Resize(newCapacity);
  199|    290|    }
_ZN9rapidjson8internal5StackINS_12CrtAllocatorEE10PushUnsafeINS_12GenericValueINS_4UTF8IcEENS_19MemoryPoolAllocatorIS2_EEEEEEPT_m:
  129|  1.10M|    RAPIDJSON_FORCEINLINE T* PushUnsafe(size_t count = 1) {
  130|  1.10M|        RAPIDJSON_ASSERT(stackTop_);
  ------------------
  |  |  437|  1.10M|#define RAPIDJSON_ASSERT(x) assert(x)
  ------------------
  |  Branch (130:9): [True: 1.10M, False: 0]
  ------------------
  131|  1.10M|        RAPIDJSON_ASSERT(static_cast<std::ptrdiff_t>(sizeof(T) * count) <= (stackEnd_ - stackTop_));
  ------------------
  |  |  437|  1.10M|#define RAPIDJSON_ASSERT(x) assert(x)
  ------------------
  |  Branch (131:9): [True: 1.10M, False: 0]
  ------------------
  132|  1.10M|        T* ret = reinterpret_cast<T*>(stackTop_);
  133|  1.10M|        stackTop_ += sizeof(T) * count;
  134|  1.10M|        return ret;
  135|  1.10M|    }
_ZN9rapidjson8internal5StackINS_12CrtAllocatorEE3PopINS_13GenericMemberINS_4UTF8IcEENS_19MemoryPoolAllocatorIS2_EEEEEEPT_m:
  138|  3.57k|    T* Pop(size_t count) {
  139|  3.57k|        RAPIDJSON_ASSERT(GetSize() >= count * sizeof(T));
  ------------------
  |  |  437|  3.57k|#define RAPIDJSON_ASSERT(x) assert(x)
  ------------------
  |  Branch (139:9): [True: 3.57k, False: 0]
  ------------------
  140|  3.57k|        stackTop_ -= count * sizeof(T);
  141|  3.57k|        return reinterpret_cast<T*>(stackTop_);
  142|  3.57k|    }
_ZN9rapidjson8internal5StackINS_12CrtAllocatorEE3TopINS_12GenericValueINS_4UTF8IcEENS_19MemoryPoolAllocatorIS2_EEEEEEPT_v:
  145|  5.87k|    T* Top() { 
  146|  5.87k|        RAPIDJSON_ASSERT(GetSize() >= sizeof(T));
  ------------------
  |  |  437|  5.87k|#define RAPIDJSON_ASSERT(x) assert(x)
  ------------------
  |  Branch (146:9): [True: 5.87k, False: 0]
  ------------------
  147|  5.87k|        return reinterpret_cast<T*>(stackTop_ - sizeof(T));
  148|  5.87k|    }
_ZN9rapidjson8internal5StackINS_12CrtAllocatorEE3PopINS_12GenericValueINS_4UTF8IcEENS_19MemoryPoolAllocatorIS2_EEEEEEPT_m:
  138|  2.32k|    T* Pop(size_t count) {
  139|  2.32k|        RAPIDJSON_ASSERT(GetSize() >= count * sizeof(T));
  ------------------
  |  |  437|  2.32k|#define RAPIDJSON_ASSERT(x) assert(x)
  ------------------
  |  Branch (139:9): [True: 2.32k, False: 0]
  ------------------
  140|  2.32k|        stackTop_ -= count * sizeof(T);
  141|  2.32k|        return reinterpret_cast<T*>(stackTop_);
  142|  2.32k|    }

_ZN9rapidjson8internal6StrLenIcEEjPKT_:
   39|  1.08k|inline SizeType StrLen(const char* s) {
   40|  1.08k|    return SizeType(std::strlen(s));
   41|  1.08k|}

_ZN9rapidjson8internal8FastPathEdi:
   28|  6.78k|inline double FastPath(double significand, int exp) {
   29|  6.78k|    if (exp < -308)
  ------------------
  |  Branch (29:9): [True: 0, False: 6.78k]
  ------------------
   30|      0|        return 0.0;
   31|  6.78k|    else if (exp >= 0)
  ------------------
  |  Branch (31:14): [True: 8, False: 6.78k]
  ------------------
   32|      8|        return significand * internal::Pow10(exp);
   33|  6.78k|    else
   34|  6.78k|        return significand / internal::Pow10(-exp);
   35|  6.78k|}
_ZN9rapidjson8internal21StrtodNormalPrecisionEdi:
   37|  6.78k|inline double StrtodNormalPrecision(double d, int p) {
   38|  6.78k|    if (p < -308) {
  ------------------
  |  Branch (38:9): [True: 0, False: 6.78k]
  ------------------
   39|       |        // Prevent expSum < -308, making Pow10(p) = 0
   40|      0|        d = FastPath(d, -308);
   41|      0|        d = FastPath(d, p + 308);
   42|      0|    }
   43|  6.78k|    else
   44|  6.78k|        d = FastPath(d, p);
   45|  6.78k|    return d;
   46|  6.78k|}

_ZN9rapidjson13GenericReaderINS_4UTF8IcEES2_NS_12CrtAllocatorEE5ParseILj1ENS_25GenericInsituStringStreamIS2_EENS_15GenericDocumentIS2_NS_19MemoryPoolAllocatorIS3_EES3_EEEENS_11ParseResultERT0_RT1_:
  559|    102|    ParseResult Parse(InputStream& is, Handler& handler) {
  560|    102|        if (parseFlags & kParseIterativeFlag)
  ------------------
  |  Branch (560:13): [Folded, False: 102]
  ------------------
  561|      0|            return IterativeParse<parseFlags>(is, handler);
  562|       |
  563|    102|        parseResult_.Clear();
  564|       |
  565|    102|        ClearStackOnExit scope(*this);
  566|       |
  567|    102|        SkipWhitespaceAndComments<parseFlags>(is);
  568|    102|        RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_);
  ------------------
  |  |   61|    102|    RAPIDJSON_MULTILINEMACRO_BEGIN \
  |  |  ------------------
  |  |  |  |  516|    102|#define RAPIDJSON_MULTILINEMACRO_BEGIN do {
  |  |  ------------------
  |  |   62|    102|    if (RAPIDJSON_UNLIKELY(HasParseError())) { return value; } \
  |  |  ------------------
  |  |  |  |  505|    102|#define RAPIDJSON_UNLIKELY(x) __builtin_expect(!!(x), 0)
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (505:31): [True: 0, False: 102]
  |  |  |  |  ------------------
  |  |  ------------------
  |  |   63|    102|    RAPIDJSON_MULTILINEMACRO_END
  |  |  ------------------
  |  |  |  |  517|    102|#define RAPIDJSON_MULTILINEMACRO_END \
  |  |  |  |  518|    102|} while((void)0, 0)
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (518:9): [Folded, False: 102]
  |  |  |  |  ------------------
  |  |  ------------------
  ------------------
  569|       |
  570|    102|        if (RAPIDJSON_UNLIKELY(is.Peek() == '\0')) {
  ------------------
  |  |  505|    102|#define RAPIDJSON_UNLIKELY(x) __builtin_expect(!!(x), 0)
  |  |  ------------------
  |  |  |  Branch (505:31): [True: 14, False: 88]
  |  |  ------------------
  ------------------
  571|     14|            RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorDocumentEmpty, is.Tell());
  ------------------
  |  |  101|     14|    RAPIDJSON_MULTILINEMACRO_BEGIN \
  |  |  ------------------
  |  |  |  |  516|     14|#define RAPIDJSON_MULTILINEMACRO_BEGIN do {
  |  |  ------------------
  |  |  102|     14|    RAPIDJSON_ASSERT(!HasParseError()); /* Error can only be assigned once */ \
  |  |  ------------------
  |  |  |  |  437|     14|#define RAPIDJSON_ASSERT(x) assert(x)
  |  |  ------------------
  |  |  103|     14|    SetParseError(parseErrorCode, offset); \
  |  |  104|     14|    RAPIDJSON_MULTILINEMACRO_END
  |  |  ------------------
  |  |  |  |  517|     14|#define RAPIDJSON_MULTILINEMACRO_END \
  |  |  |  |  518|     14|} while((void)0, 0)
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (518:9): [Folded, False: 14]
  |  |  |  |  ------------------
  |  |  ------------------
  ------------------
  |  Branch (571:13): [True: 14, False: 0]
  ------------------
  572|     14|            RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_);
  ------------------
  |  |   61|     28|    RAPIDJSON_MULTILINEMACRO_BEGIN \
  |  |  ------------------
  |  |  |  |  516|     14|#define RAPIDJSON_MULTILINEMACRO_BEGIN do {
  |  |  ------------------
  |  |   62|     28|    if (RAPIDJSON_UNLIKELY(HasParseError())) { return value; } \
  |  |  ------------------
  |  |  |  |  505|     14|#define RAPIDJSON_UNLIKELY(x) __builtin_expect(!!(x), 0)
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (505:31): [True: 14, False: 0]
  |  |  |  |  ------------------
  |  |  ------------------
  |  |   63|     28|    RAPIDJSON_MULTILINEMACRO_END
  |  |  ------------------
  |  |  |  |  517|     14|#define RAPIDJSON_MULTILINEMACRO_END \
  |  |  |  |  518|     14|} while((void)0, 0)
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (518:9): [Folded, False: 0]
  |  |  |  |  ------------------
  |  |  ------------------
  ------------------
  573|     14|        }
  574|     88|        else {
  575|     88|            ParseValue<parseFlags>(is, handler);
  576|     88|            RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_);
  ------------------
  |  |   61|     88|    RAPIDJSON_MULTILINEMACRO_BEGIN \
  |  |  ------------------
  |  |  |  |  516|     88|#define RAPIDJSON_MULTILINEMACRO_BEGIN do {
  |  |  ------------------
  |  |   62|     88|    if (RAPIDJSON_UNLIKELY(HasParseError())) { return value; } \
  |  |  ------------------
  |  |  |  |  505|     88|#define RAPIDJSON_UNLIKELY(x) __builtin_expect(!!(x), 0)
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (505:31): [True: 66, False: 22]
  |  |  |  |  ------------------
  |  |  ------------------
  |  |   63|     88|    RAPIDJSON_MULTILINEMACRO_END
  |  |  ------------------
  |  |  |  |  517|     88|#define RAPIDJSON_MULTILINEMACRO_END \
  |  |  |  |  518|     88|} while((void)0, 0)
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (518:9): [Folded, False: 22]
  |  |  |  |  ------------------
  |  |  ------------------
  ------------------
  577|       |
  578|     22|            if (!(parseFlags & kParseStopWhenDoneFlag)) {
  ------------------
  |  Branch (578:17): [True: 22, Folded]
  ------------------
  579|     22|                SkipWhitespaceAndComments<parseFlags>(is);
  580|     22|                RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_);
  ------------------
  |  |   61|     22|    RAPIDJSON_MULTILINEMACRO_BEGIN \
  |  |  ------------------
  |  |  |  |  516|     22|#define RAPIDJSON_MULTILINEMACRO_BEGIN do {
  |  |  ------------------
  |  |   62|     22|    if (RAPIDJSON_UNLIKELY(HasParseError())) { return value; } \
  |  |  ------------------
  |  |  |  |  505|     22|#define RAPIDJSON_UNLIKELY(x) __builtin_expect(!!(x), 0)
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (505:31): [True: 0, False: 22]
  |  |  |  |  ------------------
  |  |  ------------------
  |  |   63|     22|    RAPIDJSON_MULTILINEMACRO_END
  |  |  ------------------
  |  |  |  |  517|     22|#define RAPIDJSON_MULTILINEMACRO_END \
  |  |  |  |  518|     22|} while((void)0, 0)
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (518:9): [Folded, False: 22]
  |  |  |  |  ------------------
  |  |  ------------------
  ------------------
  581|       |
  582|     22|                if (RAPIDJSON_UNLIKELY(is.Peek() != '\0')) {
  ------------------
  |  |  505|     22|#define RAPIDJSON_UNLIKELY(x) __builtin_expect(!!(x), 0)
  |  |  ------------------
  |  |  |  Branch (505:31): [True: 0, False: 22]
  |  |  ------------------
  ------------------
  583|      0|                    RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorDocumentRootNotSingular, is.Tell());
  ------------------
  |  |  101|      0|    RAPIDJSON_MULTILINEMACRO_BEGIN \
  |  |  ------------------
  |  |  |  |  516|      0|#define RAPIDJSON_MULTILINEMACRO_BEGIN do {
  |  |  ------------------
  |  |  102|      0|    RAPIDJSON_ASSERT(!HasParseError()); /* Error can only be assigned once */ \
  |  |  ------------------
  |  |  |  |  437|      0|#define RAPIDJSON_ASSERT(x) assert(x)
  |  |  ------------------
  |  |  103|      0|    SetParseError(parseErrorCode, offset); \
  |  |  104|      0|    RAPIDJSON_MULTILINEMACRO_END
  |  |  ------------------
  |  |  |  |  517|      0|#define RAPIDJSON_MULTILINEMACRO_END \
  |  |  |  |  518|      0|} while((void)0, 0)
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (518:9): [Folded, False: 0]
  |  |  |  |  ------------------
  |  |  ------------------
  ------------------
  |  Branch (583:21): [True: 0, False: 0]
  ------------------
  584|      0|                    RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_);
  ------------------
  |  |   61|      0|    RAPIDJSON_MULTILINEMACRO_BEGIN \
  |  |  ------------------
  |  |  |  |  516|      0|#define RAPIDJSON_MULTILINEMACRO_BEGIN do {
  |  |  ------------------
  |  |   62|      0|    if (RAPIDJSON_UNLIKELY(HasParseError())) { return value; } \
  |  |  ------------------
  |  |  |  |  505|      0|#define RAPIDJSON_UNLIKELY(x) __builtin_expect(!!(x), 0)
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (505:31): [True: 0, False: 0]
  |  |  |  |  ------------------
  |  |  ------------------
  |  |   63|      0|    RAPIDJSON_MULTILINEMACRO_END
  |  |  ------------------
  |  |  |  |  517|      0|#define RAPIDJSON_MULTILINEMACRO_END \
  |  |  |  |  518|      0|} while((void)0, 0)
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (518:9): [Folded, False: 0]
  |  |  |  |  ------------------
  |  |  ------------------
  ------------------
  585|      0|                }
  586|     22|            }
  587|     22|        }
  588|       |
  589|     22|        return parseResult_;
  590|    102|    }
_ZN9rapidjson13GenericReaderINS_4UTF8IcEES2_NS_12CrtAllocatorEE11ParseStringILj1ENS_25GenericInsituStringStreamIS2_EENS_15GenericDocumentIS2_NS_19MemoryPoolAllocatorIS3_EES3_EEEEvRT0_RT1_b:
  959|  13.5k|    void ParseString(InputStream& is, Handler& handler, bool isKey = false) {
  960|  13.5k|        internal::StreamLocalCopy<InputStream> copy(is);
  961|  13.5k|        InputStream& s(copy.s);
  962|       |
  963|  13.5k|        RAPIDJSON_ASSERT(s.Peek() == '\"');
  ------------------
  |  |  437|  13.5k|#define RAPIDJSON_ASSERT(x) assert(x)
  ------------------
  |  Branch (963:9): [True: 13.5k, False: 0]
  ------------------
  964|  13.5k|        s.Take();  // Skip '\"'
  965|       |
  966|  13.5k|        bool success = false;
  967|  13.5k|        if (parseFlags & kParseInsituFlag) {
  ------------------
  |  Branch (967:13): [True: 13.5k, Folded]
  ------------------
  968|  13.5k|            typename InputStream::Ch *head = s.PutBegin();
  969|  13.5k|            ParseStringToStream<parseFlags, SourceEncoding, SourceEncoding>(s, s);
  970|  13.5k|            RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
  ------------------
  |  |   66|  13.5k|    RAPIDJSON_PARSE_ERROR_EARLY_RETURN(RAPIDJSON_NOTHING)
  |  |  ------------------
  |  |  |  |   61|  13.5k|    RAPIDJSON_MULTILINEMACRO_BEGIN \
  |  |  |  |  ------------------
  |  |  |  |  |  |  516|  13.5k|#define RAPIDJSON_MULTILINEMACRO_BEGIN do {
  |  |  |  |  ------------------
  |  |  |  |   62|  13.5k|    if (RAPIDJSON_UNLIKELY(HasParseError())) { return value; } \
  |  |  |  |  ------------------
  |  |  |  |  |  |  505|  13.5k|#define RAPIDJSON_UNLIKELY(x) __builtin_expect(!!(x), 0)
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  Branch (505:31): [True: 0, False: 13.5k]
  |  |  |  |  |  |  ------------------
  |  |  |  |  ------------------
  |  |  |  |   63|  13.5k|    RAPIDJSON_MULTILINEMACRO_END
  |  |  |  |  ------------------
  |  |  |  |  |  |  517|  13.5k|#define RAPIDJSON_MULTILINEMACRO_END \
  |  |  |  |  |  |  518|  13.5k|} while((void)0, 0)
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  Branch (518:9): [Folded, False: 13.5k]
  |  |  |  |  |  |  ------------------
  |  |  |  |  ------------------
  |  |  ------------------
  ------------------
  971|  13.5k|            size_t length = s.PutEnd(head) - 1;
  972|  13.5k|            RAPIDJSON_ASSERT(length <= 0xFFFFFFFF);
  ------------------
  |  |  437|  13.5k|#define RAPIDJSON_ASSERT(x) assert(x)
  ------------------
  |  Branch (972:13): [True: 13.5k, False: 0]
  ------------------
  973|  13.5k|            const typename TargetEncoding::Ch* const str = reinterpret_cast<typename TargetEncoding::Ch*>(head);
  974|  13.5k|            success = (isKey ? handler.Key(str, SizeType(length), false) : handler.String(str, SizeType(length), false));
  ------------------
  |  Branch (974:24): [True: 11.5k, False: 2.02k]
  ------------------
  975|  13.5k|        }
  976|      0|        else {
  977|      0|            StackStream<typename TargetEncoding::Ch> stackStream(stack_);
  978|      0|            ParseStringToStream<parseFlags, SourceEncoding, TargetEncoding>(s, stackStream);
  979|      0|            RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
  ------------------
  |  |   66|      0|    RAPIDJSON_PARSE_ERROR_EARLY_RETURN(RAPIDJSON_NOTHING)
  |  |  ------------------
  |  |  |  |   61|      0|    RAPIDJSON_MULTILINEMACRO_BEGIN \
  |  |  |  |  ------------------
  |  |  |  |  |  |  516|      0|#define RAPIDJSON_MULTILINEMACRO_BEGIN do {
  |  |  |  |  ------------------
  |  |  |  |   62|      0|    if (RAPIDJSON_UNLIKELY(HasParseError())) { return value; } \
  |  |  |  |  ------------------
  |  |  |  |  |  |  505|      0|#define RAPIDJSON_UNLIKELY(x) __builtin_expect(!!(x), 0)
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  Branch (505:31): [True: 0, False: 0]
  |  |  |  |  |  |  ------------------
  |  |  |  |  ------------------
  |  |  |  |   63|      0|    RAPIDJSON_MULTILINEMACRO_END
  |  |  |  |  ------------------
  |  |  |  |  |  |  517|      0|#define RAPIDJSON_MULTILINEMACRO_END \
  |  |  |  |  |  |  518|      0|} while((void)0, 0)
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  Branch (518:9): [Folded, False: 0]
  |  |  |  |  |  |  ------------------
  |  |  |  |  ------------------
  |  |  ------------------
  ------------------
  980|      0|            SizeType length = static_cast<SizeType>(stackStream.Length()) - 1;
  981|      0|            const typename TargetEncoding::Ch* const str = stackStream.Pop();
  982|      0|            success = (isKey ? handler.Key(str, length, true) : handler.String(str, length, true));
  ------------------
  |  Branch (982:24): [True: 0, False: 0]
  ------------------
  983|      0|        }
  984|  13.5k|        if (RAPIDJSON_UNLIKELY(!success))
  ------------------
  |  |  505|  13.5k|#define RAPIDJSON_UNLIKELY(x) __builtin_expect(!!(x), 0)
  |  |  ------------------
  |  |  |  Branch (505:31): [True: 0, False: 13.5k]
  |  |  ------------------
  ------------------
  985|       |            RAPIDJSON_PARSE_ERROR(kParseErrorTermination, s.Tell());
  ------------------
  |  |  120|      0|    RAPIDJSON_MULTILINEMACRO_BEGIN \
  |  |  ------------------
  |  |  |  |  516|      0|#define RAPIDJSON_MULTILINEMACRO_BEGIN do {
  |  |  ------------------
  |  |  121|      0|    RAPIDJSON_PARSE_ERROR_NORETURN(parseErrorCode, offset); \
  |  |  ------------------
  |  |  |  |  101|      0|    RAPIDJSON_MULTILINEMACRO_BEGIN \
  |  |  |  |  ------------------
  |  |  |  |  |  |  516|      0|#define RAPIDJSON_MULTILINEMACRO_BEGIN do {
  |  |  |  |  ------------------
  |  |  |  |  102|      0|    RAPIDJSON_ASSERT(!HasParseError()); /* Error can only be assigned once */ \
  |  |  |  |  ------------------
  |  |  |  |  |  |  437|      0|#define RAPIDJSON_ASSERT(x) assert(x)
  |  |  |  |  ------------------
  |  |  |  |  103|      0|    SetParseError(parseErrorCode, offset); \
  |  |  |  |  104|      0|    RAPIDJSON_MULTILINEMACRO_END
  |  |  |  |  ------------------
  |  |  |  |  |  |  517|      0|#define RAPIDJSON_MULTILINEMACRO_END \
  |  |  |  |  |  |  518|      0|} while((void)0, 0)
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  Branch (518:9): [Folded, False: 0]
  |  |  |  |  |  |  ------------------
  |  |  |  |  ------------------
  |  |  ------------------
  |  |  122|      0|    RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; \
  |  |  ------------------
  |  |  |  |   66|      0|    RAPIDJSON_PARSE_ERROR_EARLY_RETURN(RAPIDJSON_NOTHING)
  |  |  |  |  ------------------
  |  |  |  |  |  |   61|      0|    RAPIDJSON_MULTILINEMACRO_BEGIN \
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  516|      0|#define RAPIDJSON_MULTILINEMACRO_BEGIN do {
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |   62|      0|    if (RAPIDJSON_UNLIKELY(HasParseError())) { return value; } \
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  505|      0|#define RAPIDJSON_UNLIKELY(x) __builtin_expect(!!(x), 0)
  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  |  Branch (505:31): [True: 0, False: 0]
  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |   63|      0|    RAPIDJSON_MULTILINEMACRO_END
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  517|      0|#define RAPIDJSON_MULTILINEMACRO_END \
  |  |  |  |  |  |  |  |  518|      0|} while((void)0, 0)
  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  |  Branch (518:9): [Folded, False: 0]
  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  ------------------
  |  |  |  |  ------------------
  |  |  ------------------
  |  |  123|      0|    RAPIDJSON_MULTILINEMACRO_END
  |  |  ------------------
  |  |  |  |  517|      0|#define RAPIDJSON_MULTILINEMACRO_END \
  |  |  |  |  518|      0|} while((void)0, 0)
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (518:9): [Folded, False: 0]
  |  |  |  |  ------------------
  |  |  ------------------
  ------------------
  |  Branch (985:13): [True: 0, False: 0]
  ------------------
  986|  13.5k|    }
_ZN9rapidjson13GenericReaderINS_4UTF8IcEES2_NS_12CrtAllocatorEE19ParseStringToStreamILj1ES2_S2_NS_25GenericInsituStringStreamIS2_EES7_EEvRT2_RT3_:
  991|  13.5k|    RAPIDJSON_FORCEINLINE void ParseStringToStream(InputStream& is, OutputStream& os) {
  992|       |//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN
  993|  13.5k|#define Z16 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
  994|  13.5k|        static const char escape[256] = {
  995|  13.5k|            Z16, Z16, 0, 0,'\"', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '/',
  ------------------
  |  |  993|  13.5k|#define Z16 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
  ------------------
                          Z16, Z16, 0, 0,'\"', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '/',
  ------------------
  |  |  993|  13.5k|#define Z16 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
  ------------------
  996|  13.5k|            Z16, Z16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,'\\', 0, 0, 0,
  ------------------
  |  |  993|  13.5k|#define Z16 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
  ------------------
                          Z16, Z16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,'\\', 0, 0, 0,
  ------------------
  |  |  993|  13.5k|#define Z16 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
  ------------------
  997|  13.5k|            0, 0,'\b', 0, 0, 0,'\f', 0, 0, 0, 0, 0, 0, 0,'\n', 0,
  998|  13.5k|            0, 0,'\r', 0,'\t', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  999|  13.5k|            Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16
  ------------------
  |  |  993|  13.5k|#define Z16 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
  ------------------
                          Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16
  ------------------
  |  |  993|  13.5k|#define Z16 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
  ------------------
                          Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16
  ------------------
  |  |  993|  13.5k|#define Z16 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
  ------------------
                          Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16
  ------------------
  |  |  993|  13.5k|#define Z16 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
  ------------------
                          Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16
  ------------------
  |  |  993|  13.5k|#define Z16 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
  ------------------
                          Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16
  ------------------
  |  |  993|  13.5k|#define Z16 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
  ------------------
                          Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16
  ------------------
  |  |  993|  13.5k|#define Z16 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
  ------------------
                          Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16
  ------------------
  |  |  993|  13.5k|#define Z16 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
  ------------------
 1000|  13.5k|        };
 1001|  13.5k|#undef Z16
 1002|       |//!@endcond
 1003|       |
 1004|   255k|        for (;;) {
 1005|       |            // Scan and copy string before "\\\"" or < 0x20. This is an optional optimzation.
 1006|   255k|            if (!(parseFlags & kParseValidateEncodingFlag))
  ------------------
  |  Branch (1006:17): [True: 255k, Folded]
  ------------------
 1007|   255k|                ScanCopyUnescapedString(is, os);
 1008|       |
 1009|   255k|            Ch c = is.Peek();
 1010|   255k|            if (RAPIDJSON_UNLIKELY(c == '\\')) {    // Escape
  ------------------
  |  |  505|   255k|#define RAPIDJSON_UNLIKELY(x) __builtin_expect(!!(x), 0)
  |  |  ------------------
  |  |  |  Branch (505:31): [True: 0, False: 255k]
  |  |  ------------------
  ------------------
 1011|      0|                size_t escapeOffset = is.Tell();    // For invalid escaping, report the initial '\\' as error offset
 1012|      0|                is.Take();
 1013|      0|                Ch e = is.Peek();
 1014|      0|                if ((sizeof(Ch) == 1 || unsigned(e) < 256) && RAPIDJSON_LIKELY(escape[static_cast<unsigned char>(e)])) {
  ------------------
  |  |  492|      0|#define RAPIDJSON_LIKELY(x) __builtin_expect(!!(x), 1)
  |  |  ------------------
  |  |  |  Branch (492:29): [True: 0, False: 0]
  |  |  ------------------
  ------------------
  |  Branch (1014:22): [True: 0, Folded]
  |  Branch (1014:41): [True: 0, False: 0]
  ------------------
 1015|      0|                    is.Take();
 1016|      0|                    os.Put(static_cast<typename TEncoding::Ch>(escape[static_cast<unsigned char>(e)]));
 1017|      0|                }
 1018|      0|                else if ((parseFlags & kParseEscapedApostropheFlag) && RAPIDJSON_LIKELY(e == '\'')) { // Allow escaped apostrophe
  ------------------
  |  |  492|      0|#define RAPIDJSON_LIKELY(x) __builtin_expect(!!(x), 1)
  |  |  ------------------
  |  |  |  Branch (492:29): [True: 0, False: 0]
  |  |  ------------------
  ------------------
  |  Branch (1018:26): [Folded, False: 0]
  ------------------
 1019|      0|                    is.Take();
 1020|      0|                    os.Put('\'');
 1021|      0|                }
 1022|      0|                else if (RAPIDJSON_LIKELY(e == 'u')) {    // Unicode
  ------------------
  |  |  492|      0|#define RAPIDJSON_LIKELY(x) __builtin_expect(!!(x), 1)
  |  |  ------------------
  |  |  |  Branch (492:29): [True: 0, False: 0]
  |  |  ------------------
  ------------------
 1023|      0|                    is.Take();
 1024|      0|                    unsigned codepoint = ParseHex4(is, escapeOffset);
 1025|      0|                    RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
  ------------------
  |  |   66|      0|    RAPIDJSON_PARSE_ERROR_EARLY_RETURN(RAPIDJSON_NOTHING)
  |  |  ------------------
  |  |  |  |   61|      0|    RAPIDJSON_MULTILINEMACRO_BEGIN \
  |  |  |  |  ------------------
  |  |  |  |  |  |  516|      0|#define RAPIDJSON_MULTILINEMACRO_BEGIN do {
  |  |  |  |  ------------------
  |  |  |  |   62|      0|    if (RAPIDJSON_UNLIKELY(HasParseError())) { return value; } \
  |  |  |  |  ------------------
  |  |  |  |  |  |  505|      0|#define RAPIDJSON_UNLIKELY(x) __builtin_expect(!!(x), 0)
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  Branch (505:31): [True: 0, False: 0]
  |  |  |  |  |  |  ------------------
  |  |  |  |  ------------------
  |  |  |  |   63|      0|    RAPIDJSON_MULTILINEMACRO_END
  |  |  |  |  ------------------
  |  |  |  |  |  |  517|      0|#define RAPIDJSON_MULTILINEMACRO_END \
  |  |  |  |  |  |  518|      0|} while((void)0, 0)
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  Branch (518:9): [Folded, False: 0]
  |  |  |  |  |  |  ------------------
  |  |  |  |  ------------------
  |  |  ------------------
  ------------------
 1026|      0|                    if (RAPIDJSON_UNLIKELY(codepoint >= 0xD800 && codepoint <= 0xDFFF)) {
  ------------------
  |  |  505|      0|#define RAPIDJSON_UNLIKELY(x) __builtin_expect(!!(x), 0)
  |  |  ------------------
  |  |  |  Branch (505:31): [True: 0, False: 0]
  |  |  |  Branch (505:51): [True: 0, False: 0]
  |  |  |  Branch (505:51): [True: 0, False: 0]
  |  |  ------------------
  ------------------
 1027|       |                        // high surrogate, check if followed by valid low surrogate
 1028|      0|                        if (RAPIDJSON_LIKELY(codepoint <= 0xDBFF)) {
  ------------------
  |  |  492|      0|#define RAPIDJSON_LIKELY(x) __builtin_expect(!!(x), 1)
  |  |  ------------------
  |  |  |  Branch (492:29): [True: 0, False: 0]
  |  |  ------------------
  ------------------
 1029|       |                            // Handle UTF-16 surrogate pair
 1030|      0|                            if (RAPIDJSON_UNLIKELY(!Consume(is, '\\') || !Consume(is, 'u')))
  ------------------
  |  |  505|      0|#define RAPIDJSON_UNLIKELY(x) __builtin_expect(!!(x), 0)
  |  |  ------------------
  |  |  |  Branch (505:31): [True: 0, False: 0]
  |  |  |  Branch (505:51): [True: 0, False: 0]
  |  |  |  Branch (505:51): [True: 0, False: 0]
  |  |  ------------------
  ------------------
 1031|      0|                                RAPIDJSON_PARSE_ERROR(kParseErrorStringUnicodeSurrogateInvalid, escapeOffset);
  ------------------
  |  |  120|      0|    RAPIDJSON_MULTILINEMACRO_BEGIN \
  |  |  ------------------
  |  |  |  |  516|      0|#define RAPIDJSON_MULTILINEMACRO_BEGIN do {
  |  |  ------------------
  |  |  121|      0|    RAPIDJSON_PARSE_ERROR_NORETURN(parseErrorCode, offset); \
  |  |  ------------------
  |  |  |  |  101|      0|    RAPIDJSON_MULTILINEMACRO_BEGIN \
  |  |  |  |  ------------------
  |  |  |  |  |  |  516|      0|#define RAPIDJSON_MULTILINEMACRO_BEGIN do {
  |  |  |  |  ------------------
  |  |  |  |  102|      0|    RAPIDJSON_ASSERT(!HasParseError()); /* Error can only be assigned once */ \
  |  |  |  |  ------------------
  |  |  |  |  |  |  437|      0|#define RAPIDJSON_ASSERT(x) assert(x)
  |  |  |  |  ------------------
  |  |  |  |  103|      0|    SetParseError(parseErrorCode, offset); \
  |  |  |  |  104|      0|    RAPIDJSON_MULTILINEMACRO_END
  |  |  |  |  ------------------
  |  |  |  |  |  |  517|      0|#define RAPIDJSON_MULTILINEMACRO_END \
  |  |  |  |  |  |  518|      0|} while((void)0, 0)
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  Branch (518:9): [Folded, False: 0]
  |  |  |  |  |  |  ------------------
  |  |  |  |  ------------------
  |  |  ------------------
  |  |  122|      0|    RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; \
  |  |  ------------------
  |  |  |  |   66|      0|    RAPIDJSON_PARSE_ERROR_EARLY_RETURN(RAPIDJSON_NOTHING)
  |  |  |  |  ------------------
  |  |  |  |  |  |   61|      0|    RAPIDJSON_MULTILINEMACRO_BEGIN \
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  516|      0|#define RAPIDJSON_MULTILINEMACRO_BEGIN do {
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |   62|      0|    if (RAPIDJSON_UNLIKELY(HasParseError())) { return value; } \
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  505|      0|#define RAPIDJSON_UNLIKELY(x) __builtin_expect(!!(x), 0)
  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  |  Branch (505:31): [True: 0, False: 0]
  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |   63|      0|    RAPIDJSON_MULTILINEMACRO_END
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  517|      0|#define RAPIDJSON_MULTILINEMACRO_END \
  |  |  |  |  |  |  |  |  518|      0|} while((void)0, 0)
  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  |  Branch (518:9): [Folded, False: 0]
  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  ------------------
  |  |  |  |  ------------------
  |  |  ------------------
  |  |  123|      0|    RAPIDJSON_MULTILINEMACRO_END
  |  |  ------------------
  |  |  |  |  517|      0|#define RAPIDJSON_MULTILINEMACRO_END \
  |  |  |  |  518|      0|} while((void)0, 0)
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (518:9): [Folded, False: 0]
  |  |  |  |  ------------------
  |  |  ------------------
  ------------------
  |  Branch (1031:33): [True: 0, False: 0]
  ------------------
 1032|      0|                            unsigned codepoint2 = ParseHex4(is, escapeOffset);
 1033|      0|                            RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
  ------------------
  |  |   66|      0|    RAPIDJSON_PARSE_ERROR_EARLY_RETURN(RAPIDJSON_NOTHING)
  |  |  ------------------
  |  |  |  |   61|      0|    RAPIDJSON_MULTILINEMACRO_BEGIN \
  |  |  |  |  ------------------
  |  |  |  |  |  |  516|      0|#define RAPIDJSON_MULTILINEMACRO_BEGIN do {
  |  |  |  |  ------------------
  |  |  |  |   62|      0|    if (RAPIDJSON_UNLIKELY(HasParseError())) { return value; } \
  |  |  |  |  ------------------
  |  |  |  |  |  |  505|      0|#define RAPIDJSON_UNLIKELY(x) __builtin_expect(!!(x), 0)
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  Branch (505:31): [True: 0, False: 0]
  |  |  |  |  |  |  ------------------
  |  |  |  |  ------------------
  |  |  |  |   63|      0|    RAPIDJSON_MULTILINEMACRO_END
  |  |  |  |  ------------------
  |  |  |  |  |  |  517|      0|#define RAPIDJSON_MULTILINEMACRO_END \
  |  |  |  |  |  |  518|      0|} while((void)0, 0)
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  Branch (518:9): [Folded, False: 0]
  |  |  |  |  |  |  ------------------
  |  |  |  |  ------------------
  |  |  ------------------
  ------------------
 1034|      0|                            if (RAPIDJSON_UNLIKELY(codepoint2 < 0xDC00 || codepoint2 > 0xDFFF))
  ------------------
  |  |  505|      0|#define RAPIDJSON_UNLIKELY(x) __builtin_expect(!!(x), 0)
  |  |  ------------------
  |  |  |  Branch (505:31): [True: 0, False: 0]
  |  |  |  Branch (505:51): [True: 0, False: 0]
  |  |  |  Branch (505:51): [True: 0, False: 0]
  |  |  ------------------
  ------------------
 1035|      0|                                RAPIDJSON_PARSE_ERROR(kParseErrorStringUnicodeSurrogateInvalid, escapeOffset);
  ------------------
  |  |  120|      0|    RAPIDJSON_MULTILINEMACRO_BEGIN \
  |  |  ------------------
  |  |  |  |  516|      0|#define RAPIDJSON_MULTILINEMACRO_BEGIN do {
  |  |  ------------------
  |  |  121|      0|    RAPIDJSON_PARSE_ERROR_NORETURN(parseErrorCode, offset); \
  |  |  ------------------
  |  |  |  |  101|      0|    RAPIDJSON_MULTILINEMACRO_BEGIN \
  |  |  |  |  ------------------
  |  |  |  |  |  |  516|      0|#define RAPIDJSON_MULTILINEMACRO_BEGIN do {
  |  |  |  |  ------------------
  |  |  |  |  102|      0|    RAPIDJSON_ASSERT(!HasParseError()); /* Error can only be assigned once */ \
  |  |  |  |  ------------------
  |  |  |  |  |  |  437|      0|#define RAPIDJSON_ASSERT(x) assert(x)
  |  |  |  |  ------------------
  |  |  |  |  103|      0|    SetParseError(parseErrorCode, offset); \
  |  |  |  |  104|      0|    RAPIDJSON_MULTILINEMACRO_END
  |  |  |  |  ------------------
  |  |  |  |  |  |  517|      0|#define RAPIDJSON_MULTILINEMACRO_END \
  |  |  |  |  |  |  518|      0|} while((void)0, 0)
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  Branch (518:9): [Folded, False: 0]
  |  |  |  |  |  |  ------------------
  |  |  |  |  ------------------
  |  |  ------------------
  |  |  122|      0|    RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; \
  |  |  ------------------
  |  |  |  |   66|      0|    RAPIDJSON_PARSE_ERROR_EARLY_RETURN(RAPIDJSON_NOTHING)
  |  |  |  |  ------------------
  |  |  |  |  |  |   61|      0|    RAPIDJSON_MULTILINEMACRO_BEGIN \
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  516|      0|#define RAPIDJSON_MULTILINEMACRO_BEGIN do {
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |   62|      0|    if (RAPIDJSON_UNLIKELY(HasParseError())) { return value; } \
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  505|      0|#define RAPIDJSON_UNLIKELY(x) __builtin_expect(!!(x), 0)
  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  |  Branch (505:31): [True: 0, False: 0]
  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |   63|      0|    RAPIDJSON_MULTILINEMACRO_END
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  517|      0|#define RAPIDJSON_MULTILINEMACRO_END \
  |  |  |  |  |  |  |  |  518|      0|} while((void)0, 0)
  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  |  Branch (518:9): [Folded, False: 0]
  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  ------------------
  |  |  |  |  ------------------
  |  |  ------------------
  |  |  123|      0|    RAPIDJSON_MULTILINEMACRO_END
  |  |  ------------------
  |  |  |  |  517|      0|#define RAPIDJSON_MULTILINEMACRO_END \
  |  |  |  |  518|      0|} while((void)0, 0)
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (518:9): [Folded, False: 0]
  |  |  |  |  ------------------
  |  |  ------------------
  ------------------
  |  Branch (1035:33): [True: 0, False: 0]
  ------------------
 1036|      0|                            codepoint = (((codepoint - 0xD800) << 10) | (codepoint2 - 0xDC00)) + 0x10000;
 1037|      0|                        }
 1038|       |                        // single low surrogate
 1039|      0|                        else
 1040|      0|                        {
 1041|      0|                            RAPIDJSON_PARSE_ERROR(kParseErrorStringUnicodeSurrogateInvalid, escapeOffset);
  ------------------
  |  |  120|      0|    RAPIDJSON_MULTILINEMACRO_BEGIN \
  |  |  ------------------
  |  |  |  |  516|      0|#define RAPIDJSON_MULTILINEMACRO_BEGIN do {
  |  |  ------------------
  |  |  121|      0|    RAPIDJSON_PARSE_ERROR_NORETURN(parseErrorCode, offset); \
  |  |  ------------------
  |  |  |  |  101|      0|    RAPIDJSON_MULTILINEMACRO_BEGIN \
  |  |  |  |  ------------------
  |  |  |  |  |  |  516|      0|#define RAPIDJSON_MULTILINEMACRO_BEGIN do {
  |  |  |  |  ------------------
  |  |  |  |  102|      0|    RAPIDJSON_ASSERT(!HasParseError()); /* Error can only be assigned once */ \
  |  |  |  |  ------------------
  |  |  |  |  |  |  437|      0|#define RAPIDJSON_ASSERT(x) assert(x)
  |  |  |  |  ------------------
  |  |  |  |  103|      0|    SetParseError(parseErrorCode, offset); \
  |  |  |  |  104|      0|    RAPIDJSON_MULTILINEMACRO_END
  |  |  |  |  ------------------
  |  |  |  |  |  |  517|      0|#define RAPIDJSON_MULTILINEMACRO_END \
  |  |  |  |  |  |  518|      0|} while((void)0, 0)
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  Branch (518:9): [Folded, False: 0]
  |  |  |  |  |  |  ------------------
  |  |  |  |  ------------------
  |  |  ------------------
  |  |  122|      0|    RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; \
  |  |  ------------------
  |  |  |  |   66|      0|    RAPIDJSON_PARSE_ERROR_EARLY_RETURN(RAPIDJSON_NOTHING)
  |  |  |  |  ------------------
  |  |  |  |  |  |   61|      0|    RAPIDJSON_MULTILINEMACRO_BEGIN \
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  516|      0|#define RAPIDJSON_MULTILINEMACRO_BEGIN do {
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |   62|      0|    if (RAPIDJSON_UNLIKELY(HasParseError())) { return value; } \
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  505|      0|#define RAPIDJSON_UNLIKELY(x) __builtin_expect(!!(x), 0)
  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  |  Branch (505:31): [True: 0, False: 0]
  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |   63|      0|    RAPIDJSON_MULTILINEMACRO_END
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  517|      0|#define RAPIDJSON_MULTILINEMACRO_END \
  |  |  |  |  |  |  |  |  518|      0|} while((void)0, 0)
  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  |  Branch (518:9): [Folded, False: 0]
  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  ------------------
  |  |  |  |  ------------------
  |  |  ------------------
  |  |  123|      0|    RAPIDJSON_MULTILINEMACRO_END
  |  |  ------------------
  |  |  |  |  517|      0|#define RAPIDJSON_MULTILINEMACRO_END \
  |  |  |  |  518|      0|} while((void)0, 0)
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (518:9): [Folded, False: 0]
  |  |  |  |  ------------------
  |  |  ------------------
  ------------------
  |  Branch (1041:29): [True: 0, False: 0]
  ------------------
 1042|      0|                        }
 1043|      0|                    }
 1044|      0|                    TEncoding::Encode(os, codepoint);
 1045|      0|                }
 1046|      0|                else
 1047|      0|                    RAPIDJSON_PARSE_ERROR(kParseErrorStringEscapeInvalid, escapeOffset);
  ------------------
  |  |  120|      0|    RAPIDJSON_MULTILINEMACRO_BEGIN \
  |  |  ------------------
  |  |  |  |  516|      0|#define RAPIDJSON_MULTILINEMACRO_BEGIN do {
  |  |  ------------------
  |  |  121|      0|    RAPIDJSON_PARSE_ERROR_NORETURN(parseErrorCode, offset); \
  |  |  ------------------
  |  |  |  |  101|      0|    RAPIDJSON_MULTILINEMACRO_BEGIN \
  |  |  |  |  ------------------
  |  |  |  |  |  |  516|      0|#define RAPIDJSON_MULTILINEMACRO_BEGIN do {
  |  |  |  |  ------------------
  |  |  |  |  102|      0|    RAPIDJSON_ASSERT(!HasParseError()); /* Error can only be assigned once */ \
  |  |  |  |  ------------------
  |  |  |  |  |  |  437|      0|#define RAPIDJSON_ASSERT(x) assert(x)
  |  |  |  |  ------------------
  |  |  |  |  103|      0|    SetParseError(parseErrorCode, offset); \
  |  |  |  |  104|      0|    RAPIDJSON_MULTILINEMACRO_END
  |  |  |  |  ------------------
  |  |  |  |  |  |  517|      0|#define RAPIDJSON_MULTILINEMACRO_END \
  |  |  |  |  |  |  518|      0|} while((void)0, 0)
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  Branch (518:9): [Folded, False: 0]
  |  |  |  |  |  |  ------------------
  |  |  |  |  ------------------
  |  |  ------------------
  |  |  122|      0|    RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; \
  |  |  ------------------
  |  |  |  |   66|      0|    RAPIDJSON_PARSE_ERROR_EARLY_RETURN(RAPIDJSON_NOTHING)
  |  |  |  |  ------------------
  |  |  |  |  |  |   61|      0|    RAPIDJSON_MULTILINEMACRO_BEGIN \
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  516|      0|#define RAPIDJSON_MULTILINEMACRO_BEGIN do {
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |   62|      0|    if (RAPIDJSON_UNLIKELY(HasParseError())) { return value; } \
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  505|      0|#define RAPIDJSON_UNLIKELY(x) __builtin_expect(!!(x), 0)
  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  |  Branch (505:31): [True: 0, False: 0]
  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |   63|      0|    RAPIDJSON_MULTILINEMACRO_END
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  517|      0|#define RAPIDJSON_MULTILINEMACRO_END \
  |  |  |  |  |  |  |  |  518|      0|} while((void)0, 0)
  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  |  Branch (518:9): [Folded, False: 0]
  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  ------------------
  |  |  |  |  ------------------
  |  |  ------------------
  |  |  123|      0|    RAPIDJSON_MULTILINEMACRO_END
  |  |  ------------------
  |  |  |  |  517|      0|#define RAPIDJSON_MULTILINEMACRO_END \
  |  |  |  |  518|      0|} while((void)0, 0)
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (518:9): [Folded, False: 0]
  |  |  |  |  ------------------
  |  |  ------------------
  ------------------
  |  Branch (1047:21): [True: 0, False: 0]
  ------------------
 1048|      0|            }
 1049|   255k|            else if (RAPIDJSON_UNLIKELY(c == '"')) {    // Closing double quote
  ------------------
  |  |  505|   255k|#define RAPIDJSON_UNLIKELY(x) __builtin_expect(!!(x), 0)
  |  |  ------------------
  |  |  |  Branch (505:31): [True: 13.5k, False: 242k]
  |  |  ------------------
  ------------------
 1050|  13.5k|                is.Take();
 1051|  13.5k|                os.Put('\0');   // null-terminate the string
 1052|  13.5k|                return;
 1053|  13.5k|            }
 1054|   242k|            else if (RAPIDJSON_UNLIKELY(static_cast<unsigned>(c) < 0x20)) { // RFC 4627: unescaped = %x20-21 / %x23-5B / %x5D-10FFFF
  ------------------
  |  |  505|   242k|#define RAPIDJSON_UNLIKELY(x) __builtin_expect(!!(x), 0)
  |  |  ------------------
  |  |  |  Branch (505:31): [True: 0, False: 242k]
  |  |  ------------------
  ------------------
 1055|      0|                if (c == '\0')
  ------------------
  |  Branch (1055:21): [True: 0, False: 0]
  ------------------
 1056|      0|                    RAPIDJSON_PARSE_ERROR(kParseErrorStringMissQuotationMark, is.Tell());
  ------------------
  |  |  120|      0|    RAPIDJSON_MULTILINEMACRO_BEGIN \
  |  |  ------------------
  |  |  |  |  516|      0|#define RAPIDJSON_MULTILINEMACRO_BEGIN do {
  |  |  ------------------
  |  |  121|      0|    RAPIDJSON_PARSE_ERROR_NORETURN(parseErrorCode, offset); \
  |  |  ------------------
  |  |  |  |  101|      0|    RAPIDJSON_MULTILINEMACRO_BEGIN \
  |  |  |  |  ------------------
  |  |  |  |  |  |  516|      0|#define RAPIDJSON_MULTILINEMACRO_BEGIN do {
  |  |  |  |  ------------------
  |  |  |  |  102|      0|    RAPIDJSON_ASSERT(!HasParseError()); /* Error can only be assigned once */ \
  |  |  |  |  ------------------
  |  |  |  |  |  |  437|      0|#define RAPIDJSON_ASSERT(x) assert(x)
  |  |  |  |  ------------------
  |  |  |  |  103|      0|    SetParseError(parseErrorCode, offset); \
  |  |  |  |  104|      0|    RAPIDJSON_MULTILINEMACRO_END
  |  |  |  |  ------------------
  |  |  |  |  |  |  517|      0|#define RAPIDJSON_MULTILINEMACRO_END \
  |  |  |  |  |  |  518|      0|} while((void)0, 0)
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  Branch (518:9): [Folded, False: 0]
  |  |  |  |  |  |  ------------------
  |  |  |  |  ------------------
  |  |  ------------------
  |  |  122|      0|    RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; \
  |  |  ------------------
  |  |  |  |   66|      0|    RAPIDJSON_PARSE_ERROR_EARLY_RETURN(RAPIDJSON_NOTHING)
  |  |  |  |  ------------------
  |  |  |  |  |  |   61|      0|    RAPIDJSON_MULTILINEMACRO_BEGIN \
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  516|      0|#define RAPIDJSON_MULTILINEMACRO_BEGIN do {
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |   62|      0|    if (RAPIDJSON_UNLIKELY(HasParseError())) { return value; } \
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  505|      0|#define RAPIDJSON_UNLIKELY(x) __builtin_expect(!!(x), 0)
  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  |  Branch (505:31): [True: 0, False: 0]
  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |   63|      0|    RAPIDJSON_MULTILINEMACRO_END
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  517|      0|#define RAPIDJSON_MULTILINEMACRO_END \
  |  |  |  |  |  |  |  |  518|      0|} while((void)0, 0)
  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  |  Branch (518:9): [Folded, False: 0]
  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  ------------------
  |  |  |  |  ------------------
  |  |  ------------------
  |  |  123|      0|    RAPIDJSON_MULTILINEMACRO_END
  |  |  ------------------
  |  |  |  |  517|      0|#define RAPIDJSON_MULTILINEMACRO_END \
  |  |  |  |  518|      0|} while((void)0, 0)
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (518:9): [Folded, False: 0]
  |  |  |  |  ------------------
  |  |  ------------------
  ------------------
  |  Branch (1056:21): [True: 0, False: 0]
  ------------------
 1057|      0|                else
 1058|      0|                    RAPIDJSON_PARSE_ERROR(kParseErrorStringInvalidEncoding, is.Tell());
  ------------------
  |  |  120|      0|    RAPIDJSON_MULTILINEMACRO_BEGIN \
  |  |  ------------------
  |  |  |  |  516|      0|#define RAPIDJSON_MULTILINEMACRO_BEGIN do {
  |  |  ------------------
  |  |  121|      0|    RAPIDJSON_PARSE_ERROR_NORETURN(parseErrorCode, offset); \
  |  |  ------------------
  |  |  |  |  101|      0|    RAPIDJSON_MULTILINEMACRO_BEGIN \
  |  |  |  |  ------------------
  |  |  |  |  |  |  516|      0|#define RAPIDJSON_MULTILINEMACRO_BEGIN do {
  |  |  |  |  ------------------
  |  |  |  |  102|      0|    RAPIDJSON_ASSERT(!HasParseError()); /* Error can only be assigned once */ \
  |  |  |  |  ------------------
  |  |  |  |  |  |  437|      0|#define RAPIDJSON_ASSERT(x) assert(x)
  |  |  |  |  ------------------
  |  |  |  |  103|      0|    SetParseError(parseErrorCode, offset); \
  |  |  |  |  104|      0|    RAPIDJSON_MULTILINEMACRO_END
  |  |  |  |  ------------------
  |  |  |  |  |  |  517|      0|#define RAPIDJSON_MULTILINEMACRO_END \
  |  |  |  |  |  |  518|      0|} while((void)0, 0)
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  Branch (518:9): [Folded, False: 0]
  |  |  |  |  |  |  ------------------
  |  |  |  |  ------------------
  |  |  ------------------
  |  |  122|      0|    RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; \
  |  |  ------------------
  |  |  |  |   66|      0|    RAPIDJSON_PARSE_ERROR_EARLY_RETURN(RAPIDJSON_NOTHING)
  |  |  |  |  ------------------
  |  |  |  |  |  |   61|      0|    RAPIDJSON_MULTILINEMACRO_BEGIN \
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  516|      0|#define RAPIDJSON_MULTILINEMACRO_BEGIN do {
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |   62|      0|    if (RAPIDJSON_UNLIKELY(HasParseError())) { return value; } \
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  505|      0|#define RAPIDJSON_UNLIKELY(x) __builtin_expect(!!(x), 0)
  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  |  Branch (505:31): [True: 0, False: 0]
  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |   63|      0|    RAPIDJSON_MULTILINEMACRO_END
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  517|      0|#define RAPIDJSON_MULTILINEMACRO_END \
  |  |  |  |  |  |  |  |  518|      0|} while((void)0, 0)
  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  |  Branch (518:9): [Folded, False: 0]
  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  ------------------
  |  |  |  |  ------------------
  |  |  ------------------
  |  |  123|      0|    RAPIDJSON_MULTILINEMACRO_END
  |  |  ------------------
  |  |  |  |  517|      0|#define RAPIDJSON_MULTILINEMACRO_END \
  |  |  |  |  518|      0|} while((void)0, 0)
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (518:9): [Folded, False: 0]
  |  |  |  |  ------------------
  |  |  ------------------
  ------------------
  |  Branch (1058:21): [True: 0, False: 0]
  ------------------
 1059|      0|            }
 1060|   242k|            else {
 1061|   242k|                size_t offset = is.Tell();
 1062|   242k|                if (RAPIDJSON_UNLIKELY((parseFlags & kParseValidateEncodingFlag ?
  ------------------
  |  |  505|   484k|#define RAPIDJSON_UNLIKELY(x) __builtin_expect(!!(x), 0)
  |  |  ------------------
  |  |  |  Branch (505:31): [True: 0, False: 242k]
  |  |  |  Branch (505:51): [Folded, False: 242k]
  |  |  ------------------
  ------------------
 1063|   242k|                    !Transcoder<SEncoding, TEncoding>::Validate(is, os) :
 1064|   242k|                    !Transcoder<SEncoding, TEncoding>::Transcode(is, os))))
 1065|       |                    RAPIDJSON_PARSE_ERROR(kParseErrorStringInvalidEncoding, offset);
  ------------------
  |  |  120|      0|    RAPIDJSON_MULTILINEMACRO_BEGIN \
  |  |  ------------------
  |  |  |  |  516|      0|#define RAPIDJSON_MULTILINEMACRO_BEGIN do {
  |  |  ------------------
  |  |  121|      0|    RAPIDJSON_PARSE_ERROR_NORETURN(parseErrorCode, offset); \
  |  |  ------------------
  |  |  |  |  101|      0|    RAPIDJSON_MULTILINEMACRO_BEGIN \
  |  |  |  |  ------------------
  |  |  |  |  |  |  516|      0|#define RAPIDJSON_MULTILINEMACRO_BEGIN do {
  |  |  |  |  ------------------
  |  |  |  |  102|      0|    RAPIDJSON_ASSERT(!HasParseError()); /* Error can only be assigned once */ \
  |  |  |  |  ------------------
  |  |  |  |  |  |  437|      0|#define RAPIDJSON_ASSERT(x) assert(x)
  |  |  |  |  ------------------
  |  |  |  |  103|      0|    SetParseError(parseErrorCode, offset); \
  |  |  |  |  104|      0|    RAPIDJSON_MULTILINEMACRO_END
  |  |  |  |  ------------------
  |  |  |  |  |  |  517|      0|#define RAPIDJSON_MULTILINEMACRO_END \
  |  |  |  |  |  |  518|      0|} while((void)0, 0)
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  Branch (518:9): [Folded, False: 0]
  |  |  |  |  |  |  ------------------
  |  |  |  |  ------------------
  |  |  ------------------
  |  |  122|      0|    RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; \
  |  |  ------------------
  |  |  |  |   66|      0|    RAPIDJSON_PARSE_ERROR_EARLY_RETURN(RAPIDJSON_NOTHING)
  |  |  |  |  ------------------
  |  |  |  |  |  |   61|      0|    RAPIDJSON_MULTILINEMACRO_BEGIN \
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  516|      0|#define RAPIDJSON_MULTILINEMACRO_BEGIN do {
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |   62|      0|    if (RAPIDJSON_UNLIKELY(HasParseError())) { return value; } \
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  505|      0|#define RAPIDJSON_UNLIKELY(x) __builtin_expect(!!(x), 0)
  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  |  Branch (505:31): [True: 0, False: 0]
  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |   63|      0|    RAPIDJSON_MULTILINEMACRO_END
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  517|      0|#define RAPIDJSON_MULTILINEMACRO_END \
  |  |  |  |  |  |  |  |  518|      0|} while((void)0, 0)
  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  |  Branch (518:9): [Folded, False: 0]
  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  ------------------
  |  |  |  |  ------------------
  |  |  ------------------
  |  |  123|      0|    RAPIDJSON_MULTILINEMACRO_END
  |  |  ------------------
  |  |  |  |  517|      0|#define RAPIDJSON_MULTILINEMACRO_END \
  |  |  |  |  518|      0|} while((void)0, 0)
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (518:9): [Folded, False: 0]
  |  |  |  |  ------------------
  |  |  ------------------
  ------------------
  |  Branch (1065:21): [True: 0, False: 0]
  ------------------
 1066|   242k|            }
 1067|   255k|        }
 1068|  13.5k|    }
_ZN9rapidjson13GenericReaderINS_4UTF8IcEES2_NS_12CrtAllocatorEE23ScanCopyUnescapedStringINS_25GenericInsituStringStreamIS2_EES7_EEvRT_RT0_:
 1071|   255k|    static RAPIDJSON_FORCEINLINE void ScanCopyUnescapedString(InputStream&, OutputStream&) {
 1072|       |            // Do nothing for generic version
 1073|   255k|    }
_ZN9rapidjson13GenericReaderINS_4UTF8IcEES2_NS_12CrtAllocatorEE7ConsumeINS_25GenericInsituStringStreamIS2_EEEEbRT_NS8_2ChE:
  895|  1.10M|    RAPIDJSON_FORCEINLINE static bool Consume(InputStream& is, typename InputStream::Ch expect) {
  896|  1.10M|        if (RAPIDJSON_LIKELY(is.Peek() == expect)) {
  ------------------
  |  |  492|  1.10M|#define RAPIDJSON_LIKELY(x) __builtin_expect(!!(x), 1)
  |  |  ------------------
  |  |  |  Branch (492:29): [True: 837k, False: 269k]
  |  |  ------------------
  ------------------
  897|   837k|            is.Take();
  898|   837k|            return true;
  899|   837k|        }
  900|   269k|        else
  901|   269k|            return false;
  902|  1.10M|    }
_ZN9rapidjson13GenericReaderINS_4UTF8IcEES2_NS_12CrtAllocatorEE10ClearStackEv:
  698|    102|    void ClearStack() { stack_.Clear(); }
_ZN9rapidjson13GenericReaderINS_4UTF8IcEES2_NS_12CrtAllocatorEE25SkipWhitespaceAndCommentsILj1ENS_25GenericInsituStringStreamIS2_EEEEvRT0_:
  711|  1.95M|    void SkipWhitespaceAndComments(InputStream& is) {
  712|  1.95M|        SkipWhitespace(is);
  713|       |
  714|  1.95M|        if (parseFlags & kParseCommentsFlag) {
  ------------------
  |  Branch (714:13): [Folded, False: 1.95M]
  ------------------
  715|      0|            while (RAPIDJSON_UNLIKELY(Consume(is, '/'))) {
  ------------------
  |  |  505|      0|#define RAPIDJSON_UNLIKELY(x) __builtin_expect(!!(x), 0)
  |  |  ------------------
  |  |  |  Branch (505:31): [True: 0, False: 0]
  |  |  ------------------
  ------------------
  716|      0|                if (Consume(is, '*')) {
  ------------------
  |  Branch (716:21): [True: 0, False: 0]
  ------------------
  717|      0|                    while (true) {
  ------------------
  |  Branch (717:28): [True: 0, Folded]
  ------------------
  718|      0|                        if (RAPIDJSON_UNLIKELY(is.Peek() == '\0'))
  ------------------
  |  |  505|      0|#define RAPIDJSON_UNLIKELY(x) __builtin_expect(!!(x), 0)
  |  |  ------------------
  |  |  |  Branch (505:31): [True: 0, False: 0]
  |  |  ------------------
  ------------------
  719|      0|                            RAPIDJSON_PARSE_ERROR(kParseErrorUnspecificSyntaxError, is.Tell());
  ------------------
  |  |  120|      0|    RAPIDJSON_MULTILINEMACRO_BEGIN \
  |  |  ------------------
  |  |  |  |  516|      0|#define RAPIDJSON_MULTILINEMACRO_BEGIN do {
  |  |  ------------------
  |  |  121|      0|    RAPIDJSON_PARSE_ERROR_NORETURN(parseErrorCode, offset); \
  |  |  ------------------
  |  |  |  |  101|      0|    RAPIDJSON_MULTILINEMACRO_BEGIN \
  |  |  |  |  ------------------
  |  |  |  |  |  |  516|      0|#define RAPIDJSON_MULTILINEMACRO_BEGIN do {
  |  |  |  |  ------------------
  |  |  |  |  102|      0|    RAPIDJSON_ASSERT(!HasParseError()); /* Error can only be assigned once */ \
  |  |  |  |  ------------------
  |  |  |  |  |  |  437|      0|#define RAPIDJSON_ASSERT(x) assert(x)
  |  |  |  |  ------------------
  |  |  |  |  103|      0|    SetParseError(parseErrorCode, offset); \
  |  |  |  |  104|      0|    RAPIDJSON_MULTILINEMACRO_END
  |  |  |  |  ------------------
  |  |  |  |  |  |  517|      0|#define RAPIDJSON_MULTILINEMACRO_END \
  |  |  |  |  |  |  518|      0|} while((void)0, 0)
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  Branch (518:9): [Folded, False: 0]
  |  |  |  |  |  |  ------------------
  |  |  |  |  ------------------
  |  |  ------------------
  |  |  122|      0|    RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; \
  |  |  ------------------
  |  |  |  |   66|      0|    RAPIDJSON_PARSE_ERROR_EARLY_RETURN(RAPIDJSON_NOTHING)
  |  |  |  |  ------------------
  |  |  |  |  |  |   61|      0|    RAPIDJSON_MULTILINEMACRO_BEGIN \
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  516|      0|#define RAPIDJSON_MULTILINEMACRO_BEGIN do {
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |   62|      0|    if (RAPIDJSON_UNLIKELY(HasParseError())) { return value; } \
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  505|      0|#define RAPIDJSON_UNLIKELY(x) __builtin_expect(!!(x), 0)
  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  |  Branch (505:31): [True: 0, False: 0]
  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |   63|      0|    RAPIDJSON_MULTILINEMACRO_END
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  517|      0|#define RAPIDJSON_MULTILINEMACRO_END \
  |  |  |  |  |  |  |  |  518|      0|} while((void)0, 0)
  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  |  Branch (518:9): [Folded, False: 0]
  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  ------------------
  |  |  |  |  ------------------
  |  |  ------------------
  |  |  123|      0|    RAPIDJSON_MULTILINEMACRO_END
  |  |  ------------------
  |  |  |  |  517|      0|#define RAPIDJSON_MULTILINEMACRO_END \
  |  |  |  |  518|      0|} while((void)0, 0)
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (518:9): [Folded, False: 0]
  |  |  |  |  ------------------
  |  |  ------------------
  ------------------
  |  Branch (719:29): [True: 0, False: 0]
  ------------------
  720|      0|                        else if (Consume(is, '*')) {
  ------------------
  |  Branch (720:34): [True: 0, False: 0]
  ------------------
  721|      0|                            if (Consume(is, '/'))
  ------------------
  |  Branch (721:33): [True: 0, False: 0]
  ------------------
  722|      0|                                break;
  723|      0|                        }
  724|      0|                        else
  725|      0|                            is.Take();
  726|      0|                    }
  727|      0|                }
  728|      0|                else if (RAPIDJSON_LIKELY(Consume(is, '/')))
  ------------------
  |  |  492|      0|#define RAPIDJSON_LIKELY(x) __builtin_expect(!!(x), 1)
  |  |  ------------------
  |  |  |  Branch (492:29): [True: 0, False: 0]
  |  |  ------------------
  ------------------
  729|      0|                    while (is.Peek() != '\0' && is.Take() != '\n') {}
  ------------------
  |  Branch (729:28): [True: 0, False: 0]
  |  Branch (729:49): [True: 0, False: 0]
  ------------------
  730|      0|                else
  731|      0|                    RAPIDJSON_PARSE_ERROR(kParseErrorUnspecificSyntaxError, is.Tell());
  ------------------
  |  |  120|      0|    RAPIDJSON_MULTILINEMACRO_BEGIN \
  |  |  ------------------
  |  |  |  |  516|      0|#define RAPIDJSON_MULTILINEMACRO_BEGIN do {
  |  |  ------------------
  |  |  121|      0|    RAPIDJSON_PARSE_ERROR_NORETURN(parseErrorCode, offset); \
  |  |  ------------------
  |  |  |  |  101|      0|    RAPIDJSON_MULTILINEMACRO_BEGIN \
  |  |  |  |  ------------------
  |  |  |  |  |  |  516|      0|#define RAPIDJSON_MULTILINEMACRO_BEGIN do {
  |  |  |  |  ------------------
  |  |  |  |  102|      0|    RAPIDJSON_ASSERT(!HasParseError()); /* Error can only be assigned once */ \
  |  |  |  |  ------------------
  |  |  |  |  |  |  437|      0|#define RAPIDJSON_ASSERT(x) assert(x)
  |  |  |  |  ------------------
  |  |  |  |  103|      0|    SetParseError(parseErrorCode, offset); \
  |  |  |  |  104|      0|    RAPIDJSON_MULTILINEMACRO_END
  |  |  |  |  ------------------
  |  |  |  |  |  |  517|      0|#define RAPIDJSON_MULTILINEMACRO_END \
  |  |  |  |  |  |  518|      0|} while((void)0, 0)
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  Branch (518:9): [Folded, False: 0]
  |  |  |  |  |  |  ------------------
  |  |  |  |  ------------------
  |  |  ------------------
  |  |  122|      0|    RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; \
  |  |  ------------------
  |  |  |  |   66|      0|    RAPIDJSON_PARSE_ERROR_EARLY_RETURN(RAPIDJSON_NOTHING)
  |  |  |  |  ------------------
  |  |  |  |  |  |   61|      0|    RAPIDJSON_MULTILINEMACRO_BEGIN \
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  516|      0|#define RAPIDJSON_MULTILINEMACRO_BEGIN do {
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |   62|      0|    if (RAPIDJSON_UNLIKELY(HasParseError())) { return value; } \
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  505|      0|#define RAPIDJSON_UNLIKELY(x) __builtin_expect(!!(x), 0)
  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  |  Branch (505:31): [True: 0, False: 0]
  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |   63|      0|    RAPIDJSON_MULTILINEMACRO_END
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  517|      0|#define RAPIDJSON_MULTILINEMACRO_END \
  |  |  |  |  |  |  |  |  518|      0|} while((void)0, 0)
  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  |  Branch (518:9): [Folded, False: 0]
  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  ------------------
  |  |  |  |  ------------------
  |  |  ------------------
  |  |  123|      0|    RAPIDJSON_MULTILINEMACRO_END
  |  |  ------------------
  |  |  |  |  517|      0|#define RAPIDJSON_MULTILINEMACRO_END \
  |  |  |  |  518|      0|} while((void)0, 0)
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (518:9): [Folded, False: 0]
  |  |  |  |  ------------------
  |  |  ------------------
  ------------------
  |  Branch (731:21): [True: 0, False: 0]
  ------------------
  732|       |
  733|      0|                SkipWhitespace(is);
  734|      0|            }
  735|      0|        }
  736|  1.95M|    }
_ZN9rapidjson14SkipWhitespaceINS_25GenericInsituStringStreamINS_4UTF8IcEEEEEEvRT_:
  266|  1.95M|void SkipWhitespace(InputStream& is) {
  267|  1.95M|    internal::StreamLocalCopy<InputStream> copy(is);
  268|  1.95M|    InputStream& s(copy.s);
  269|       |
  270|  1.95M|    typename InputStream::Ch c;
  271|  2.31M|    while ((c = s.Peek()) == ' ' || c == '\n' || c == '\r' || c == '\t')
  ------------------
  |  Branch (271:12): [True: 303k, False: 2.01M]
  |  Branch (271:37): [True: 42.4k, False: 1.97M]
  |  Branch (271:50): [True: 15.8k, False: 1.95M]
  |  Branch (271:63): [True: 100, False: 1.95M]
  ------------------
  272|   361k|        s.Take();
  273|  1.95M|}
_ZNK9rapidjson13GenericReaderINS_4UTF8IcEES2_NS_12CrtAllocatorEE13HasParseErrorEv:
  682|  3.08M|    bool HasParseError() const { return parseResult_.IsError(); }
_ZN9rapidjson13GenericReaderINS_4UTF8IcEES2_NS_12CrtAllocatorEE13SetParseErrorENS_14ParseErrorCodeEm:
  691|     80|    void SetParseError(ParseErrorCode code, size_t offset) { parseResult_.Set(code, offset); }
_ZN9rapidjson13GenericReaderINS_4UTF8IcEES2_NS_12CrtAllocatorEE10ParseValueILj1ENS_25GenericInsituStringStreamIS2_EENS_15GenericDocumentIS2_NS_19MemoryPoolAllocatorIS3_EES3_EEEEvRT0_RT1_:
 1752|  1.09M|    void ParseValue(InputStream& is, Handler& handler) {
 1753|  1.09M|        switch (is.Peek()) {
 1754|      0|            case 'n': ParseNull  <parseFlags>(is, handler); break;
  ------------------
  |  Branch (1754:13): [True: 0, False: 1.09M]
  ------------------
 1755|     41|            case 't': ParseTrue  <parseFlags>(is, handler); break;
  ------------------
  |  Branch (1755:13): [True: 41, False: 1.09M]
  ------------------
 1756|    102|            case 'f': ParseFalse <parseFlags>(is, handler); break;
  ------------------
  |  Branch (1756:13): [True: 102, False: 1.09M]
  ------------------
 1757|  2.02k|            case '"': ParseString<parseFlags>(is, handler); break;
  ------------------
  |  Branch (1757:13): [True: 2.02k, False: 1.09M]
  ------------------
 1758|  3.57k|            case '{': ParseObject<parseFlags>(is, handler); break;
  ------------------
  |  Branch (1758:13): [True: 3.57k, False: 1.09M]
  ------------------
 1759|   263k|            case '[': ParseArray <parseFlags>(is, handler); break;
  ------------------
  |  Branch (1759:13): [True: 263k, False: 834k]
  ------------------
 1760|   828k|            default :
  ------------------
  |  Branch (1760:13): [True: 828k, False: 269k]
  ------------------
 1761|   828k|                      ParseNumber<parseFlags>(is, handler);
 1762|   828k|                      break;
 1763|       |
 1764|  1.09M|        }
 1765|  1.09M|    }
_ZN9rapidjson13GenericReaderINS_4UTF8IcEES2_NS_12CrtAllocatorEE9ParseTrueILj1ENS_25GenericInsituStringStreamIS2_EENS_15GenericDocumentIS2_NS_19MemoryPoolAllocatorIS3_EES3_EEEEvRT0_RT1_:
  869|     41|    void ParseTrue(InputStream& is, Handler& handler) {
  870|     41|        RAPIDJSON_ASSERT(is.Peek() == 't');
  ------------------
  |  |  437|     41|#define RAPIDJSON_ASSERT(x) assert(x)
  ------------------
  |  Branch (870:9): [True: 41, False: 0]
  ------------------
  871|     41|        is.Take();
  872|       |
  873|     41|        if (RAPIDJSON_LIKELY(Consume(is, 'r') && Consume(is, 'u') && Consume(is, 'e'))) {
  ------------------
  |  |  492|    164|#define RAPIDJSON_LIKELY(x) __builtin_expect(!!(x), 1)
  |  |  ------------------
  |  |  |  Branch (492:29): [True: 41, False: 0]
  |  |  |  Branch (492:49): [True: 41, False: 0]
  |  |  |  Branch (492:49): [True: 41, False: 0]
  |  |  |  Branch (492:49): [True: 41, False: 0]
  |  |  ------------------
  ------------------
  874|     41|            if (RAPIDJSON_UNLIKELY(!handler.Bool(true)))
  ------------------
  |  |  505|     41|#define RAPIDJSON_UNLIKELY(x) __builtin_expect(!!(x), 0)
  |  |  ------------------
  |  |  |  Branch (505:31): [True: 0, False: 41]
  |  |  ------------------
  ------------------
  875|     41|                RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell());
  ------------------
  |  |  120|      0|    RAPIDJSON_MULTILINEMACRO_BEGIN \
  |  |  ------------------
  |  |  |  |  516|      0|#define RAPIDJSON_MULTILINEMACRO_BEGIN do {
  |  |  ------------------
  |  |  121|      0|    RAPIDJSON_PARSE_ERROR_NORETURN(parseErrorCode, offset); \
  |  |  ------------------
  |  |  |  |  101|      0|    RAPIDJSON_MULTILINEMACRO_BEGIN \
  |  |  |  |  ------------------
  |  |  |  |  |  |  516|      0|#define RAPIDJSON_MULTILINEMACRO_BEGIN do {
  |  |  |  |  ------------------
  |  |  |  |  102|      0|    RAPIDJSON_ASSERT(!HasParseError()); /* Error can only be assigned once */ \
  |  |  |  |  ------------------
  |  |  |  |  |  |  437|      0|#define RAPIDJSON_ASSERT(x) assert(x)
  |  |  |  |  ------------------
  |  |  |  |  103|      0|    SetParseError(parseErrorCode, offset); \
  |  |  |  |  104|      0|    RAPIDJSON_MULTILINEMACRO_END
  |  |  |  |  ------------------
  |  |  |  |  |  |  517|      0|#define RAPIDJSON_MULTILINEMACRO_END \
  |  |  |  |  |  |  518|      0|} while((void)0, 0)
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  Branch (518:9): [Folded, False: 0]
  |  |  |  |  |  |  ------------------
  |  |  |  |  ------------------
  |  |  ------------------
  |  |  122|      0|    RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; \
  |  |  ------------------
  |  |  |  |   66|      0|    RAPIDJSON_PARSE_ERROR_EARLY_RETURN(RAPIDJSON_NOTHING)
  |  |  |  |  ------------------
  |  |  |  |  |  |   61|      0|    RAPIDJSON_MULTILINEMACRO_BEGIN \
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  516|      0|#define RAPIDJSON_MULTILINEMACRO_BEGIN do {
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |   62|      0|    if (RAPIDJSON_UNLIKELY(HasParseError())) { return value; } \
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  505|      0|#define RAPIDJSON_UNLIKELY(x) __builtin_expect(!!(x), 0)
  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  |  Branch (505:31): [True: 0, False: 0]
  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |   63|      0|    RAPIDJSON_MULTILINEMACRO_END
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  517|      0|#define RAPIDJSON_MULTILINEMACRO_END \
  |  |  |  |  |  |  |  |  518|      0|} while((void)0, 0)
  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  |  Branch (518:9): [Folded, False: 0]
  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  ------------------
  |  |  |  |  ------------------
  |  |  ------------------
  |  |  123|      0|    RAPIDJSON_MULTILINEMACRO_END
  |  |  ------------------
  |  |  |  |  517|      0|#define RAPIDJSON_MULTILINEMACRO_END \
  |  |  |  |  518|      0|} while((void)0, 0)
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (518:9): [Folded, False: 0]
  |  |  |  |  ------------------
  |  |  ------------------
  ------------------
  |  Branch (875:17): [True: 0, False: 0]
  ------------------
  876|     41|        }
  877|      0|        else
  878|       |            RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, is.Tell());
  ------------------
  |  |  120|      0|    RAPIDJSON_MULTILINEMACRO_BEGIN \
  |  |  ------------------
  |  |  |  |  516|      0|#define RAPIDJSON_MULTILINEMACRO_BEGIN do {
  |  |  ------------------
  |  |  121|      0|    RAPIDJSON_PARSE_ERROR_NORETURN(parseErrorCode, offset); \
  |  |  ------------------
  |  |  |  |  101|      0|    RAPIDJSON_MULTILINEMACRO_BEGIN \
  |  |  |  |  ------------------
  |  |  |  |  |  |  516|      0|#define RAPIDJSON_MULTILINEMACRO_BEGIN do {
  |  |  |  |  ------------------
  |  |  |  |  102|      0|    RAPIDJSON_ASSERT(!HasParseError()); /* Error can only be assigned once */ \
  |  |  |  |  ------------------
  |  |  |  |  |  |  437|      0|#define RAPIDJSON_ASSERT(x) assert(x)
  |  |  |  |  ------------------
  |  |  |  |  103|      0|    SetParseError(parseErrorCode, offset); \
  |  |  |  |  104|      0|    RAPIDJSON_MULTILINEMACRO_END
  |  |  |  |  ------------------
  |  |  |  |  |  |  517|      0|#define RAPIDJSON_MULTILINEMACRO_END \
  |  |  |  |  |  |  518|      0|} while((void)0, 0)
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  Branch (518:9): [Folded, False: 0]
  |  |  |  |  |  |  ------------------
  |  |  |  |  ------------------
  |  |  ------------------
  |  |  122|      0|    RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; \
  |  |  ------------------
  |  |  |  |   66|      0|    RAPIDJSON_PARSE_ERROR_EARLY_RETURN(RAPIDJSON_NOTHING)
  |  |  |  |  ------------------
  |  |  |  |  |  |   61|      0|    RAPIDJSON_MULTILINEMACRO_BEGIN \
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  516|      0|#define RAPIDJSON_MULTILINEMACRO_BEGIN do {
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |   62|      0|    if (RAPIDJSON_UNLIKELY(HasParseError())) { return value; } \
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  505|      0|#define RAPIDJSON_UNLIKELY(x) __builtin_expect(!!(x), 0)
  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  |  Branch (505:31): [True: 0, False: 0]
  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |   63|      0|    RAPIDJSON_MULTILINEMACRO_END
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  517|      0|#define RAPIDJSON_MULTILINEMACRO_END \
  |  |  |  |  |  |  |  |  518|      0|} while((void)0, 0)
  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  |  Branch (518:9): [Folded, False: 0]
  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  ------------------
  |  |  |  |  ------------------
  |  |  ------------------
  |  |  123|      0|    RAPIDJSON_MULTILINEMACRO_END
  |  |  ------------------
  |  |  |  |  517|      0|#define RAPIDJSON_MULTILINEMACRO_END \
  |  |  |  |  518|      0|} while((void)0, 0)
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (518:9): [Folded, False: 0]
  |  |  |  |  ------------------
  |  |  ------------------
  ------------------
  |  Branch (878:13): [True: 0, False: 0]
  ------------------
  879|     41|    }
_ZN9rapidjson13GenericReaderINS_4UTF8IcEES2_NS_12CrtAllocatorEE10ParseFalseILj1ENS_25GenericInsituStringStreamIS2_EENS_15GenericDocumentIS2_NS_19MemoryPoolAllocatorIS3_EES3_EEEEvRT0_RT1_:
  882|    102|    void ParseFalse(InputStream& is, Handler& handler) {
  883|    102|        RAPIDJSON_ASSERT(is.Peek() == 'f');
  ------------------
  |  |  437|    102|#define RAPIDJSON_ASSERT(x) assert(x)
  ------------------
  |  Branch (883:9): [True: 102, False: 0]
  ------------------
  884|    102|        is.Take();
  885|       |
  886|    102|        if (RAPIDJSON_LIKELY(Consume(is, 'a') && Consume(is, 'l') && Consume(is, 's') && Consume(is, 'e'))) {
  ------------------
  |  |  492|    612|#define RAPIDJSON_LIKELY(x) __builtin_expect(!!(x), 1)
  |  |  ------------------
  |  |  |  Branch (492:29): [True: 102, False: 0]
  |  |  |  Branch (492:49): [True: 102, False: 0]
  |  |  |  Branch (492:49): [True: 102, False: 0]
  |  |  |  Branch (492:49): [True: 102, False: 0]
  |  |  |  Branch (492:49): [True: 102, False: 0]
  |  |  ------------------
  ------------------
  887|    102|            if (RAPIDJSON_UNLIKELY(!handler.Bool(false)))
  ------------------
  |  |  505|    102|#define RAPIDJSON_UNLIKELY(x) __builtin_expect(!!(x), 0)
  |  |  ------------------
  |  |  |  Branch (505:31): [True: 0, False: 102]
  |  |  ------------------
  ------------------
  888|    102|                RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell());
  ------------------
  |  |  120|      0|    RAPIDJSON_MULTILINEMACRO_BEGIN \
  |  |  ------------------
  |  |  |  |  516|      0|#define RAPIDJSON_MULTILINEMACRO_BEGIN do {
  |  |  ------------------
  |  |  121|      0|    RAPIDJSON_PARSE_ERROR_NORETURN(parseErrorCode, offset); \
  |  |  ------------------
  |  |  |  |  101|      0|    RAPIDJSON_MULTILINEMACRO_BEGIN \
  |  |  |  |  ------------------
  |  |  |  |  |  |  516|      0|#define RAPIDJSON_MULTILINEMACRO_BEGIN do {
  |  |  |  |  ------------------
  |  |  |  |  102|      0|    RAPIDJSON_ASSERT(!HasParseError()); /* Error can only be assigned once */ \
  |  |  |  |  ------------------
  |  |  |  |  |  |  437|      0|#define RAPIDJSON_ASSERT(x) assert(x)
  |  |  |  |  ------------------
  |  |  |  |  103|      0|    SetParseError(parseErrorCode, offset); \
  |  |  |  |  104|      0|    RAPIDJSON_MULTILINEMACRO_END
  |  |  |  |  ------------------
  |  |  |  |  |  |  517|      0|#define RAPIDJSON_MULTILINEMACRO_END \
  |  |  |  |  |  |  518|      0|} while((void)0, 0)
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  Branch (518:9): [Folded, False: 0]
  |  |  |  |  |  |  ------------------
  |  |  |  |  ------------------
  |  |  ------------------
  |  |  122|      0|    RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; \
  |  |  ------------------
  |  |  |  |   66|      0|    RAPIDJSON_PARSE_ERROR_EARLY_RETURN(RAPIDJSON_NOTHING)
  |  |  |  |  ------------------
  |  |  |  |  |  |   61|      0|    RAPIDJSON_MULTILINEMACRO_BEGIN \
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  516|      0|#define RAPIDJSON_MULTILINEMACRO_BEGIN do {
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |   62|      0|    if (RAPIDJSON_UNLIKELY(HasParseError())) { return value; } \
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  505|      0|#define RAPIDJSON_UNLIKELY(x) __builtin_expect(!!(x), 0)
  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  |  Branch (505:31): [True: 0, False: 0]
  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |   63|      0|    RAPIDJSON_MULTILINEMACRO_END
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  517|      0|#define RAPIDJSON_MULTILINEMACRO_END \
  |  |  |  |  |  |  |  |  518|      0|} while((void)0, 0)
  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  |  Branch (518:9): [Folded, False: 0]
  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  ------------------
  |  |  |  |  ------------------
  |  |  ------------------
  |  |  123|      0|    RAPIDJSON_MULTILINEMACRO_END
  |  |  ------------------
  |  |  |  |  517|      0|#define RAPIDJSON_MULTILINEMACRO_END \
  |  |  |  |  518|      0|} while((void)0, 0)
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (518:9): [Folded, False: 0]
  |  |  |  |  ------------------
  |  |  ------------------
  ------------------
  |  Branch (888:17): [True: 0, False: 0]
  ------------------
  889|    102|        }
  890|      0|        else
  891|       |            RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, is.Tell());
  ------------------
  |  |  120|      0|    RAPIDJSON_MULTILINEMACRO_BEGIN \
  |  |  ------------------
  |  |  |  |  516|      0|#define RAPIDJSON_MULTILINEMACRO_BEGIN do {
  |  |  ------------------
  |  |  121|      0|    RAPIDJSON_PARSE_ERROR_NORETURN(parseErrorCode, offset); \
  |  |  ------------------
  |  |  |  |  101|      0|    RAPIDJSON_MULTILINEMACRO_BEGIN \
  |  |  |  |  ------------------
  |  |  |  |  |  |  516|      0|#define RAPIDJSON_MULTILINEMACRO_BEGIN do {
  |  |  |  |  ------------------
  |  |  |  |  102|      0|    RAPIDJSON_ASSERT(!HasParseError()); /* Error can only be assigned once */ \
  |  |  |  |  ------------------
  |  |  |  |  |  |  437|      0|#define RAPIDJSON_ASSERT(x) assert(x)
  |  |  |  |  ------------------
  |  |  |  |  103|      0|    SetParseError(parseErrorCode, offset); \
  |  |  |  |  104|      0|    RAPIDJSON_MULTILINEMACRO_END
  |  |  |  |  ------------------
  |  |  |  |  |  |  517|      0|#define RAPIDJSON_MULTILINEMACRO_END \
  |  |  |  |  |  |  518|      0|} while((void)0, 0)
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  Branch (518:9): [Folded, False: 0]
  |  |  |  |  |  |  ------------------
  |  |  |  |  ------------------
  |  |  ------------------
  |  |  122|      0|    RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; \
  |  |  ------------------
  |  |  |  |   66|      0|    RAPIDJSON_PARSE_ERROR_EARLY_RETURN(RAPIDJSON_NOTHING)
  |  |  |  |  ------------------
  |  |  |  |  |  |   61|      0|    RAPIDJSON_MULTILINEMACRO_BEGIN \
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  516|      0|#define RAPIDJSON_MULTILINEMACRO_BEGIN do {
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |   62|      0|    if (RAPIDJSON_UNLIKELY(HasParseError())) { return value; } \
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  505|      0|#define RAPIDJSON_UNLIKELY(x) __builtin_expect(!!(x), 0)
  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  |  Branch (505:31): [True: 0, False: 0]
  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |   63|      0|    RAPIDJSON_MULTILINEMACRO_END
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  517|      0|#define RAPIDJSON_MULTILINEMACRO_END \
  |  |  |  |  |  |  |  |  518|      0|} while((void)0, 0)
  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  |  Branch (518:9): [Folded, False: 0]
  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  ------------------
  |  |  |  |  ------------------
  |  |  ------------------
  |  |  123|      0|    RAPIDJSON_MULTILINEMACRO_END
  |  |  ------------------
  |  |  |  |  517|      0|#define RAPIDJSON_MULTILINEMACRO_END \
  |  |  |  |  518|      0|} while((void)0, 0)
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (518:9): [Folded, False: 0]
  |  |  |  |  ------------------
  |  |  ------------------
  ------------------
  |  Branch (891:13): [True: 0, False: 0]
  ------------------
  892|    102|    }
_ZN9rapidjson13GenericReaderINS_4UTF8IcEES2_NS_12CrtAllocatorEE11ParseObjectILj1ENS_25GenericInsituStringStreamIS2_EENS_15GenericDocumentIS2_NS_19MemoryPoolAllocatorIS3_EES3_EEEEvRT0_RT1_:
  740|  3.57k|    void ParseObject(InputStream& is, Handler& handler) {
  741|  3.57k|        RAPIDJSON_ASSERT(is.Peek() == '{');
  ------------------
  |  |  437|  3.57k|#define RAPIDJSON_ASSERT(x) assert(x)
  ------------------
  |  Branch (741:9): [True: 3.57k, False: 0]
  ------------------
  742|  3.57k|        is.Take();  // Skip '{'
  743|       |
  744|  3.57k|        if (RAPIDJSON_UNLIKELY(!handler.StartObject()))
  ------------------
  |  |  505|  3.57k|#define RAPIDJSON_UNLIKELY(x) __builtin_expect(!!(x), 0)
  |  |  ------------------
  |  |  |  Branch (505:31): [True: 0, False: 3.57k]
  |  |  ------------------
  ------------------
  745|  3.57k|            RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell());
  ------------------
  |  |  120|      0|    RAPIDJSON_MULTILINEMACRO_BEGIN \
  |  |  ------------------
  |  |  |  |  516|      0|#define RAPIDJSON_MULTILINEMACRO_BEGIN do {
  |  |  ------------------
  |  |  121|      0|    RAPIDJSON_PARSE_ERROR_NORETURN(parseErrorCode, offset); \
  |  |  ------------------
  |  |  |  |  101|      0|    RAPIDJSON_MULTILINEMACRO_BEGIN \
  |  |  |  |  ------------------
  |  |  |  |  |  |  516|      0|#define RAPIDJSON_MULTILINEMACRO_BEGIN do {
  |  |  |  |  ------------------
  |  |  |  |  102|      0|    RAPIDJSON_ASSERT(!HasParseError()); /* Error can only be assigned once */ \
  |  |  |  |  ------------------
  |  |  |  |  |  |  437|      0|#define RAPIDJSON_ASSERT(x) assert(x)
  |  |  |  |  ------------------
  |  |  |  |  103|      0|    SetParseError(parseErrorCode, offset); \
  |  |  |  |  104|      0|    RAPIDJSON_MULTILINEMACRO_END
  |  |  |  |  ------------------
  |  |  |  |  |  |  517|      0|#define RAPIDJSON_MULTILINEMACRO_END \
  |  |  |  |  |  |  518|      0|} while((void)0, 0)
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  Branch (518:9): [Folded, False: 0]
  |  |  |  |  |  |  ------------------
  |  |  |  |  ------------------
  |  |  ------------------
  |  |  122|      0|    RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; \
  |  |  ------------------
  |  |  |  |   66|      0|    RAPIDJSON_PARSE_ERROR_EARLY_RETURN(RAPIDJSON_NOTHING)
  |  |  |  |  ------------------
  |  |  |  |  |  |   61|      0|    RAPIDJSON_MULTILINEMACRO_BEGIN \
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  516|      0|#define RAPIDJSON_MULTILINEMACRO_BEGIN do {
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |   62|      0|    if (RAPIDJSON_UNLIKELY(HasParseError())) { return value; } \
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  505|      0|#define RAPIDJSON_UNLIKELY(x) __builtin_expect(!!(x), 0)
  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  |  Branch (505:31): [True: 0, False: 0]
  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |   63|      0|    RAPIDJSON_MULTILINEMACRO_END
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  517|      0|#define RAPIDJSON_MULTILINEMACRO_END \
  |  |  |  |  |  |  |  |  518|      0|} while((void)0, 0)
  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  |  Branch (518:9): [Folded, False: 0]
  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  ------------------
  |  |  |  |  ------------------
  |  |  ------------------
  |  |  123|      0|    RAPIDJSON_MULTILINEMACRO_END
  |  |  ------------------
  |  |  |  |  517|      0|#define RAPIDJSON_MULTILINEMACRO_END \
  |  |  |  |  518|      0|} while((void)0, 0)
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (518:9): [Folded, False: 0]
  |  |  |  |  ------------------
  |  |  ------------------
  ------------------
  |  Branch (745:13): [True: 0, False: 0]
  ------------------
  746|       |
  747|  3.57k|        SkipWhitespaceAndComments<parseFlags>(is);
  748|  3.57k|        RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
  ------------------
  |  |   66|  3.57k|    RAPIDJSON_PARSE_ERROR_EARLY_RETURN(RAPIDJSON_NOTHING)
  |  |  ------------------
  |  |  |  |   61|  3.57k|    RAPIDJSON_MULTILINEMACRO_BEGIN \
  |  |  |  |  ------------------
  |  |  |  |  |  |  516|  3.57k|#define RAPIDJSON_MULTILINEMACRO_BEGIN do {
  |  |  |  |  ------------------
  |  |  |  |   62|  3.57k|    if (RAPIDJSON_UNLIKELY(HasParseError())) { return value; } \
  |  |  |  |  ------------------
  |  |  |  |  |  |  505|  3.57k|#define RAPIDJSON_UNLIKELY(x) __builtin_expect(!!(x), 0)
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  Branch (505:31): [True: 0, False: 3.57k]
  |  |  |  |  |  |  ------------------
  |  |  |  |  ------------------
  |  |  |  |   63|  3.57k|    RAPIDJSON_MULTILINEMACRO_END
  |  |  |  |  ------------------
  |  |  |  |  |  |  517|  3.57k|#define RAPIDJSON_MULTILINEMACRO_END \
  |  |  |  |  |  |  518|  3.57k|} while((void)0, 0)
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  Branch (518:9): [Folded, False: 3.57k]
  |  |  |  |  |  |  ------------------
  |  |  |  |  ------------------
  |  |  ------------------
  ------------------
  749|       |
  750|  3.57k|        if (Consume(is, '}')) {
  ------------------
  |  Branch (750:13): [True: 14, False: 3.55k]
  ------------------
  751|     14|            if (RAPIDJSON_UNLIKELY(!handler.EndObject(0)))  // empty object
  ------------------
  |  |  505|     14|#define RAPIDJSON_UNLIKELY(x) __builtin_expect(!!(x), 0)
  |  |  ------------------
  |  |  |  Branch (505:31): [True: 0, False: 14]
  |  |  ------------------
  ------------------
  752|     14|                RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell());
  ------------------
  |  |  120|      0|    RAPIDJSON_MULTILINEMACRO_BEGIN \
  |  |  ------------------
  |  |  |  |  516|      0|#define RAPIDJSON_MULTILINEMACRO_BEGIN do {
  |  |  ------------------
  |  |  121|      0|    RAPIDJSON_PARSE_ERROR_NORETURN(parseErrorCode, offset); \
  |  |  ------------------
  |  |  |  |  101|      0|    RAPIDJSON_MULTILINEMACRO_BEGIN \
  |  |  |  |  ------------------
  |  |  |  |  |  |  516|      0|#define RAPIDJSON_MULTILINEMACRO_BEGIN do {
  |  |  |  |  ------------------
  |  |  |  |  102|      0|    RAPIDJSON_ASSERT(!HasParseError()); /* Error can only be assigned once */ \
  |  |  |  |  ------------------
  |  |  |  |  |  |  437|      0|#define RAPIDJSON_ASSERT(x) assert(x)
  |  |  |  |  ------------------
  |  |  |  |  103|      0|    SetParseError(parseErrorCode, offset); \
  |  |  |  |  104|      0|    RAPIDJSON_MULTILINEMACRO_END
  |  |  |  |  ------------------
  |  |  |  |  |  |  517|      0|#define RAPIDJSON_MULTILINEMACRO_END \
  |  |  |  |  |  |  518|      0|} while((void)0, 0)
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  Branch (518:9): [Folded, False: 0]
  |  |  |  |  |  |  ------------------
  |  |  |  |  ------------------
  |  |  ------------------
  |  |  122|      0|    RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; \
  |  |  ------------------
  |  |  |  |   66|      0|    RAPIDJSON_PARSE_ERROR_EARLY_RETURN(RAPIDJSON_NOTHING)
  |  |  |  |  ------------------
  |  |  |  |  |  |   61|      0|    RAPIDJSON_MULTILINEMACRO_BEGIN \
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  516|      0|#define RAPIDJSON_MULTILINEMACRO_BEGIN do {
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |   62|      0|    if (RAPIDJSON_UNLIKELY(HasParseError())) { return value; } \
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  505|      0|#define RAPIDJSON_UNLIKELY(x) __builtin_expect(!!(x), 0)
  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  |  Branch (505:31): [True: 0, False: 0]
  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |   63|      0|    RAPIDJSON_MULTILINEMACRO_END
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  517|      0|#define RAPIDJSON_MULTILINEMACRO_END \
  |  |  |  |  |  |  |  |  518|      0|} while((void)0, 0)
  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  |  Branch (518:9): [Folded, False: 0]
  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  ------------------
  |  |  |  |  ------------------
  |  |  ------------------
  |  |  123|      0|    RAPIDJSON_MULTILINEMACRO_END
  |  |  ------------------
  |  |  |  |  517|      0|#define RAPIDJSON_MULTILINEMACRO_END \
  |  |  |  |  518|      0|} while((void)0, 0)
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (518:9): [Folded, False: 0]
  |  |  |  |  ------------------
  |  |  ------------------
  ------------------
  |  Branch (752:17): [True: 0, False: 0]
  ------------------
  753|     14|            return;
  754|     14|        }
  755|       |
  756|  11.5k|        for (SizeType memberCount = 0;;) {
  757|  11.5k|            if (RAPIDJSON_UNLIKELY(is.Peek() != '"'))
  ------------------
  |  |  505|  11.5k|#define RAPIDJSON_UNLIKELY(x) __builtin_expect(!!(x), 0)
  |  |  ------------------
  |  |  |  Branch (505:31): [True: 0, False: 11.5k]
  |  |  ------------------
  ------------------
  758|  11.5k|                RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissName, is.Tell());
  ------------------
  |  |  120|      0|    RAPIDJSON_MULTILINEMACRO_BEGIN \
  |  |  ------------------
  |  |  |  |  516|      0|#define RAPIDJSON_MULTILINEMACRO_BEGIN do {
  |  |  ------------------
  |  |  121|      0|    RAPIDJSON_PARSE_ERROR_NORETURN(parseErrorCode, offset); \
  |  |  ------------------
  |  |  |  |  101|      0|    RAPIDJSON_MULTILINEMACRO_BEGIN \
  |  |  |  |  ------------------
  |  |  |  |  |  |  516|      0|#define RAPIDJSON_MULTILINEMACRO_BEGIN do {
  |  |  |  |  ------------------
  |  |  |  |  102|      0|    RAPIDJSON_ASSERT(!HasParseError()); /* Error can only be assigned once */ \
  |  |  |  |  ------------------
  |  |  |  |  |  |  437|      0|#define RAPIDJSON_ASSERT(x) assert(x)
  |  |  |  |  ------------------
  |  |  |  |  103|      0|    SetParseError(parseErrorCode, offset); \
  |  |  |  |  104|      0|    RAPIDJSON_MULTILINEMACRO_END
  |  |  |  |  ------------------
  |  |  |  |  |  |  517|      0|#define RAPIDJSON_MULTILINEMACRO_END \
  |  |  |  |  |  |  518|      0|} while((void)0, 0)
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  Branch (518:9): [Folded, False: 0]
  |  |  |  |  |  |  ------------------
  |  |  |  |  ------------------
  |  |  ------------------
  |  |  122|      0|    RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; \
  |  |  ------------------
  |  |  |  |   66|      0|    RAPIDJSON_PARSE_ERROR_EARLY_RETURN(RAPIDJSON_NOTHING)
  |  |  |  |  ------------------
  |  |  |  |  |  |   61|      0|    RAPIDJSON_MULTILINEMACRO_BEGIN \
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  516|      0|#define RAPIDJSON_MULTILINEMACRO_BEGIN do {
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |   62|      0|    if (RAPIDJSON_UNLIKELY(HasParseError())) { return value; } \
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  505|      0|#define RAPIDJSON_UNLIKELY(x) __builtin_expect(!!(x), 0)
  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  |  Branch (505:31): [True: 0, False: 0]
  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |   63|      0|    RAPIDJSON_MULTILINEMACRO_END
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  517|      0|#define RAPIDJSON_MULTILINEMACRO_END \
  |  |  |  |  |  |  |  |  518|      0|} while((void)0, 0)
  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  |  Branch (518:9): [Folded, False: 0]
  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  ------------------
  |  |  |  |  ------------------
  |  |  ------------------
  |  |  123|      0|    RAPIDJSON_MULTILINEMACRO_END
  |  |  ------------------
  |  |  |  |  517|      0|#define RAPIDJSON_MULTILINEMACRO_END \
  |  |  |  |  518|      0|} while((void)0, 0)
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (518:9): [Folded, False: 0]
  |  |  |  |  ------------------
  |  |  ------------------
  ------------------
  |  Branch (758:17): [True: 0, False: 0]
  ------------------
  759|       |
  760|  11.5k|            ParseString<parseFlags>(is, handler, true);
  761|  11.5k|            RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
  ------------------
  |  |   66|  11.5k|    RAPIDJSON_PARSE_ERROR_EARLY_RETURN(RAPIDJSON_NOTHING)
  |  |  ------------------
  |  |  |  |   61|  11.5k|    RAPIDJSON_MULTILINEMACRO_BEGIN \
  |  |  |  |  ------------------
  |  |  |  |  |  |  516|  11.5k|#define RAPIDJSON_MULTILINEMACRO_BEGIN do {
  |  |  |  |  ------------------
  |  |  |  |   62|  11.5k|    if (RAPIDJSON_UNLIKELY(HasParseError())) { return value; } \
  |  |  |  |  ------------------
  |  |  |  |  |  |  505|  11.5k|#define RAPIDJSON_UNLIKELY(x) __builtin_expect(!!(x), 0)
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  Branch (505:31): [True: 0, False: 11.5k]
  |  |  |  |  |  |  ------------------
  |  |  |  |  ------------------
  |  |  |  |   63|  11.5k|    RAPIDJSON_MULTILINEMACRO_END
  |  |  |  |  ------------------
  |  |  |  |  |  |  517|  11.5k|#define RAPIDJSON_MULTILINEMACRO_END \
  |  |  |  |  |  |  518|  11.5k|} while((void)0, 0)
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  Branch (518:9): [Folded, False: 11.5k]
  |  |  |  |  |  |  ------------------
  |  |  |  |  ------------------
  |  |  ------------------
  ------------------
  762|       |
  763|  11.5k|            SkipWhitespaceAndComments<parseFlags>(is);
  764|  11.5k|            RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
  ------------------
  |  |   66|  11.5k|    RAPIDJSON_PARSE_ERROR_EARLY_RETURN(RAPIDJSON_NOTHING)
  |  |  ------------------
  |  |  |  |   61|  11.5k|    RAPIDJSON_MULTILINEMACRO_BEGIN \
  |  |  |  |  ------------------
  |  |  |  |  |  |  516|  11.5k|#define RAPIDJSON_MULTILINEMACRO_BEGIN do {
  |  |  |  |  ------------------
  |  |  |  |   62|  11.5k|    if (RAPIDJSON_UNLIKELY(HasParseError())) { return value; } \
  |  |  |  |  ------------------
  |  |  |  |  |  |  505|  11.5k|#define RAPIDJSON_UNLIKELY(x) __builtin_expect(!!(x), 0)
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  Branch (505:31): [True: 0, False: 11.5k]
  |  |  |  |  |  |  ------------------
  |  |  |  |  ------------------
  |  |  |  |   63|  11.5k|    RAPIDJSON_MULTILINEMACRO_END
  |  |  |  |  ------------------
  |  |  |  |  |  |  517|  11.5k|#define RAPIDJSON_MULTILINEMACRO_END \
  |  |  |  |  |  |  518|  11.5k|} while((void)0, 0)
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  Branch (518:9): [Folded, False: 11.5k]
  |  |  |  |  |  |  ------------------
  |  |  |  |  ------------------
  |  |  ------------------
  ------------------
  765|       |
  766|  11.5k|            if (RAPIDJSON_UNLIKELY(!Consume(is, ':')))
  ------------------
  |  |  505|  11.5k|#define RAPIDJSON_UNLIKELY(x) __builtin_expect(!!(x), 0)
  |  |  ------------------
  |  |  |  Branch (505:31): [True: 0, False: 11.5k]
  |  |  ------------------
  ------------------
  767|  11.5k|                RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissColon, is.Tell());
  ------------------
  |  |  120|      0|    RAPIDJSON_MULTILINEMACRO_BEGIN \
  |  |  ------------------
  |  |  |  |  516|      0|#define RAPIDJSON_MULTILINEMACRO_BEGIN do {
  |  |  ------------------
  |  |  121|      0|    RAPIDJSON_PARSE_ERROR_NORETURN(parseErrorCode, offset); \
  |  |  ------------------
  |  |  |  |  101|      0|    RAPIDJSON_MULTILINEMACRO_BEGIN \
  |  |  |  |  ------------------
  |  |  |  |  |  |  516|      0|#define RAPIDJSON_MULTILINEMACRO_BEGIN do {
  |  |  |  |  ------------------
  |  |  |  |  102|      0|    RAPIDJSON_ASSERT(!HasParseError()); /* Error can only be assigned once */ \
  |  |  |  |  ------------------
  |  |  |  |  |  |  437|      0|#define RAPIDJSON_ASSERT(x) assert(x)
  |  |  |  |  ------------------
  |  |  |  |  103|      0|    SetParseError(parseErrorCode, offset); \
  |  |  |  |  104|      0|    RAPIDJSON_MULTILINEMACRO_END
  |  |  |  |  ------------------
  |  |  |  |  |  |  517|      0|#define RAPIDJSON_MULTILINEMACRO_END \
  |  |  |  |  |  |  518|      0|} while((void)0, 0)
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  Branch (518:9): [Folded, False: 0]
  |  |  |  |  |  |  ------------------
  |  |  |  |  ------------------
  |  |  ------------------
  |  |  122|      0|    RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; \
  |  |  ------------------
  |  |  |  |   66|      0|    RAPIDJSON_PARSE_ERROR_EARLY_RETURN(RAPIDJSON_NOTHING)
  |  |  |  |  ------------------
  |  |  |  |  |  |   61|      0|    RAPIDJSON_MULTILINEMACRO_BEGIN \
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  516|      0|#define RAPIDJSON_MULTILINEMACRO_BEGIN do {
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |   62|      0|    if (RAPIDJSON_UNLIKELY(HasParseError())) { return value; } \
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  505|      0|#define RAPIDJSON_UNLIKELY(x) __builtin_expect(!!(x), 0)
  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  |  Branch (505:31): [True: 0, False: 0]
  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |   63|      0|    RAPIDJSON_MULTILINEMACRO_END
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  517|      0|#define RAPIDJSON_MULTILINEMACRO_END \
  |  |  |  |  |  |  |  |  518|      0|} while((void)0, 0)
  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  |  Branch (518:9): [Folded, False: 0]
  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  ------------------
  |  |  |  |  ------------------
  |  |  ------------------
  |  |  123|      0|    RAPIDJSON_MULTILINEMACRO_END
  |  |  ------------------
  |  |  |  |  517|      0|#define RAPIDJSON_MULTILINEMACRO_END \
  |  |  |  |  518|      0|} while((void)0, 0)
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (518:9): [Folded, False: 0]
  |  |  |  |  ------------------
  |  |  ------------------
  ------------------
  |  Branch (767:17): [True: 0, False: 0]
  ------------------
  768|       |
  769|  11.5k|            SkipWhitespaceAndComments<parseFlags>(is);
  770|  11.5k|            RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
  ------------------
  |  |   66|  11.5k|    RAPIDJSON_PARSE_ERROR_EARLY_RETURN(RAPIDJSON_NOTHING)
  |  |  ------------------
  |  |  |  |   61|  11.5k|    RAPIDJSON_MULTILINEMACRO_BEGIN \
  |  |  |  |  ------------------
  |  |  |  |  |  |  516|  11.5k|#define RAPIDJSON_MULTILINEMACRO_BEGIN do {
  |  |  |  |  ------------------
  |  |  |  |   62|  11.5k|    if (RAPIDJSON_UNLIKELY(HasParseError())) { return value; } \
  |  |  |  |  ------------------
  |  |  |  |  |  |  505|  11.5k|#define RAPIDJSON_UNLIKELY(x) __builtin_expect(!!(x), 0)
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  Branch (505:31): [True: 0, False: 11.5k]
  |  |  |  |  |  |  ------------------
  |  |  |  |  ------------------
  |  |  |  |   63|  11.5k|    RAPIDJSON_MULTILINEMACRO_END
  |  |  |  |  ------------------
  |  |  |  |  |  |  517|  11.5k|#define RAPIDJSON_MULTILINEMACRO_END \
  |  |  |  |  |  |  518|  11.5k|} while((void)0, 0)
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  Branch (518:9): [Folded, False: 11.5k]
  |  |  |  |  |  |  ------------------
  |  |  |  |  ------------------
  |  |  ------------------
  ------------------
  771|       |
  772|  11.5k|            ParseValue<parseFlags>(is, handler);
  773|  11.5k|            RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
  ------------------
  |  |   66|  11.5k|    RAPIDJSON_PARSE_ERROR_EARLY_RETURN(RAPIDJSON_NOTHING)
  |  |  ------------------
  |  |  |  |   61|  11.5k|    RAPIDJSON_MULTILINEMACRO_BEGIN \
  |  |  |  |  ------------------
  |  |  |  |  |  |  516|  11.5k|#define RAPIDJSON_MULTILINEMACRO_BEGIN do {
  |  |  |  |  ------------------
  |  |  |  |   62|  11.5k|    if (RAPIDJSON_UNLIKELY(HasParseError())) { return value; } \
  |  |  |  |  ------------------
  |  |  |  |  |  |  505|  11.5k|#define RAPIDJSON_UNLIKELY(x) __builtin_expect(!!(x), 0)
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  Branch (505:31): [True: 0, False: 11.5k]
  |  |  |  |  |  |  ------------------
  |  |  |  |  ------------------
  |  |  |  |   63|  11.5k|    RAPIDJSON_MULTILINEMACRO_END
  |  |  |  |  ------------------
  |  |  |  |  |  |  517|  11.5k|#define RAPIDJSON_MULTILINEMACRO_END \
  |  |  |  |  |  |  518|  11.5k|} while((void)0, 0)
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  Branch (518:9): [Folded, False: 11.5k]
  |  |  |  |  |  |  ------------------
  |  |  |  |  ------------------
  |  |  ------------------
  ------------------
  774|       |
  775|  11.5k|            SkipWhitespaceAndComments<parseFlags>(is);
  776|  11.5k|            RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
  ------------------
  |  |   66|  11.5k|    RAPIDJSON_PARSE_ERROR_EARLY_RETURN(RAPIDJSON_NOTHING)
  |  |  ------------------
  |  |  |  |   61|  11.5k|    RAPIDJSON_MULTILINEMACRO_BEGIN \
  |  |  |  |  ------------------
  |  |  |  |  |  |  516|  11.5k|#define RAPIDJSON_MULTILINEMACRO_BEGIN do {
  |  |  |  |  ------------------
  |  |  |  |   62|  11.5k|    if (RAPIDJSON_UNLIKELY(HasParseError())) { return value; } \
  |  |  |  |  ------------------
  |  |  |  |  |  |  505|  11.5k|#define RAPIDJSON_UNLIKELY(x) __builtin_expect(!!(x), 0)
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  Branch (505:31): [True: 0, False: 11.5k]
  |  |  |  |  |  |  ------------------
  |  |  |  |  ------------------
  |  |  |  |   63|  11.5k|    RAPIDJSON_MULTILINEMACRO_END
  |  |  |  |  ------------------
  |  |  |  |  |  |  517|  11.5k|#define RAPIDJSON_MULTILINEMACRO_END \
  |  |  |  |  |  |  518|  11.5k|} while((void)0, 0)
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  Branch (518:9): [Folded, False: 11.5k]
  |  |  |  |  |  |  ------------------
  |  |  |  |  ------------------
  |  |  ------------------
  ------------------
  777|       |
  778|  11.5k|            ++memberCount;
  779|       |
  780|  11.5k|            switch (is.Peek()) {
  781|  8.01k|                case ',':
  ------------------
  |  Branch (781:17): [True: 8.01k, False: 3.55k]
  ------------------
  782|  8.01k|                    is.Take();
  783|  8.01k|                    SkipWhitespaceAndComments<parseFlags>(is);
  784|  8.01k|                    RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
  ------------------
  |  |   66|  8.01k|    RAPIDJSON_PARSE_ERROR_EARLY_RETURN(RAPIDJSON_NOTHING)
  |  |  ------------------
  |  |  |  |   61|  8.01k|    RAPIDJSON_MULTILINEMACRO_BEGIN \
  |  |  |  |  ------------------
  |  |  |  |  |  |  516|  8.01k|#define RAPIDJSON_MULTILINEMACRO_BEGIN do {
  |  |  |  |  ------------------
  |  |  |  |   62|  8.01k|    if (RAPIDJSON_UNLIKELY(HasParseError())) { return value; } \
  |  |  |  |  ------------------
  |  |  |  |  |  |  505|  8.01k|#define RAPIDJSON_UNLIKELY(x) __builtin_expect(!!(x), 0)
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  Branch (505:31): [True: 0, False: 8.01k]
  |  |  |  |  |  |  ------------------
  |  |  |  |  ------------------
  |  |  |  |   63|  8.01k|    RAPIDJSON_MULTILINEMACRO_END
  |  |  |  |  ------------------
  |  |  |  |  |  |  517|  8.01k|#define RAPIDJSON_MULTILINEMACRO_END \
  |  |  |  |  |  |  518|  8.01k|} while((void)0, 0)
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  Branch (518:9): [Folded, False: 8.01k]
  |  |  |  |  |  |  ------------------
  |  |  |  |  ------------------
  |  |  ------------------
  ------------------
  785|  8.01k|                    break;
  786|  8.01k|                case '}':
  ------------------
  |  Branch (786:17): [True: 3.55k, False: 8.01k]
  ------------------
  787|  3.55k|                    is.Take();
  788|  3.55k|                    if (RAPIDJSON_UNLIKELY(!handler.EndObject(memberCount)))
  ------------------
  |  |  505|  3.55k|#define RAPIDJSON_UNLIKELY(x) __builtin_expect(!!(x), 0)
  |  |  ------------------
  |  |  |  Branch (505:31): [True: 0, False: 3.55k]
  |  |  ------------------
  ------------------
  789|  3.55k|                        RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell());
  ------------------
  |  |  120|      0|    RAPIDJSON_MULTILINEMACRO_BEGIN \
  |  |  ------------------
  |  |  |  |  516|      0|#define RAPIDJSON_MULTILINEMACRO_BEGIN do {
  |  |  ------------------
  |  |  121|      0|    RAPIDJSON_PARSE_ERROR_NORETURN(parseErrorCode, offset); \
  |  |  ------------------
  |  |  |  |  101|      0|    RAPIDJSON_MULTILINEMACRO_BEGIN \
  |  |  |  |  ------------------
  |  |  |  |  |  |  516|      0|#define RAPIDJSON_MULTILINEMACRO_BEGIN do {
  |  |  |  |  ------------------
  |  |  |  |  102|      0|    RAPIDJSON_ASSERT(!HasParseError()); /* Error can only be assigned once */ \
  |  |  |  |  ------------------
  |  |  |  |  |  |  437|      0|#define RAPIDJSON_ASSERT(x) assert(x)
  |  |  |  |  ------------------
  |  |  |  |  103|      0|    SetParseError(parseErrorCode, offset); \
  |  |  |  |  104|      0|    RAPIDJSON_MULTILINEMACRO_END
  |  |  |  |  ------------------
  |  |  |  |  |  |  517|      0|#define RAPIDJSON_MULTILINEMACRO_END \
  |  |  |  |  |  |  518|      0|} while((void)0, 0)
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  Branch (518:9): [Folded, False: 0]
  |  |  |  |  |  |  ------------------
  |  |  |  |  ------------------
  |  |  ------------------
  |  |  122|      0|    RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; \
  |  |  ------------------
  |  |  |  |   66|      0|    RAPIDJSON_PARSE_ERROR_EARLY_RETURN(RAPIDJSON_NOTHING)
  |  |  |  |  ------------------
  |  |  |  |  |  |   61|      0|    RAPIDJSON_MULTILINEMACRO_BEGIN \
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  516|      0|#define RAPIDJSON_MULTILINEMACRO_BEGIN do {
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |   62|      0|    if (RAPIDJSON_UNLIKELY(HasParseError())) { return value; } \
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  505|      0|#define RAPIDJSON_UNLIKELY(x) __builtin_expect(!!(x), 0)
  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  |  Branch (505:31): [True: 0, False: 0]
  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |   63|      0|    RAPIDJSON_MULTILINEMACRO_END
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  517|      0|#define RAPIDJSON_MULTILINEMACRO_END \
  |  |  |  |  |  |  |  |  518|      0|} while((void)0, 0)
  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  |  Branch (518:9): [Folded, False: 0]
  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  ------------------
  |  |  |  |  ------------------
  |  |  ------------------
  |  |  123|      0|    RAPIDJSON_MULTILINEMACRO_END
  |  |  ------------------
  |  |  |  |  517|      0|#define RAPIDJSON_MULTILINEMACRO_END \
  |  |  |  |  518|      0|} while((void)0, 0)
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (518:9): [Folded, False: 0]
  |  |  |  |  ------------------
  |  |  ------------------
  ------------------
  |  Branch (789:25): [True: 0, False: 0]
  ------------------
  790|  3.55k|                    return;
  791|  3.55k|                default:
  ------------------
  |  Branch (791:17): [True: 0, False: 11.5k]
  ------------------
  792|      0|                    RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissCommaOrCurlyBracket, is.Tell()); break; // This useless break is only for making warning and coverage happy
  ------------------
  |  |  120|      0|    RAPIDJSON_MULTILINEMACRO_BEGIN \
  |  |  ------------------
  |  |  |  |  516|      0|#define RAPIDJSON_MULTILINEMACRO_BEGIN do {
  |  |  ------------------
  |  |  121|      0|    RAPIDJSON_PARSE_ERROR_NORETURN(parseErrorCode, offset); \
  |  |  ------------------
  |  |  |  |  101|      0|    RAPIDJSON_MULTILINEMACRO_BEGIN \
  |  |  |  |  ------------------
  |  |  |  |  |  |  516|      0|#define RAPIDJSON_MULTILINEMACRO_BEGIN do {
  |  |  |  |  ------------------
  |  |  |  |  102|      0|    RAPIDJSON_ASSERT(!HasParseError()); /* Error can only be assigned once */ \
  |  |  |  |  ------------------
  |  |  |  |  |  |  437|      0|#define RAPIDJSON_ASSERT(x) assert(x)
  |  |  |  |  ------------------
  |  |  |  |  103|      0|    SetParseError(parseErrorCode, offset); \
  |  |  |  |  104|      0|    RAPIDJSON_MULTILINEMACRO_END
  |  |  |  |  ------------------
  |  |  |  |  |  |  517|      0|#define RAPIDJSON_MULTILINEMACRO_END \
  |  |  |  |  |  |  518|      0|} while((void)0, 0)
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  Branch (518:9): [Folded, False: 0]
  |  |  |  |  |  |  ------------------
  |  |  |  |  ------------------
  |  |  ------------------
  |  |  122|      0|    RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; \
  |  |  ------------------
  |  |  |  |   66|      0|    RAPIDJSON_PARSE_ERROR_EARLY_RETURN(RAPIDJSON_NOTHING)
  |  |  |  |  ------------------
  |  |  |  |  |  |   61|      0|    RAPIDJSON_MULTILINEMACRO_BEGIN \
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  516|      0|#define RAPIDJSON_MULTILINEMACRO_BEGIN do {
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |   62|      0|    if (RAPIDJSON_UNLIKELY(HasParseError())) { return value; } \
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  505|      0|#define RAPIDJSON_UNLIKELY(x) __builtin_expect(!!(x), 0)
  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  |  Branch (505:31): [True: 0, False: 0]
  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |   63|      0|    RAPIDJSON_MULTILINEMACRO_END
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  517|      0|#define RAPIDJSON_MULTILINEMACRO_END \
  |  |  |  |  |  |  |  |  518|      0|} while((void)0, 0)
  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  |  Branch (518:9): [Folded, False: 0]
  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  ------------------
  |  |  |  |  ------------------
  |  |  ------------------
  |  |  123|      0|    RAPIDJSON_MULTILINEMACRO_END
  |  |  ------------------
  |  |  |  |  517|      0|#define RAPIDJSON_MULTILINEMACRO_END \
  |  |  |  |  518|      0|} while((void)0, 0)
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (518:9): [Folded, False: 0]
  |  |  |  |  ------------------
  |  |  ------------------
  ------------------
  |  Branch (792:21): [True: 0, False: 0]
  ------------------
  793|  11.5k|            }
  794|       |
  795|  8.01k|            if (parseFlags & kParseTrailingCommasFlag) {
  ------------------
  |  Branch (795:17): [Folded, False: 8.01k]
  ------------------
  796|      0|                if (is.Peek() == '}') {
  ------------------
  |  Branch (796:21): [True: 0, False: 0]
  ------------------
  797|      0|                    if (RAPIDJSON_UNLIKELY(!handler.EndObject(memberCount)))
  ------------------
  |  |  505|      0|#define RAPIDJSON_UNLIKELY(x) __builtin_expect(!!(x), 0)
  |  |  ------------------
  |  |  |  Branch (505:31): [True: 0, False: 0]
  |  |  ------------------
  ------------------
  798|      0|                        RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell());
  ------------------
  |  |  120|      0|    RAPIDJSON_MULTILINEMACRO_BEGIN \
  |  |  ------------------
  |  |  |  |  516|      0|#define RAPIDJSON_MULTILINEMACRO_BEGIN do {
  |  |  ------------------
  |  |  121|      0|    RAPIDJSON_PARSE_ERROR_NORETURN(parseErrorCode, offset); \
  |  |  ------------------
  |  |  |  |  101|      0|    RAPIDJSON_MULTILINEMACRO_BEGIN \
  |  |  |  |  ------------------
  |  |  |  |  |  |  516|      0|#define RAPIDJSON_MULTILINEMACRO_BEGIN do {
  |  |  |  |  ------------------
  |  |  |  |  102|      0|    RAPIDJSON_ASSERT(!HasParseError()); /* Error can only be assigned once */ \
  |  |  |  |  ------------------
  |  |  |  |  |  |  437|      0|#define RAPIDJSON_ASSERT(x) assert(x)
  |  |  |  |  ------------------
  |  |  |  |  103|      0|    SetParseError(parseErrorCode, offset); \
  |  |  |  |  104|      0|    RAPIDJSON_MULTILINEMACRO_END
  |  |  |  |  ------------------
  |  |  |  |  |  |  517|      0|#define RAPIDJSON_MULTILINEMACRO_END \
  |  |  |  |  |  |  518|      0|} while((void)0, 0)
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  Branch (518:9): [Folded, False: 0]
  |  |  |  |  |  |  ------------------
  |  |  |  |  ------------------
  |  |  ------------------
  |  |  122|      0|    RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; \
  |  |  ------------------
  |  |  |  |   66|      0|    RAPIDJSON_PARSE_ERROR_EARLY_RETURN(RAPIDJSON_NOTHING)
  |  |  |  |  ------------------
  |  |  |  |  |  |   61|      0|    RAPIDJSON_MULTILINEMACRO_BEGIN \
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  516|      0|#define RAPIDJSON_MULTILINEMACRO_BEGIN do {
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |   62|      0|    if (RAPIDJSON_UNLIKELY(HasParseError())) { return value; } \
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  505|      0|#define RAPIDJSON_UNLIKELY(x) __builtin_expect(!!(x), 0)
  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  |  Branch (505:31): [True: 0, False: 0]
  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |   63|      0|    RAPIDJSON_MULTILINEMACRO_END
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  517|      0|#define RAPIDJSON_MULTILINEMACRO_END \
  |  |  |  |  |  |  |  |  518|      0|} while((void)0, 0)
  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  |  Branch (518:9): [Folded, False: 0]
  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  ------------------
  |  |  |  |  ------------------
  |  |  ------------------
  |  |  123|      0|    RAPIDJSON_MULTILINEMACRO_END
  |  |  ------------------
  |  |  |  |  517|      0|#define RAPIDJSON_MULTILINEMACRO_END \
  |  |  |  |  518|      0|} while((void)0, 0)
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (518:9): [Folded, False: 0]
  |  |  |  |  ------------------
  |  |  ------------------
  ------------------
  |  Branch (798:25): [True: 0, False: 0]
  ------------------
  799|      0|                    is.Take();
  800|      0|                    return;
  801|      0|                }
  802|      0|            }
  803|  8.01k|        }
  804|  3.55k|    }
_ZN9rapidjson13GenericReaderINS_4UTF8IcEES2_NS_12CrtAllocatorEE10ParseArrayILj1ENS_25GenericInsituStringStreamIS2_EENS_15GenericDocumentIS2_NS_19MemoryPoolAllocatorIS3_EES3_EEEEvRT0_RT1_:
  808|   263k|    void ParseArray(InputStream& is, Handler& handler) {
  809|   263k|        RAPIDJSON_ASSERT(is.Peek() == '[');
  ------------------
  |  |  437|   263k|#define RAPIDJSON_ASSERT(x) assert(x)
  ------------------
  |  Branch (809:9): [True: 263k, False: 0]
  ------------------
  810|   263k|        is.Take();  // Skip '['
  811|       |
  812|   263k|        if (RAPIDJSON_UNLIKELY(!handler.StartArray()))
  ------------------
  |  |  505|   263k|#define RAPIDJSON_UNLIKELY(x) __builtin_expect(!!(x), 0)
  |  |  ------------------
  |  |  |  Branch (505:31): [True: 0, False: 263k]
  |  |  ------------------
  ------------------
  813|   263k|            RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell());
  ------------------
  |  |  120|      0|    RAPIDJSON_MULTILINEMACRO_BEGIN \
  |  |  ------------------
  |  |  |  |  516|      0|#define RAPIDJSON_MULTILINEMACRO_BEGIN do {
  |  |  ------------------
  |  |  121|      0|    RAPIDJSON_PARSE_ERROR_NORETURN(parseErrorCode, offset); \
  |  |  ------------------
  |  |  |  |  101|      0|    RAPIDJSON_MULTILINEMACRO_BEGIN \
  |  |  |  |  ------------------
  |  |  |  |  |  |  516|      0|#define RAPIDJSON_MULTILINEMACRO_BEGIN do {
  |  |  |  |  ------------------
  |  |  |  |  102|      0|    RAPIDJSON_ASSERT(!HasParseError()); /* Error can only be assigned once */ \
  |  |  |  |  ------------------
  |  |  |  |  |  |  437|      0|#define RAPIDJSON_ASSERT(x) assert(x)
  |  |  |  |  ------------------
  |  |  |  |  103|      0|    SetParseError(parseErrorCode, offset); \
  |  |  |  |  104|      0|    RAPIDJSON_MULTILINEMACRO_END
  |  |  |  |  ------------------
  |  |  |  |  |  |  517|      0|#define RAPIDJSON_MULTILINEMACRO_END \
  |  |  |  |  |  |  518|      0|} while((void)0, 0)
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  Branch (518:9): [Folded, False: 0]
  |  |  |  |  |  |  ------------------
  |  |  |  |  ------------------
  |  |  ------------------
  |  |  122|      0|    RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; \
  |  |  ------------------
  |  |  |  |   66|      0|    RAPIDJSON_PARSE_ERROR_EARLY_RETURN(RAPIDJSON_NOTHING)
  |  |  |  |  ------------------
  |  |  |  |  |  |   61|      0|    RAPIDJSON_MULTILINEMACRO_BEGIN \
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  516|      0|#define RAPIDJSON_MULTILINEMACRO_BEGIN do {
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |   62|      0|    if (RAPIDJSON_UNLIKELY(HasParseError())) { return value; } \
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  505|      0|#define RAPIDJSON_UNLIKELY(x) __builtin_expect(!!(x), 0)
  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  |  Branch (505:31): [True: 0, False: 0]
  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |   63|      0|    RAPIDJSON_MULTILINEMACRO_END
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  517|      0|#define RAPIDJSON_MULTILINEMACRO_END \
  |  |  |  |  |  |  |  |  518|      0|} while((void)0, 0)
  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  |  Branch (518:9): [Folded, False: 0]
  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  ------------------
  |  |  |  |  ------------------
  |  |  ------------------
  |  |  123|      0|    RAPIDJSON_MULTILINEMACRO_END
  |  |  ------------------
  |  |  |  |  517|      0|#define RAPIDJSON_MULTILINEMACRO_END \
  |  |  |  |  518|      0|} while((void)0, 0)
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (518:9): [Folded, False: 0]
  |  |  |  |  ------------------
  |  |  ------------------
  ------------------
  |  Branch (813:13): [True: 0, False: 0]
  ------------------
  814|       |
  815|   263k|        SkipWhitespaceAndComments<parseFlags>(is);
  816|   263k|        RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
  ------------------
  |  |   66|   263k|    RAPIDJSON_PARSE_ERROR_EARLY_RETURN(RAPIDJSON_NOTHING)
  |  |  ------------------
  |  |  |  |   61|   263k|    RAPIDJSON_MULTILINEMACRO_BEGIN \
  |  |  |  |  ------------------
  |  |  |  |  |  |  516|   263k|#define RAPIDJSON_MULTILINEMACRO_BEGIN do {
  |  |  |  |  ------------------
  |  |  |  |   62|   263k|    if (RAPIDJSON_UNLIKELY(HasParseError())) { return value; } \
  |  |  |  |  ------------------
  |  |  |  |  |  |  505|   263k|#define RAPIDJSON_UNLIKELY(x) __builtin_expect(!!(x), 0)
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  Branch (505:31): [True: 0, False: 263k]
  |  |  |  |  |  |  ------------------
  |  |  |  |  ------------------
  |  |  |  |   63|   263k|    RAPIDJSON_MULTILINEMACRO_END
  |  |  |  |  ------------------
  |  |  |  |  |  |  517|   263k|#define RAPIDJSON_MULTILINEMACRO_END \
  |  |  |  |  |  |  518|   263k|} while((void)0, 0)
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  Branch (518:9): [Folded, False: 263k]
  |  |  |  |  |  |  ------------------
  |  |  |  |  ------------------
  |  |  ------------------
  ------------------
  817|       |
  818|   263k|        if (Consume(is, ']')) {
  ------------------
  |  Branch (818:13): [True: 16, False: 263k]
  ------------------
  819|     16|            if (RAPIDJSON_UNLIKELY(!handler.EndArray(0))) // empty array
  ------------------
  |  |  505|     16|#define RAPIDJSON_UNLIKELY(x) __builtin_expect(!!(x), 0)
  |  |  ------------------
  |  |  |  Branch (505:31): [True: 0, False: 16]
  |  |  ------------------
  ------------------
  820|     16|                RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell());
  ------------------
  |  |  120|      0|    RAPIDJSON_MULTILINEMACRO_BEGIN \
  |  |  ------------------
  |  |  |  |  516|      0|#define RAPIDJSON_MULTILINEMACRO_BEGIN do {
  |  |  ------------------
  |  |  121|      0|    RAPIDJSON_PARSE_ERROR_NORETURN(parseErrorCode, offset); \
  |  |  ------------------
  |  |  |  |  101|      0|    RAPIDJSON_MULTILINEMACRO_BEGIN \
  |  |  |  |  ------------------
  |  |  |  |  |  |  516|      0|#define RAPIDJSON_MULTILINEMACRO_BEGIN do {
  |  |  |  |  ------------------
  |  |  |  |  102|      0|    RAPIDJSON_ASSERT(!HasParseError()); /* Error can only be assigned once */ \
  |  |  |  |  ------------------
  |  |  |  |  |  |  437|      0|#define RAPIDJSON_ASSERT(x) assert(x)
  |  |  |  |  ------------------
  |  |  |  |  103|      0|    SetParseError(parseErrorCode, offset); \
  |  |  |  |  104|      0|    RAPIDJSON_MULTILINEMACRO_END
  |  |  |  |  ------------------
  |  |  |  |  |  |  517|      0|#define RAPIDJSON_MULTILINEMACRO_END \
  |  |  |  |  |  |  518|      0|} while((void)0, 0)
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  Branch (518:9): [Folded, False: 0]
  |  |  |  |  |  |  ------------------
  |  |  |  |  ------------------
  |  |  ------------------
  |  |  122|      0|    RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; \
  |  |  ------------------
  |  |  |  |   66|      0|    RAPIDJSON_PARSE_ERROR_EARLY_RETURN(RAPIDJSON_NOTHING)
  |  |  |  |  ------------------
  |  |  |  |  |  |   61|      0|    RAPIDJSON_MULTILINEMACRO_BEGIN \
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  516|      0|#define RAPIDJSON_MULTILINEMACRO_BEGIN do {
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |   62|      0|    if (RAPIDJSON_UNLIKELY(HasParseError())) { return value; } \
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  505|      0|#define RAPIDJSON_UNLIKELY(x) __builtin_expect(!!(x), 0)
  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  |  Branch (505:31): [True: 0, False: 0]
  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |   63|      0|    RAPIDJSON_MULTILINEMACRO_END
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  517|      0|#define RAPIDJSON_MULTILINEMACRO_END \
  |  |  |  |  |  |  |  |  518|      0|} while((void)0, 0)
  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  |  Branch (518:9): [Folded, False: 0]
  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  ------------------
  |  |  |  |  ------------------
  |  |  ------------------
  |  |  123|      0|    RAPIDJSON_MULTILINEMACRO_END
  |  |  ------------------
  |  |  |  |  517|      0|#define RAPIDJSON_MULTILINEMACRO_END \
  |  |  |  |  518|      0|} while((void)0, 0)
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (518:9): [Folded, False: 0]
  |  |  |  |  ------------------
  |  |  ------------------
  ------------------
  |  Branch (820:17): [True: 0, False: 0]
  ------------------
  821|     16|            return;
  822|     16|        }
  823|       |
  824|  1.08M|        for (SizeType elementCount = 0;;) {
  825|  1.08M|            ParseValue<parseFlags>(is, handler);
  826|  1.08M|            RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
  ------------------
  |  |   66|  1.08M|    RAPIDJSON_PARSE_ERROR_EARLY_RETURN(RAPIDJSON_NOTHING)
  |  |  ------------------
  |  |  |  |   61|  1.08M|    RAPIDJSON_MULTILINEMACRO_BEGIN \
  |  |  |  |  ------------------
  |  |  |  |  |  |  516|  1.08M|#define RAPIDJSON_MULTILINEMACRO_BEGIN do {
  |  |  |  |  ------------------
  |  |  |  |   62|  1.08M|    if (RAPIDJSON_UNLIKELY(HasParseError())) { return value; } \
  |  |  |  |  ------------------
  |  |  |  |  |  |  505|  1.08M|#define RAPIDJSON_UNLIKELY(x) __builtin_expect(!!(x), 0)
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  Branch (505:31): [True: 261k, False: 825k]
  |  |  |  |  |  |  ------------------
  |  |  |  |  ------------------
  |  |  |  |   63|  1.08M|    RAPIDJSON_MULTILINEMACRO_END
  |  |  |  |  ------------------
  |  |  |  |  |  |  517|  1.08M|#define RAPIDJSON_MULTILINEMACRO_END \
  |  |  |  |  |  |  518|  1.08M|} while((void)0, 0)
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  Branch (518:9): [Folded, False: 825k]
  |  |  |  |  |  |  ------------------
  |  |  |  |  ------------------
  |  |  ------------------
  ------------------
  827|       |
  828|   825k|            ++elementCount;
  829|   825k|            SkipWhitespaceAndComments<parseFlags>(is);
  830|   825k|            RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
  ------------------
  |  |   66|   825k|    RAPIDJSON_PARSE_ERROR_EARLY_RETURN(RAPIDJSON_NOTHING)
  |  |  ------------------
  |  |  |  |   61|   825k|    RAPIDJSON_MULTILINEMACRO_BEGIN \
  |  |  |  |  ------------------
  |  |  |  |  |  |  516|   825k|#define RAPIDJSON_MULTILINEMACRO_BEGIN do {
  |  |  |  |  ------------------
  |  |  |  |   62|   825k|    if (RAPIDJSON_UNLIKELY(HasParseError())) { return value; } \
  |  |  |  |  ------------------
  |  |  |  |  |  |  505|   825k|#define RAPIDJSON_UNLIKELY(x) __builtin_expect(!!(x), 0)
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  Branch (505:31): [True: 0, False: 825k]
  |  |  |  |  |  |  ------------------
  |  |  |  |  ------------------
  |  |  |  |   63|   825k|    RAPIDJSON_MULTILINEMACRO_END
  |  |  |  |  ------------------
  |  |  |  |  |  |  517|   825k|#define RAPIDJSON_MULTILINEMACRO_END \
  |  |  |  |  |  |  518|   825k|} while((void)0, 0)
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  Branch (518:9): [Folded, False: 825k]
  |  |  |  |  |  |  ------------------
  |  |  |  |  ------------------
  |  |  ------------------
  ------------------
  831|       |
  832|   825k|            if (Consume(is, ',')) {
  ------------------
  |  Branch (832:17): [True: 822k, False: 2.28k]
  ------------------
  833|   822k|                SkipWhitespaceAndComments<parseFlags>(is);
  834|   822k|                RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
  ------------------
  |  |   66|   822k|    RAPIDJSON_PARSE_ERROR_EARLY_RETURN(RAPIDJSON_NOTHING)
  |  |  ------------------
  |  |  |  |   61|   822k|    RAPIDJSON_MULTILINEMACRO_BEGIN \
  |  |  |  |  ------------------
  |  |  |  |  |  |  516|   822k|#define RAPIDJSON_MULTILINEMACRO_BEGIN do {
  |  |  |  |  ------------------
  |  |  |  |   62|   822k|    if (RAPIDJSON_UNLIKELY(HasParseError())) { return value; } \
  |  |  |  |  ------------------
  |  |  |  |  |  |  505|   822k|#define RAPIDJSON_UNLIKELY(x) __builtin_expect(!!(x), 0)
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  Branch (505:31): [True: 0, False: 822k]
  |  |  |  |  |  |  ------------------
  |  |  |  |  ------------------
  |  |  |  |   63|   822k|    RAPIDJSON_MULTILINEMACRO_END
  |  |  |  |  ------------------
  |  |  |  |  |  |  517|   822k|#define RAPIDJSON_MULTILINEMACRO_END \
  |  |  |  |  |  |  518|   822k|} while((void)0, 0)
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  Branch (518:9): [Folded, False: 822k]
  |  |  |  |  |  |  ------------------
  |  |  |  |  ------------------
  |  |  ------------------
  ------------------
  835|   822k|            }
  836|  2.28k|            else if (Consume(is, ']')) {
  ------------------
  |  Branch (836:22): [True: 2.28k, False: 6]
  ------------------
  837|  2.28k|                if (RAPIDJSON_UNLIKELY(!handler.EndArray(elementCount)))
  ------------------
  |  |  505|  2.28k|#define RAPIDJSON_UNLIKELY(x) __builtin_expect(!!(x), 0)
  |  |  ------------------
  |  |  |  Branch (505:31): [True: 0, False: 2.28k]
  |  |  ------------------
  ------------------
  838|  2.28k|                    RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell());
  ------------------
  |  |  120|      0|    RAPIDJSON_MULTILINEMACRO_BEGIN \
  |  |  ------------------
  |  |  |  |  516|      0|#define RAPIDJSON_MULTILINEMACRO_BEGIN do {
  |  |  ------------------
  |  |  121|      0|    RAPIDJSON_PARSE_ERROR_NORETURN(parseErrorCode, offset); \
  |  |  ------------------
  |  |  |  |  101|      0|    RAPIDJSON_MULTILINEMACRO_BEGIN \
  |  |  |  |  ------------------
  |  |  |  |  |  |  516|      0|#define RAPIDJSON_MULTILINEMACRO_BEGIN do {
  |  |  |  |  ------------------
  |  |  |  |  102|      0|    RAPIDJSON_ASSERT(!HasParseError()); /* Error can only be assigned once */ \
  |  |  |  |  ------------------
  |  |  |  |  |  |  437|      0|#define RAPIDJSON_ASSERT(x) assert(x)
  |  |  |  |  ------------------
  |  |  |  |  103|      0|    SetParseError(parseErrorCode, offset); \
  |  |  |  |  104|      0|    RAPIDJSON_MULTILINEMACRO_END
  |  |  |  |  ------------------
  |  |  |  |  |  |  517|      0|#define RAPIDJSON_MULTILINEMACRO_END \
  |  |  |  |  |  |  518|      0|} while((void)0, 0)
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  Branch (518:9): [Folded, False: 0]
  |  |  |  |  |  |  ------------------
  |  |  |  |  ------------------
  |  |  ------------------
  |  |  122|      0|    RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; \
  |  |  ------------------
  |  |  |  |   66|      0|    RAPIDJSON_PARSE_ERROR_EARLY_RETURN(RAPIDJSON_NOTHING)
  |  |  |  |  ------------------
  |  |  |  |  |  |   61|      0|    RAPIDJSON_MULTILINEMACRO_BEGIN \
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  516|      0|#define RAPIDJSON_MULTILINEMACRO_BEGIN do {
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |   62|      0|    if (RAPIDJSON_UNLIKELY(HasParseError())) { return value; } \
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  505|      0|#define RAPIDJSON_UNLIKELY(x) __builtin_expect(!!(x), 0)
  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  |  Branch (505:31): [True: 0, False: 0]
  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |   63|      0|    RAPIDJSON_MULTILINEMACRO_END
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  517|      0|#define RAPIDJSON_MULTILINEMACRO_END \
  |  |  |  |  |  |  |  |  518|      0|} while((void)0, 0)
  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  |  Branch (518:9): [Folded, False: 0]
  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  ------------------
  |  |  |  |  ------------------
  |  |  ------------------
  |  |  123|      0|    RAPIDJSON_MULTILINEMACRO_END
  |  |  ------------------
  |  |  |  |  517|      0|#define RAPIDJSON_MULTILINEMACRO_END \
  |  |  |  |  518|      0|} while((void)0, 0)
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (518:9): [Folded, False: 0]
  |  |  |  |  ------------------
  |  |  ------------------
  ------------------
  |  Branch (838:21): [True: 0, False: 0]
  ------------------
  839|  2.28k|                return;
  840|  2.28k|            }
  841|      6|            else
  842|  2.28k|                RAPIDJSON_PARSE_ERROR(kParseErrorArrayMissCommaOrSquareBracket, is.Tell());
  ------------------
  |  |  120|     12|    RAPIDJSON_MULTILINEMACRO_BEGIN \
  |  |  ------------------
  |  |  |  |  516|      6|#define RAPIDJSON_MULTILINEMACRO_BEGIN do {
  |  |  ------------------
  |  |  121|     12|    RAPIDJSON_PARSE_ERROR_NORETURN(parseErrorCode, offset); \
  |  |  ------------------
  |  |  |  |  101|      6|    RAPIDJSON_MULTILINEMACRO_BEGIN \
  |  |  |  |  ------------------
  |  |  |  |  |  |  516|      6|#define RAPIDJSON_MULTILINEMACRO_BEGIN do {
  |  |  |  |  ------------------
  |  |  |  |  102|      6|    RAPIDJSON_ASSERT(!HasParseError()); /* Error can only be assigned once */ \
  |  |  |  |  ------------------
  |  |  |  |  |  |  437|      6|#define RAPIDJSON_ASSERT(x) assert(x)
  |  |  |  |  ------------------
  |  |  |  |  103|      6|    SetParseError(parseErrorCode, offset); \
  |  |  |  |  104|      6|    RAPIDJSON_MULTILINEMACRO_END
  |  |  |  |  ------------------
  |  |  |  |  |  |  517|      6|#define RAPIDJSON_MULTILINEMACRO_END \
  |  |  |  |  |  |  518|      6|} while((void)0, 0)
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  Branch (518:9): [Folded, False: 6]
  |  |  |  |  |  |  ------------------
  |  |  |  |  ------------------
  |  |  ------------------
  |  |  122|     12|    RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; \
  |  |  ------------------
  |  |  |  |   66|      6|    RAPIDJSON_PARSE_ERROR_EARLY_RETURN(RAPIDJSON_NOTHING)
  |  |  |  |  ------------------
  |  |  |  |  |  |   61|     12|    RAPIDJSON_MULTILINEMACRO_BEGIN \
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  516|      6|#define RAPIDJSON_MULTILINEMACRO_BEGIN do {
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |   62|     12|    if (RAPIDJSON_UNLIKELY(HasParseError())) { return value; } \
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  505|      6|#define RAPIDJSON_UNLIKELY(x) __builtin_expect(!!(x), 0)
  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  |  Branch (505:31): [True: 6, False: 0]
  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |   63|     12|    RAPIDJSON_MULTILINEMACRO_END
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  517|      6|#define RAPIDJSON_MULTILINEMACRO_END \
  |  |  |  |  |  |  |  |  518|      6|} while((void)0, 0)
  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  |  Branch (518:9): [Folded, False: 0]
  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  ------------------
  |  |  |  |  ------------------
  |  |  ------------------
  |  |  123|      6|    RAPIDJSON_MULTILINEMACRO_END
  |  |  ------------------
  |  |  |  |  517|      6|#define RAPIDJSON_MULTILINEMACRO_END \
  |  |  |  |  518|      6|} while((void)0, 0)
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (518:9): [Folded, False: 0]
  |  |  |  |  ------------------
  |  |  ------------------
  ------------------
  |  Branch (842:17): [True: 6, False: 0]
  ------------------
  843|       |
  844|   822k|            if (parseFlags & kParseTrailingCommasFlag) {
  ------------------
  |  Branch (844:17): [Folded, False: 822k]
  ------------------
  845|      0|                if (is.Peek() == ']') {
  ------------------
  |  Branch (845:21): [True: 0, False: 0]
  ------------------
  846|      0|                    if (RAPIDJSON_UNLIKELY(!handler.EndArray(elementCount)))
  ------------------
  |  |  505|      0|#define RAPIDJSON_UNLIKELY(x) __builtin_expect(!!(x), 0)
  |  |  ------------------
  |  |  |  Branch (505:31): [True: 0, False: 0]
  |  |  ------------------
  ------------------
  847|      0|                        RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell());
  ------------------
  |  |  120|      0|    RAPIDJSON_MULTILINEMACRO_BEGIN \
  |  |  ------------------
  |  |  |  |  516|      0|#define RAPIDJSON_MULTILINEMACRO_BEGIN do {
  |  |  ------------------
  |  |  121|      0|    RAPIDJSON_PARSE_ERROR_NORETURN(parseErrorCode, offset); \
  |  |  ------------------
  |  |  |  |  101|      0|    RAPIDJSON_MULTILINEMACRO_BEGIN \
  |  |  |  |  ------------------
  |  |  |  |  |  |  516|      0|#define RAPIDJSON_MULTILINEMACRO_BEGIN do {
  |  |  |  |  ------------------
  |  |  |  |  102|      0|    RAPIDJSON_ASSERT(!HasParseError()); /* Error can only be assigned once */ \
  |  |  |  |  ------------------
  |  |  |  |  |  |  437|      0|#define RAPIDJSON_ASSERT(x) assert(x)
  |  |  |  |  ------------------
  |  |  |  |  103|      0|    SetParseError(parseErrorCode, offset); \
  |  |  |  |  104|      0|    RAPIDJSON_MULTILINEMACRO_END
  |  |  |  |  ------------------
  |  |  |  |  |  |  517|      0|#define RAPIDJSON_MULTILINEMACRO_END \
  |  |  |  |  |  |  518|      0|} while((void)0, 0)
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  Branch (518:9): [Folded, False: 0]
  |  |  |  |  |  |  ------------------
  |  |  |  |  ------------------
  |  |  ------------------
  |  |  122|      0|    RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; \
  |  |  ------------------
  |  |  |  |   66|      0|    RAPIDJSON_PARSE_ERROR_EARLY_RETURN(RAPIDJSON_NOTHING)
  |  |  |  |  ------------------
  |  |  |  |  |  |   61|      0|    RAPIDJSON_MULTILINEMACRO_BEGIN \
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  516|      0|#define RAPIDJSON_MULTILINEMACRO_BEGIN do {
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |   62|      0|    if (RAPIDJSON_UNLIKELY(HasParseError())) { return value; } \
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  505|      0|#define RAPIDJSON_UNLIKELY(x) __builtin_expect(!!(x), 0)
  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  |  Branch (505:31): [True: 0, False: 0]
  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |   63|      0|    RAPIDJSON_MULTILINEMACRO_END
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  517|      0|#define RAPIDJSON_MULTILINEMACRO_END \
  |  |  |  |  |  |  |  |  518|      0|} while((void)0, 0)
  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  |  Branch (518:9): [Folded, False: 0]
  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  ------------------
  |  |  |  |  ------------------
  |  |  ------------------
  |  |  123|      0|    RAPIDJSON_MULTILINEMACRO_END
  |  |  ------------------
  |  |  |  |  517|      0|#define RAPIDJSON_MULTILINEMACRO_END \
  |  |  |  |  518|      0|} while((void)0, 0)
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (518:9): [Folded, False: 0]
  |  |  |  |  ------------------
  |  |  ------------------
  ------------------
  |  Branch (847:25): [True: 0, False: 0]
  ------------------
  848|      0|                    is.Take();
  849|      0|                    return;
  850|      0|                }
  851|      0|            }
  852|   822k|        }
  853|   263k|    }
_ZN9rapidjson13GenericReaderINS_4UTF8IcEES2_NS_12CrtAllocatorEE11ParseNumberILj1ENS_25GenericInsituStringStreamIS2_EENS_15GenericDocumentIS2_NS_19MemoryPoolAllocatorIS3_EES3_EEEEvRT0_RT1_:
 1468|   828k|    void ParseNumber(InputStream& is, Handler& handler) {
 1469|   828k|        typedef typename internal::SelectIf<internal::BoolType<(parseFlags & kParseNumbersAsStringsFlag) != 0>, typename TargetEncoding::Ch, char>::Type NumberCharacter;
 1470|       |
 1471|   828k|        internal::StreamLocalCopy<InputStream> copy(is);
 1472|   828k|        NumberStream<InputStream, NumberCharacter,
 1473|   828k|            ((parseFlags & kParseNumbersAsStringsFlag) != 0) ?
 1474|   828k|                ((parseFlags & kParseInsituFlag) == 0) :
 1475|   828k|                ((parseFlags & kParseFullPrecisionFlag) != 0),
 1476|   828k|            (parseFlags & kParseNumbersAsStringsFlag) != 0 &&
 1477|   828k|                (parseFlags & kParseInsituFlag) == 0> s(*this, copy.s);
 1478|       |
 1479|   828k|        size_t startOffset = s.Tell();
 1480|   828k|        double d = 0.0;
 1481|   828k|        bool useNanOrInf = false;
 1482|       |
 1483|       |        // Parse minus
 1484|   828k|        bool minus = Consume(s, '-');
 1485|       |
 1486|       |        // Parse int: zero / ( digit1-9 *DIGIT )
 1487|   828k|        unsigned i = 0;
 1488|   828k|        uint64_t i64 = 0;
 1489|   828k|        bool use64bit = false;
 1490|   828k|        int significandDigit = 0;
 1491|   828k|        if (RAPIDJSON_UNLIKELY(s.Peek() == '0')) {
  ------------------
  |  |  505|   828k|#define RAPIDJSON_UNLIKELY(x) __builtin_expect(!!(x), 0)
  |  |  ------------------
  |  |  |  Branch (505:31): [True: 6.62k, False: 822k]
  |  |  ------------------
  ------------------
 1492|  6.62k|            i = 0;
 1493|  6.62k|            s.TakePush();
 1494|  6.62k|        }
 1495|   822k|        else if (RAPIDJSON_LIKELY(s.Peek() >= '1' && s.Peek() <= '9')) {
  ------------------
  |  |  492|  1.64M|#define RAPIDJSON_LIKELY(x) __builtin_expect(!!(x), 1)
  |  |  ------------------
  |  |  |  Branch (492:29): [True: 822k, False: 60]
  |  |  |  Branch (492:49): [True: 822k, False: 22]
  |  |  |  Branch (492:49): [True: 822k, False: 38]
  |  |  ------------------
  ------------------
 1496|   822k|            i = static_cast<unsigned>(s.TakePush() - '0');
 1497|       |
 1498|   822k|            if (minus)
  ------------------
  |  Branch (1498:17): [True: 1.35k, False: 820k]
  ------------------
 1499|  2.20k|                while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) {
  ------------------
  |  |  492|  3.06k|#define RAPIDJSON_LIKELY(x) __builtin_expect(!!(x), 1)
  |  |  ------------------
  |  |  |  Branch (492:29): [True: 861, False: 1.34k]
  |  |  |  Branch (492:49): [True: 862, False: 1.33k]
  |  |  |  Branch (492:49): [True: 861, False: 1]
  |  |  ------------------
  ------------------
 1500|    861|                    if (RAPIDJSON_UNLIKELY(i >= 214748364)) { // 2^31 = 2147483648
  ------------------
  |  |  505|    861|#define RAPIDJSON_UNLIKELY(x) __builtin_expect(!!(x), 0)
  |  |  ------------------
  |  |  |  Branch (505:31): [True: 14, False: 847]
  |  |  ------------------
  ------------------
 1501|     14|                        if (RAPIDJSON_LIKELY(i != 214748364 || s.Peek() > '8')) {
  ------------------
  |  |  492|     14|#define RAPIDJSON_LIKELY(x) __builtin_expect(!!(x), 1)
  |  |  ------------------
  |  |  |  Branch (492:29): [True: 14, False: 0]
  |  |  |  Branch (492:49): [True: 14, False: 0]
  |  |  |  Branch (492:49): [True: 0, False: 0]
  |  |  ------------------
  ------------------
 1502|     14|                            i64 = i;
 1503|     14|                            use64bit = true;
 1504|     14|                            break;
 1505|     14|                        }
 1506|     14|                    }
 1507|    847|                    i = i * 10 + static_cast<unsigned>(s.TakePush() - '0');
 1508|    847|                    significandDigit++;
 1509|    847|                }
 1510|   820k|            else
 1511|   955k|                while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) {
  ------------------
  |  |  492|  1.09M|#define RAPIDJSON_LIKELY(x) __builtin_expect(!!(x), 1)
  |  |  ------------------
  |  |  |  Branch (492:29): [True: 142k, False: 813k]
  |  |  |  Branch (492:49): [True: 142k, False: 813k]
  |  |  |  Branch (492:49): [True: 142k, False: 28]
  |  |  ------------------
  ------------------
 1512|   142k|                    if (RAPIDJSON_UNLIKELY(i >= 429496729)) { // 2^32 - 1 = 4294967295
  ------------------
  |  |  505|   142k|#define RAPIDJSON_UNLIKELY(x) __builtin_expect(!!(x), 0)
  |  |  ------------------
  |  |  |  Branch (505:31): [True: 8.01k, False: 134k]
  |  |  ------------------
  ------------------
 1513|  8.01k|                        if (RAPIDJSON_LIKELY(i != 429496729 || s.Peek() > '5')) {
  ------------------
  |  |  492|  8.97k|#define RAPIDJSON_LIKELY(x) __builtin_expect(!!(x), 1)
  |  |  ------------------
  |  |  |  Branch (492:29): [True: 7.07k, False: 946]
  |  |  |  Branch (492:49): [True: 7.06k, False: 956]
  |  |  |  Branch (492:49): [True: 10, False: 946]
  |  |  ------------------
  ------------------
 1514|  7.07k|                            i64 = i;
 1515|  7.07k|                            use64bit = true;
 1516|  7.07k|                            break;
 1517|  7.07k|                        }
 1518|  8.01k|                    }
 1519|   135k|                    i = i * 10 + static_cast<unsigned>(s.TakePush() - '0');
 1520|   135k|                    significandDigit++;
 1521|   135k|                }
 1522|   822k|        }
 1523|       |        // Parse NaN or Infinity here
 1524|     60|        else if ((parseFlags & kParseNanAndInfFlag) && RAPIDJSON_LIKELY((s.Peek() == 'I' || s.Peek() == 'N'))) {
  ------------------
  |  |  492|      0|#define RAPIDJSON_LIKELY(x) __builtin_expect(!!(x), 1)
  |  |  ------------------
  |  |  |  Branch (492:29): [True: 0, False: 0]
  |  |  |  Branch (492:49): [True: 0, False: 0]
  |  |  |  Branch (492:49): [True: 0, False: 0]
  |  |  ------------------
  ------------------
  |  Branch (1524:18): [Folded, False: 60]
  ------------------
 1525|      0|            if (Consume(s, 'N')) {
  ------------------
  |  Branch (1525:17): [True: 0, False: 0]
  ------------------
 1526|      0|                if (Consume(s, 'a') && Consume(s, 'N')) {
  ------------------
  |  Branch (1526:21): [True: 0, False: 0]
  |  Branch (1526:40): [True: 0, False: 0]
  ------------------
 1527|      0|                    d = std::numeric_limits<double>::quiet_NaN();
 1528|      0|                    useNanOrInf = true;
 1529|      0|                }
 1530|      0|            }
 1531|      0|            else if (RAPIDJSON_LIKELY(Consume(s, 'I'))) {
  ------------------
  |  |  492|      0|#define RAPIDJSON_LIKELY(x) __builtin_expect(!!(x), 1)
  |  |  ------------------
  |  |  |  Branch (492:29): [True: 0, False: 0]
  |  |  ------------------
  ------------------
 1532|      0|                if (Consume(s, 'n') && Consume(s, 'f')) {
  ------------------
  |  Branch (1532:21): [True: 0, False: 0]
  |  Branch (1532:40): [True: 0, False: 0]
  ------------------
 1533|      0|                    d = (minus ? -std::numeric_limits<double>::infinity() : std::numeric_limits<double>::infinity());
  ------------------
  |  Branch (1533:26): [True: 0, False: 0]
  ------------------
 1534|      0|                    useNanOrInf = true;
 1535|       |
 1536|      0|                    if (RAPIDJSON_UNLIKELY(s.Peek() == 'i' && !(Consume(s, 'i') && Consume(s, 'n')
  ------------------
  |  |  505|      0|#define RAPIDJSON_UNLIKELY(x) __builtin_expect(!!(x), 0)
  |  |  ------------------
  |  |  |  Branch (505:31): [True: 0, False: 0]
  |  |  |  Branch (505:51): [True: 0, False: 0]
  |  |  |  Branch (505:51): [True: 0, False: 0]
  |  |  |  Branch (505:51): [True: 0, False: 0]
  |  |  |  Branch (505:51): [True: 0, False: 0]
  |  |  |  Branch (505:51): [True: 0, False: 0]
  |  |  |  Branch (505:51): [True: 0, False: 0]
  |  |  ------------------
  ------------------
 1537|      0|                                                                && Consume(s, 'i') && Consume(s, 't') && Consume(s, 'y')))) {
 1538|      0|                        RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, s.Tell());
  ------------------
  |  |  120|      0|    RAPIDJSON_MULTILINEMACRO_BEGIN \
  |  |  ------------------
  |  |  |  |  516|      0|#define RAPIDJSON_MULTILINEMACRO_BEGIN do {
  |  |  ------------------
  |  |  121|      0|    RAPIDJSON_PARSE_ERROR_NORETURN(parseErrorCode, offset); \
  |  |  ------------------
  |  |  |  |  101|      0|    RAPIDJSON_MULTILINEMACRO_BEGIN \
  |  |  |  |  ------------------
  |  |  |  |  |  |  516|      0|#define RAPIDJSON_MULTILINEMACRO_BEGIN do {
  |  |  |  |  ------------------
  |  |  |  |  102|      0|    RAPIDJSON_ASSERT(!HasParseError()); /* Error can only be assigned once */ \
  |  |  |  |  ------------------
  |  |  |  |  |  |  437|      0|#define RAPIDJSON_ASSERT(x) assert(x)
  |  |  |  |  ------------------
  |  |  |  |  103|      0|    SetParseError(parseErrorCode, offset); \
  |  |  |  |  104|      0|    RAPIDJSON_MULTILINEMACRO_END
  |  |  |  |  ------------------
  |  |  |  |  |  |  517|      0|#define RAPIDJSON_MULTILINEMACRO_END \
  |  |  |  |  |  |  518|      0|} while((void)0, 0)
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  Branch (518:9): [Folded, False: 0]
  |  |  |  |  |  |  ------------------
  |  |  |  |  ------------------
  |  |  ------------------
  |  |  122|      0|    RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; \
  |  |  ------------------
  |  |  |  |   66|      0|    RAPIDJSON_PARSE_ERROR_EARLY_RETURN(RAPIDJSON_NOTHING)
  |  |  |  |  ------------------
  |  |  |  |  |  |   61|      0|    RAPIDJSON_MULTILINEMACRO_BEGIN \
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  516|      0|#define RAPIDJSON_MULTILINEMACRO_BEGIN do {
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |   62|      0|    if (RAPIDJSON_UNLIKELY(HasParseError())) { return value; } \
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  505|      0|#define RAPIDJSON_UNLIKELY(x) __builtin_expect(!!(x), 0)
  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  |  Branch (505:31): [True: 0, False: 0]
  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |   63|      0|    RAPIDJSON_MULTILINEMACRO_END
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  517|      0|#define RAPIDJSON_MULTILINEMACRO_END \
  |  |  |  |  |  |  |  |  518|      0|} while((void)0, 0)
  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  |  Branch (518:9): [Folded, False: 0]
  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  ------------------
  |  |  |  |  ------------------
  |  |  ------------------
  |  |  123|      0|    RAPIDJSON_MULTILINEMACRO_END
  |  |  ------------------
  |  |  |  |  517|      0|#define RAPIDJSON_MULTILINEMACRO_END \
  |  |  |  |  518|      0|} while((void)0, 0)
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (518:9): [Folded, False: 0]
  |  |  |  |  ------------------
  |  |  ------------------
  ------------------
  |  Branch (1538:25): [True: 0, False: 0]
  ------------------
 1539|      0|                    }
 1540|      0|                }
 1541|      0|            }
 1542|       |
 1543|      0|            if (RAPIDJSON_UNLIKELY(!useNanOrInf)) {
  ------------------
  |  |  505|      0|#define RAPIDJSON_UNLIKELY(x) __builtin_expect(!!(x), 0)
  |  |  ------------------
  |  |  |  Branch (505:31): [True: 0, False: 0]
  |  |  ------------------
  ------------------
 1544|      0|                RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, s.Tell());
  ------------------
  |  |  120|      0|    RAPIDJSON_MULTILINEMACRO_BEGIN \
  |  |  ------------------
  |  |  |  |  516|      0|#define RAPIDJSON_MULTILINEMACRO_BEGIN do {
  |  |  ------------------
  |  |  121|      0|    RAPIDJSON_PARSE_ERROR_NORETURN(parseErrorCode, offset); \
  |  |  ------------------
  |  |  |  |  101|      0|    RAPIDJSON_MULTILINEMACRO_BEGIN \
  |  |  |  |  ------------------
  |  |  |  |  |  |  516|      0|#define RAPIDJSON_MULTILINEMACRO_BEGIN do {
  |  |  |  |  ------------------
  |  |  |  |  102|      0|    RAPIDJSON_ASSERT(!HasParseError()); /* Error can only be assigned once */ \
  |  |  |  |  ------------------
  |  |  |  |  |  |  437|      0|#define RAPIDJSON_ASSERT(x) assert(x)
  |  |  |  |  ------------------
  |  |  |  |  103|      0|    SetParseError(parseErrorCode, offset); \
  |  |  |  |  104|      0|    RAPIDJSON_MULTILINEMACRO_END
  |  |  |  |  ------------------
  |  |  |  |  |  |  517|      0|#define RAPIDJSON_MULTILINEMACRO_END \
  |  |  |  |  |  |  518|      0|} while((void)0, 0)
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  Branch (518:9): [Folded, False: 0]
  |  |  |  |  |  |  ------------------
  |  |  |  |  ------------------
  |  |  ------------------
  |  |  122|      0|    RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; \
  |  |  ------------------
  |  |  |  |   66|      0|    RAPIDJSON_PARSE_ERROR_EARLY_RETURN(RAPIDJSON_NOTHING)
  |  |  |  |  ------------------
  |  |  |  |  |  |   61|      0|    RAPIDJSON_MULTILINEMACRO_BEGIN \
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  516|      0|#define RAPIDJSON_MULTILINEMACRO_BEGIN do {
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |   62|      0|    if (RAPIDJSON_UNLIKELY(HasParseError())) { return value; } \
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  505|      0|#define RAPIDJSON_UNLIKELY(x) __builtin_expect(!!(x), 0)
  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  |  Branch (505:31): [True: 0, False: 0]
  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |   63|      0|    RAPIDJSON_MULTILINEMACRO_END
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  517|      0|#define RAPIDJSON_MULTILINEMACRO_END \
  |  |  |  |  |  |  |  |  518|      0|} while((void)0, 0)
  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  |  Branch (518:9): [Folded, False: 0]
  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  ------------------
  |  |  |  |  ------------------
  |  |  ------------------
  |  |  123|      0|    RAPIDJSON_MULTILINEMACRO_END
  |  |  ------------------
  |  |  |  |  517|      0|#define RAPIDJSON_MULTILINEMACRO_END \
  |  |  |  |  518|      0|} while((void)0, 0)
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (518:9): [Folded, False: 0]
  |  |  |  |  ------------------
  |  |  ------------------
  ------------------
  |  Branch (1544:17): [True: 0, False: 0]
  ------------------
 1545|      0|            }
 1546|      0|        }
 1547|     60|        else
 1548|     60|            RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, s.Tell());
  ------------------
  |  |  120|    120|    RAPIDJSON_MULTILINEMACRO_BEGIN \
  |  |  ------------------
  |  |  |  |  516|     60|#define RAPIDJSON_MULTILINEMACRO_BEGIN do {
  |  |  ------------------
  |  |  121|    120|    RAPIDJSON_PARSE_ERROR_NORETURN(parseErrorCode, offset); \
  |  |  ------------------
  |  |  |  |  101|     60|    RAPIDJSON_MULTILINEMACRO_BEGIN \
  |  |  |  |  ------------------
  |  |  |  |  |  |  516|     60|#define RAPIDJSON_MULTILINEMACRO_BEGIN do {
  |  |  |  |  ------------------
  |  |  |  |  102|     60|    RAPIDJSON_ASSERT(!HasParseError()); /* Error can only be assigned once */ \
  |  |  |  |  ------------------
  |  |  |  |  |  |  437|     60|#define RAPIDJSON_ASSERT(x) assert(x)
  |  |  |  |  ------------------
  |  |  |  |  103|     60|    SetParseError(parseErrorCode, offset); \
  |  |  |  |  104|     60|    RAPIDJSON_MULTILINEMACRO_END
  |  |  |  |  ------------------
  |  |  |  |  |  |  517|     60|#define RAPIDJSON_MULTILINEMACRO_END \
  |  |  |  |  |  |  518|     60|} while((void)0, 0)
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  Branch (518:9): [Folded, False: 60]
  |  |  |  |  |  |  ------------------
  |  |  |  |  ------------------
  |  |  ------------------
  |  |  122|    120|    RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; \
  |  |  ------------------
  |  |  |  |   66|     60|    RAPIDJSON_PARSE_ERROR_EARLY_RETURN(RAPIDJSON_NOTHING)
  |  |  |  |  ------------------
  |  |  |  |  |  |   61|    120|    RAPIDJSON_MULTILINEMACRO_BEGIN \
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  516|     60|#define RAPIDJSON_MULTILINEMACRO_BEGIN do {
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |   62|    120|    if (RAPIDJSON_UNLIKELY(HasParseError())) { return value; } \
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  505|     60|#define RAPIDJSON_UNLIKELY(x) __builtin_expect(!!(x), 0)
  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  |  Branch (505:31): [True: 60, False: 0]
  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |   63|    120|    RAPIDJSON_MULTILINEMACRO_END
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  517|     60|#define RAPIDJSON_MULTILINEMACRO_END \
  |  |  |  |  |  |  |  |  518|     60|} while((void)0, 0)
  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  |  Branch (518:9): [Folded, False: 0]
  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  ------------------
  |  |  |  |  ------------------
  |  |  ------------------
  |  |  123|     60|    RAPIDJSON_MULTILINEMACRO_END
  |  |  ------------------
  |  |  |  |  517|     60|#define RAPIDJSON_MULTILINEMACRO_END \
  |  |  |  |  518|     60|} while((void)0, 0)
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (518:9): [Folded, False: 0]
  |  |  |  |  ------------------
  |  |  ------------------
  ------------------
  |  Branch (1548:13): [True: 60, False: 0]
  ------------------
 1549|       |
 1550|       |        // Parse 64bit int
 1551|   828k|        bool useDouble = false;
 1552|   828k|        if (use64bit) {
  ------------------
  |  Branch (1552:13): [True: 7.08k, False: 821k]
  ------------------
 1553|  7.08k|            if (minus)
  ------------------
  |  Branch (1553:17): [True: 14, False: 7.07k]
  ------------------
 1554|    100|                while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) {
  ------------------
  |  |  492|    188|#define RAPIDJSON_LIKELY(x) __builtin_expect(!!(x), 1)
  |  |  ------------------
  |  |  |  Branch (492:29): [True: 88, False: 12]
  |  |  |  Branch (492:49): [True: 88, False: 12]
  |  |  |  Branch (492:49): [True: 88, False: 0]
  |  |  ------------------
  ------------------
 1555|     88|                     if (RAPIDJSON_UNLIKELY(i64 >= RAPIDJSON_UINT64_C2(0x0CCCCCCC, 0xCCCCCCCC))) // 2^63 = 9223372036854775808
  ------------------
  |  |  505|     88|#define RAPIDJSON_UNLIKELY(x) __builtin_expect(!!(x), 0)
  |  |  ------------------
  |  |  |  Branch (505:31): [True: 2, False: 86]
  |  |  ------------------
  ------------------
 1556|      2|                        if (RAPIDJSON_LIKELY(i64 != RAPIDJSON_UINT64_C2(0x0CCCCCCC, 0xCCCCCCCC) || s.Peek() > '8')) {
  ------------------
  |  |  492|      2|#define RAPIDJSON_LIKELY(x) __builtin_expect(!!(x), 1)
  |  |  ------------------
  |  |  |  Branch (492:29): [True: 2, False: 0]
  |  |  |  Branch (492:49): [True: 2, False: 0]
  |  |  |  Branch (492:49): [True: 0, False: 0]
  |  |  ------------------
  ------------------
 1557|      2|                            d = static_cast<double>(i64);
 1558|      2|                            useDouble = true;
 1559|      2|                            break;
 1560|      2|                        }
 1561|     86|                    i64 = i64 * 10 + static_cast<unsigned>(s.TakePush() - '0');
 1562|     86|                    significandDigit++;
 1563|     86|                }
 1564|  7.07k|            else
 1565|  63.5k|                while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) {
  ------------------
  |  |  492|   120k|#define RAPIDJSON_LIKELY(x) __builtin_expect(!!(x), 1)
  |  |  ------------------
  |  |  |  Branch (492:29): [True: 56.5k, False: 7.06k]
  |  |  |  Branch (492:49): [True: 56.5k, False: 7.06k]
  |  |  |  Branch (492:49): [True: 56.5k, False: 0]
  |  |  ------------------
  ------------------
 1566|  56.5k|                    if (RAPIDJSON_UNLIKELY(i64 >= RAPIDJSON_UINT64_C2(0x19999999, 0x99999999))) // 2^64 - 1 = 18446744073709551615
  ------------------
  |  |  505|  56.5k|#define RAPIDJSON_UNLIKELY(x) __builtin_expect(!!(x), 0)
  |  |  ------------------
  |  |  |  Branch (505:31): [True: 9, False: 56.5k]
  |  |  ------------------
  ------------------
 1567|      9|                        if (RAPIDJSON_LIKELY(i64 != RAPIDJSON_UINT64_C2(0x19999999, 0x99999999) || s.Peek() > '5')) {
  ------------------
  |  |  492|      9|#define RAPIDJSON_LIKELY(x) __builtin_expect(!!(x), 1)
  |  |  ------------------
  |  |  |  Branch (492:29): [True: 9, False: 0]
  |  |  |  Branch (492:49): [True: 9, False: 0]
  |  |  |  Branch (492:49): [True: 0, False: 0]
  |  |  ------------------
  ------------------
 1568|      9|                            d = static_cast<double>(i64);
 1569|      9|                            useDouble = true;
 1570|      9|                            break;
 1571|      9|                        }
 1572|  56.5k|                    i64 = i64 * 10 + static_cast<unsigned>(s.TakePush() - '0');
 1573|  56.5k|                    significandDigit++;
 1574|  56.5k|                }
 1575|  7.08k|        }
 1576|       |
 1577|       |        // Force double for big integer
 1578|   828k|        if (useDouble) {
  ------------------
  |  Branch (1578:13): [True: 11, False: 828k]
  ------------------
 1579|     84|            while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) {
  ------------------
  |  |  492|    157|#define RAPIDJSON_LIKELY(x) __builtin_expect(!!(x), 1)
  |  |  ------------------
  |  |  |  Branch (492:29): [True: 73, False: 11]
  |  |  |  Branch (492:49): [True: 73, False: 11]
  |  |  |  Branch (492:49): [True: 73, False: 0]
  |  |  ------------------
  ------------------
 1580|     73|                d = d * 10 + (s.TakePush() - '0');
 1581|     73|            }
 1582|     11|        }
 1583|       |
 1584|       |        // Parse frac = decimal-point 1*DIGIT
 1585|   828k|        int expFrac = 0;
 1586|   828k|        size_t decimalPosition;
 1587|   828k|        if (Consume(s, '.')) {
  ------------------
  |  Branch (1587:13): [True: 6.78k, False: 821k]
  ------------------
 1588|  6.78k|            decimalPosition = s.Length();
 1589|       |
 1590|  6.78k|            if (RAPIDJSON_UNLIKELY(!(s.Peek() >= '0' && s.Peek() <= '9')))
  ------------------
  |  |  505|  13.5k|#define RAPIDJSON_UNLIKELY(x) __builtin_expect(!!(x), 0)
  |  |  ------------------
  |  |  |  Branch (505:31): [True: 0, False: 6.78k]
  |  |  |  Branch (505:51): [True: 6.78k, False: 0]
  |  |  |  Branch (505:51): [True: 6.78k, False: 0]
  |  |  ------------------
  ------------------
 1591|  6.78k|                RAPIDJSON_PARSE_ERROR(kParseErrorNumberMissFraction, s.Tell());
  ------------------
  |  |  120|      0|    RAPIDJSON_MULTILINEMACRO_BEGIN \
  |  |  ------------------
  |  |  |  |  516|      0|#define RAPIDJSON_MULTILINEMACRO_BEGIN do {
  |  |  ------------------
  |  |  121|      0|    RAPIDJSON_PARSE_ERROR_NORETURN(parseErrorCode, offset); \
  |  |  ------------------
  |  |  |  |  101|      0|    RAPIDJSON_MULTILINEMACRO_BEGIN \
  |  |  |  |  ------------------
  |  |  |  |  |  |  516|      0|#define RAPIDJSON_MULTILINEMACRO_BEGIN do {
  |  |  |  |  ------------------
  |  |  |  |  102|      0|    RAPIDJSON_ASSERT(!HasParseError()); /* Error can only be assigned once */ \
  |  |  |  |  ------------------
  |  |  |  |  |  |  437|      0|#define RAPIDJSON_ASSERT(x) assert(x)
  |  |  |  |  ------------------
  |  |  |  |  103|      0|    SetParseError(parseErrorCode, offset); \
  |  |  |  |  104|      0|    RAPIDJSON_MULTILINEMACRO_END
  |  |  |  |  ------------------
  |  |  |  |  |  |  517|      0|#define RAPIDJSON_MULTILINEMACRO_END \
  |  |  |  |  |  |  518|      0|} while((void)0, 0)
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  Branch (518:9): [Folded, False: 0]
  |  |  |  |  |  |  ------------------
  |  |  |  |  ------------------
  |  |  ------------------
  |  |  122|      0|    RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; \
  |  |  ------------------
  |  |  |  |   66|      0|    RAPIDJSON_PARSE_ERROR_EARLY_RETURN(RAPIDJSON_NOTHING)
  |  |  |  |  ------------------
  |  |  |  |  |  |   61|      0|    RAPIDJSON_MULTILINEMACRO_BEGIN \
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  516|      0|#define RAPIDJSON_MULTILINEMACRO_BEGIN do {
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |   62|      0|    if (RAPIDJSON_UNLIKELY(HasParseError())) { return value; } \
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  505|      0|#define RAPIDJSON_UNLIKELY(x) __builtin_expect(!!(x), 0)
  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  |  Branch (505:31): [True: 0, False: 0]
  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |   63|      0|    RAPIDJSON_MULTILINEMACRO_END
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  517|      0|#define RAPIDJSON_MULTILINEMACRO_END \
  |  |  |  |  |  |  |  |  518|      0|} while((void)0, 0)
  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  |  Branch (518:9): [Folded, False: 0]
  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  ------------------
  |  |  |  |  ------------------
  |  |  ------------------
  |  |  123|      0|    RAPIDJSON_MULTILINEMACRO_END
  |  |  ------------------
  |  |  |  |  517|      0|#define RAPIDJSON_MULTILINEMACRO_END \
  |  |  |  |  518|      0|} while((void)0, 0)
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (518:9): [Folded, False: 0]
  |  |  |  |  ------------------
  |  |  ------------------
  ------------------
  |  Branch (1591:17): [True: 0, False: 0]
  ------------------
 1592|       |
 1593|  6.78k|            if (!useDouble) {
  ------------------
  |  Branch (1593:17): [True: 6.77k, False: 3]
  ------------------
 1594|  6.77k|#if RAPIDJSON_64BIT
 1595|       |                // Use i64 to store significand in 64-bit architecture
 1596|  6.77k|                if (!use64bit)
  ------------------
  |  Branch (1596:21): [True: 6.77k, False: 0]
  ------------------
 1597|  6.77k|                    i64 = i;
 1598|       |
 1599|  78.7k|                while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) {
  ------------------
  |  |  492|   151k|#define RAPIDJSON_LIKELY(x) __builtin_expect(!!(x), 1)
  |  |  ------------------
  |  |  |  Branch (492:29): [True: 71.9k, False: 6.77k]
  |  |  |  Branch (492:49): [True: 72.4k, False: 6.24k]
  |  |  |  Branch (492:49): [True: 71.9k, False: 531]
  |  |  ------------------
  ------------------
 1600|  71.9k|                    if (i64 > RAPIDJSON_UINT64_C2(0x1FFFFF, 0xFFFFFFFF)) // 2^53 - 1 for fast path
  ------------------
  |  |  320|  71.9k|#define RAPIDJSON_UINT64_C2(high32, low32) ((static_cast<uint64_t>(high32) << 32) | static_cast<uint64_t>(low32))
  ------------------
  |  Branch (1600:25): [True: 0, False: 71.9k]
  ------------------
 1601|      0|                        break;
 1602|  71.9k|                    else {
 1603|  71.9k|                        i64 = i64 * 10 + static_cast<unsigned>(s.TakePush() - '0');
 1604|  71.9k|                        --expFrac;
 1605|  71.9k|                        if (i64 != 0)
  ------------------
  |  Branch (1605:29): [True: 71.1k, False: 846]
  ------------------
 1606|  71.1k|                            significandDigit++;
 1607|  71.9k|                    }
 1608|  71.9k|                }
 1609|       |
 1610|  6.77k|                d = static_cast<double>(i64);
 1611|       |#else
 1612|       |                // Use double to store significand in 32-bit architecture
 1613|       |                d = static_cast<double>(use64bit ? i64 : i);
 1614|       |#endif
 1615|  6.77k|                useDouble = true;
 1616|  6.77k|            }
 1617|       |
 1618|  6.82k|            while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) {
  ------------------
  |  |  492|  7.41k|#define RAPIDJSON_LIKELY(x) __builtin_expect(!!(x), 1)
  |  |  ------------------
  |  |  |  Branch (492:29): [True: 48, False: 6.78k]
  |  |  |  Branch (492:49): [True: 582, False: 6.24k]
  |  |  |  Branch (492:49): [True: 48, False: 534]
  |  |  ------------------
  ------------------
 1619|     48|                if (significandDigit < 17) {
  ------------------
  |  Branch (1619:21): [True: 0, False: 48]
  ------------------
 1620|      0|                    d = d * 10.0 + (s.TakePush() - '0');
 1621|      0|                    --expFrac;
 1622|      0|                    if (RAPIDJSON_LIKELY(d > 0.0))
  ------------------
  |  |  492|      0|#define RAPIDJSON_LIKELY(x) __builtin_expect(!!(x), 1)
  |  |  ------------------
  |  |  |  Branch (492:29): [True: 0, False: 0]
  |  |  ------------------
  ------------------
 1623|      0|                        significandDigit++;
 1624|      0|                }
 1625|     48|                else
 1626|     48|                    s.TakePush();
 1627|     48|            }
 1628|  6.78k|        }
 1629|   821k|        else
 1630|   821k|            decimalPosition = s.Length(); // decimal position at the end of integer.
 1631|       |
 1632|       |        // Parse exp = e [ minus / plus ] 1*DIGIT
 1633|   828k|        int exp = 0;
 1634|   828k|        if (Consume(s, 'e') || Consume(s, 'E')) {
  ------------------
  |  Branch (1634:13): [True: 532, False: 828k]
  |  Branch (1634:32): [True: 0, False: 828k]
  ------------------
 1635|    532|            if (!useDouble) {
  ------------------
  |  Branch (1635:17): [True: 0, False: 532]
  ------------------
 1636|      0|                d = static_cast<double>(use64bit ? i64 : i);
  ------------------
  |  Branch (1636:41): [True: 0, False: 0]
  ------------------
 1637|      0|                useDouble = true;
 1638|      0|            }
 1639|       |
 1640|    532|            bool expMinus = false;
 1641|    532|            if (Consume(s, '+'))
  ------------------
  |  Branch (1641:17): [True: 0, False: 532]
  ------------------
 1642|      0|                ;
 1643|    532|            else if (Consume(s, '-'))
  ------------------
  |  Branch (1643:22): [True: 532, False: 0]
  ------------------
 1644|    532|                expMinus = true;
 1645|       |
 1646|    532|            if (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) {
  ------------------
  |  |  492|  1.06k|#define RAPIDJSON_LIKELY(x) __builtin_expect(!!(x), 1)
  |  |  ------------------
  |  |  |  Branch (492:29): [True: 532, False: 0]
  |  |  |  Branch (492:49): [True: 532, False: 0]
  |  |  |  Branch (492:49): [True: 532, False: 0]
  |  |  ------------------
  ------------------
 1647|    532|                exp = static_cast<int>(s.Take() - '0');
 1648|    532|                if (expMinus) {
  ------------------
  |  Branch (1648:21): [True: 532, False: 0]
  ------------------
 1649|       |                    // (exp + expFrac) must not underflow int => we're detecting when -exp gets
 1650|       |                    // dangerously close to INT_MIN (a pessimistic next digit 9 would push it into
 1651|       |                    // underflow territory):
 1652|       |                    //
 1653|       |                    //        -(exp * 10 + 9) + expFrac >= INT_MIN
 1654|       |                    //   <=>  exp <= (expFrac - INT_MIN - 9) / 10
 1655|    532|                    RAPIDJSON_ASSERT(expFrac <= 0);
  ------------------
  |  |  437|    532|#define RAPIDJSON_ASSERT(x) assert(x)
  ------------------
  |  Branch (1655:21): [True: 532, False: 0]
  ------------------
 1656|    532|                    int maxExp = (expFrac + 2147483639) / 10;
 1657|       |
 1658|    948|                    while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) {
  ------------------
  |  |  492|  1.36k|#define RAPIDJSON_LIKELY(x) __builtin_expect(!!(x), 1)
  |  |  ------------------
  |  |  |  Branch (492:29): [True: 416, False: 532]
  |  |  |  Branch (492:49): [True: 416, False: 532]
  |  |  |  Branch (492:49): [True: 416, False: 0]
  |  |  ------------------
  ------------------
 1659|    416|                        exp = exp * 10 + static_cast<int>(s.Take() - '0');
 1660|    416|                        if (RAPIDJSON_UNLIKELY(exp > maxExp)) {
  ------------------
  |  |  505|    416|#define RAPIDJSON_UNLIKELY(x) __builtin_expect(!!(x), 0)
  |  |  ------------------
  |  |  |  Branch (505:31): [True: 0, False: 416]
  |  |  ------------------
  ------------------
 1661|      0|                            while (RAPIDJSON_UNLIKELY(s.Peek() >= '0' && s.Peek() <= '9'))  // Consume the rest of exponent
  ------------------
  |  |  505|      0|#define RAPIDJSON_UNLIKELY(x) __builtin_expect(!!(x), 0)
  |  |  ------------------
  |  |  |  Branch (505:31): [True: 0, False: 0]
  |  |  |  Branch (505:51): [True: 0, False: 0]
  |  |  |  Branch (505:51): [True: 0, False: 0]
  |  |  ------------------
  ------------------
 1662|      0|                                s.Take();
 1663|      0|                        }
 1664|    416|                    }
 1665|    532|                }
 1666|      0|                else {  // positive exp
 1667|      0|                    int maxExp = 308 - expFrac;
 1668|      0|                    while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) {
  ------------------
  |  |  492|      0|#define RAPIDJSON_LIKELY(x) __builtin_expect(!!(x), 1)
  |  |  ------------------
  |  |  |  Branch (492:29): [True: 0, False: 0]
  |  |  |  Branch (492:49): [True: 0, False: 0]
  |  |  |  Branch (492:49): [True: 0, False: 0]
  |  |  ------------------
  ------------------
 1669|      0|                        exp = exp * 10 + static_cast<int>(s.Take() - '0');
 1670|      0|                        if (RAPIDJSON_UNLIKELY(exp > maxExp))
  ------------------
  |  |  505|      0|#define RAPIDJSON_UNLIKELY(x) __builtin_expect(!!(x), 0)
  |  |  ------------------
  |  |  |  Branch (505:31): [True: 0, False: 0]
  |  |  ------------------
  ------------------
 1671|      0|                            RAPIDJSON_PARSE_ERROR(kParseErrorNumberTooBig, startOffset);
  ------------------
  |  |  120|      0|    RAPIDJSON_MULTILINEMACRO_BEGIN \
  |  |  ------------------
  |  |  |  |  516|      0|#define RAPIDJSON_MULTILINEMACRO_BEGIN do {
  |  |  ------------------
  |  |  121|      0|    RAPIDJSON_PARSE_ERROR_NORETURN(parseErrorCode, offset); \
  |  |  ------------------
  |  |  |  |  101|      0|    RAPIDJSON_MULTILINEMACRO_BEGIN \
  |  |  |  |  ------------------
  |  |  |  |  |  |  516|      0|#define RAPIDJSON_MULTILINEMACRO_BEGIN do {
  |  |  |  |  ------------------
  |  |  |  |  102|      0|    RAPIDJSON_ASSERT(!HasParseError()); /* Error can only be assigned once */ \
  |  |  |  |  ------------------
  |  |  |  |  |  |  437|      0|#define RAPIDJSON_ASSERT(x) assert(x)
  |  |  |  |  ------------------
  |  |  |  |  103|      0|    SetParseError(parseErrorCode, offset); \
  |  |  |  |  104|      0|    RAPIDJSON_MULTILINEMACRO_END
  |  |  |  |  ------------------
  |  |  |  |  |  |  517|      0|#define RAPIDJSON_MULTILINEMACRO_END \
  |  |  |  |  |  |  518|      0|} while((void)0, 0)
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  Branch (518:9): [Folded, False: 0]
  |  |  |  |  |  |  ------------------
  |  |  |  |  ------------------
  |  |  ------------------
  |  |  122|      0|    RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; \
  |  |  ------------------
  |  |  |  |   66|      0|    RAPIDJSON_PARSE_ERROR_EARLY_RETURN(RAPIDJSON_NOTHING)
  |  |  |  |  ------------------
  |  |  |  |  |  |   61|      0|    RAPIDJSON_MULTILINEMACRO_BEGIN \
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  516|      0|#define RAPIDJSON_MULTILINEMACRO_BEGIN do {
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |   62|      0|    if (RAPIDJSON_UNLIKELY(HasParseError())) { return value; } \
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  505|      0|#define RAPIDJSON_UNLIKELY(x) __builtin_expect(!!(x), 0)
  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  |  Branch (505:31): [True: 0, False: 0]
  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |   63|      0|    RAPIDJSON_MULTILINEMACRO_END
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  517|      0|#define RAPIDJSON_MULTILINEMACRO_END \
  |  |  |  |  |  |  |  |  518|      0|} while((void)0, 0)
  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  |  Branch (518:9): [Folded, False: 0]
  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  ------------------
  |  |  |  |  ------------------
  |  |  ------------------
  |  |  123|      0|    RAPIDJSON_MULTILINEMACRO_END
  |  |  ------------------
  |  |  |  |  517|      0|#define RAPIDJSON_MULTILINEMACRO_END \
  |  |  |  |  518|      0|} while((void)0, 0)
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (518:9): [Folded, False: 0]
  |  |  |  |  ------------------
  |  |  ------------------
  ------------------
  |  Branch (1671:29): [True: 0, False: 0]
  ------------------
 1672|      0|                    }
 1673|      0|                }
 1674|    532|            }
 1675|      0|            else
 1676|    532|                RAPIDJSON_PARSE_ERROR(kParseErrorNumberMissExponent, s.Tell());
  ------------------
  |  |  120|      0|    RAPIDJSON_MULTILINEMACRO_BEGIN \
  |  |  ------------------
  |  |  |  |  516|      0|#define RAPIDJSON_MULTILINEMACRO_BEGIN do {
  |  |  ------------------
  |  |  121|      0|    RAPIDJSON_PARSE_ERROR_NORETURN(parseErrorCode, offset); \
  |  |  ------------------
  |  |  |  |  101|      0|    RAPIDJSON_MULTILINEMACRO_BEGIN \
  |  |  |  |  ------------------
  |  |  |  |  |  |  516|      0|#define RAPIDJSON_MULTILINEMACRO_BEGIN do {
  |  |  |  |  ------------------
  |  |  |  |  102|      0|    RAPIDJSON_ASSERT(!HasParseError()); /* Error can only be assigned once */ \
  |  |  |  |  ------------------
  |  |  |  |  |  |  437|      0|#define RAPIDJSON_ASSERT(x) assert(x)
  |  |  |  |  ------------------
  |  |  |  |  103|      0|    SetParseError(parseErrorCode, offset); \
  |  |  |  |  104|      0|    RAPIDJSON_MULTILINEMACRO_END
  |  |  |  |  ------------------
  |  |  |  |  |  |  517|      0|#define RAPIDJSON_MULTILINEMACRO_END \
  |  |  |  |  |  |  518|      0|} while((void)0, 0)
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  Branch (518:9): [Folded, False: 0]
  |  |  |  |  |  |  ------------------
  |  |  |  |  ------------------
  |  |  ------------------
  |  |  122|      0|    RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; \
  |  |  ------------------
  |  |  |  |   66|      0|    RAPIDJSON_PARSE_ERROR_EARLY_RETURN(RAPIDJSON_NOTHING)
  |  |  |  |  ------------------
  |  |  |  |  |  |   61|      0|    RAPIDJSON_MULTILINEMACRO_BEGIN \
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  516|      0|#define RAPIDJSON_MULTILINEMACRO_BEGIN do {
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |   62|      0|    if (RAPIDJSON_UNLIKELY(HasParseError())) { return value; } \
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  505|      0|#define RAPIDJSON_UNLIKELY(x) __builtin_expect(!!(x), 0)
  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  |  Branch (505:31): [True: 0, False: 0]
  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |   63|      0|    RAPIDJSON_MULTILINEMACRO_END
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  517|      0|#define RAPIDJSON_MULTILINEMACRO_END \
  |  |  |  |  |  |  |  |  518|      0|} while((void)0, 0)
  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  |  Branch (518:9): [Folded, False: 0]
  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  ------------------
  |  |  |  |  ------------------
  |  |  ------------------
  |  |  123|      0|    RAPIDJSON_MULTILINEMACRO_END
  |  |  ------------------
  |  |  |  |  517|      0|#define RAPIDJSON_MULTILINEMACRO_END \
  |  |  |  |  518|      0|} while((void)0, 0)
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (518:9): [Folded, False: 0]
  |  |  |  |  ------------------
  |  |  ------------------
  ------------------
  |  Branch (1676:17): [True: 0, False: 0]
  ------------------
 1677|       |
 1678|    532|            if (expMinus)
  ------------------
  |  Branch (1678:17): [True: 532, False: 0]
  ------------------
 1679|    532|                exp = -exp;
 1680|    532|        }
 1681|       |
 1682|       |        // Finish parsing, call event according to the type of number.
 1683|   828k|        bool cont = true;
 1684|       |
 1685|   828k|        if (parseFlags & kParseNumbersAsStringsFlag) {
  ------------------
  |  Branch (1685:13): [Folded, False: 828k]
  ------------------
 1686|      0|            if (parseFlags & kParseInsituFlag) {
  ------------------
  |  Branch (1686:17): [True: 0, Folded]
  ------------------
 1687|      0|                s.Pop();  // Pop stack no matter if it will be used or not.
 1688|      0|                typename InputStream::Ch* head = is.PutBegin();
 1689|      0|                const size_t length = s.Tell() - startOffset;
 1690|      0|                RAPIDJSON_ASSERT(length <= 0xFFFFFFFF);
  ------------------
  |  |  437|      0|#define RAPIDJSON_ASSERT(x) assert(x)
  ------------------
  |  Branch (1690:17): [True: 0, False: 0]
  ------------------
 1691|       |                // unable to insert the \0 character here, it will erase the comma after this number
 1692|      0|                const typename TargetEncoding::Ch* const str = reinterpret_cast<typename TargetEncoding::Ch*>(head);
 1693|      0|                cont = handler.RawNumber(str, SizeType(length), false);
 1694|      0|            }
 1695|      0|            else {
 1696|      0|                SizeType numCharsToCopy = static_cast<SizeType>(s.Length());
 1697|      0|                GenericStringStream<UTF8<NumberCharacter> > srcStream(s.Pop());
 1698|      0|                StackStream<typename TargetEncoding::Ch> dstStream(stack_);
 1699|      0|                while (numCharsToCopy--) {
  ------------------
  |  Branch (1699:24): [True: 0, False: 0]
  ------------------
 1700|      0|                    Transcoder<UTF8<typename TargetEncoding::Ch>, TargetEncoding>::Transcode(srcStream, dstStream);
 1701|      0|                }
 1702|      0|                dstStream.Put('\0');
 1703|      0|                const typename TargetEncoding::Ch* str = dstStream.Pop();
 1704|      0|                const SizeType length = static_cast<SizeType>(dstStream.Length()) - 1;
 1705|      0|                cont = handler.RawNumber(str, SizeType(length), true);
 1706|      0|            }
 1707|      0|        }
 1708|   828k|        else {
 1709|   828k|           size_t length = s.Length();
 1710|   828k|           const NumberCharacter* decimal = s.Pop();  // Pop stack no matter if it will be used or not.
 1711|       |
 1712|   828k|           if (useDouble) {
  ------------------
  |  Branch (1712:16): [True: 6.78k, False: 821k]
  ------------------
 1713|  6.78k|               int p = exp + expFrac;
 1714|  6.78k|               if (parseFlags & kParseFullPrecisionFlag)
  ------------------
  |  Branch (1714:20): [Folded, False: 6.78k]
  ------------------
 1715|      0|                   d = internal::StrtodFullPrecision(d, p, decimal, length, decimalPosition, exp);
 1716|  6.78k|               else
 1717|  6.78k|                   d = internal::StrtodNormalPrecision(d, p);
 1718|       |
 1719|       |               // Use > max, instead of == inf, to fix bogus warning -Wfloat-equal
 1720|  6.78k|               if (d > (std::numeric_limits<double>::max)()) {
  ------------------
  |  Branch (1720:20): [True: 0, False: 6.78k]
  ------------------
 1721|       |                   // Overflow
 1722|       |                   // TODO: internal::StrtodX should report overflow (or underflow)
 1723|      0|                   RAPIDJSON_PARSE_ERROR(kParseErrorNumberTooBig, startOffset);
  ------------------
  |  |  120|      0|    RAPIDJSON_MULTILINEMACRO_BEGIN \
  |  |  ------------------
  |  |  |  |  516|      0|#define RAPIDJSON_MULTILINEMACRO_BEGIN do {
  |  |  ------------------
  |  |  121|      0|    RAPIDJSON_PARSE_ERROR_NORETURN(parseErrorCode, offset); \
  |  |  ------------------
  |  |  |  |  101|      0|    RAPIDJSON_MULTILINEMACRO_BEGIN \
  |  |  |  |  ------------------
  |  |  |  |  |  |  516|      0|#define RAPIDJSON_MULTILINEMACRO_BEGIN do {
  |  |  |  |  ------------------
  |  |  |  |  102|      0|    RAPIDJSON_ASSERT(!HasParseError()); /* Error can only be assigned once */ \
  |  |  |  |  ------------------
  |  |  |  |  |  |  437|      0|#define RAPIDJSON_ASSERT(x) assert(x)
  |  |  |  |  ------------------
  |  |  |  |  103|      0|    SetParseError(parseErrorCode, offset); \
  |  |  |  |  104|      0|    RAPIDJSON_MULTILINEMACRO_END
  |  |  |  |  ------------------
  |  |  |  |  |  |  517|      0|#define RAPIDJSON_MULTILINEMACRO_END \
  |  |  |  |  |  |  518|      0|} while((void)0, 0)
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  Branch (518:9): [Folded, False: 0]
  |  |  |  |  |  |  ------------------
  |  |  |  |  ------------------
  |  |  ------------------
  |  |  122|      0|    RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; \
  |  |  ------------------
  |  |  |  |   66|      0|    RAPIDJSON_PARSE_ERROR_EARLY_RETURN(RAPIDJSON_NOTHING)
  |  |  |  |  ------------------
  |  |  |  |  |  |   61|      0|    RAPIDJSON_MULTILINEMACRO_BEGIN \
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  516|      0|#define RAPIDJSON_MULTILINEMACRO_BEGIN do {
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |   62|      0|    if (RAPIDJSON_UNLIKELY(HasParseError())) { return value; } \
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  505|      0|#define RAPIDJSON_UNLIKELY(x) __builtin_expect(!!(x), 0)
  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  |  Branch (505:31): [True: 0, False: 0]
  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |   63|      0|    RAPIDJSON_MULTILINEMACRO_END
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  517|      0|#define RAPIDJSON_MULTILINEMACRO_END \
  |  |  |  |  |  |  |  |  518|      0|} while((void)0, 0)
  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  |  Branch (518:9): [Folded, False: 0]
  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  ------------------
  |  |  |  |  ------------------
  |  |  ------------------
  |  |  123|      0|    RAPIDJSON_MULTILINEMACRO_END
  |  |  ------------------
  |  |  |  |  517|      0|#define RAPIDJSON_MULTILINEMACRO_END \
  |  |  |  |  518|      0|} while((void)0, 0)
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (518:9): [Folded, False: 0]
  |  |  |  |  ------------------
  |  |  ------------------
  ------------------
  |  Branch (1723:20): [True: 0, False: 0]
  ------------------
 1724|      0|               }
 1725|       |
 1726|  6.78k|               cont = handler.Double(minus ? -d : d);
  ------------------
  |  Branch (1726:38): [True: 2.05k, False: 4.73k]
  ------------------
 1727|  6.78k|           }
 1728|   821k|           else if (useNanOrInf) {
  ------------------
  |  Branch (1728:21): [True: 0, False: 821k]
  ------------------
 1729|      0|               cont = handler.Double(d);
 1730|      0|           }
 1731|   821k|           else {
 1732|   821k|               if (use64bit) {
  ------------------
  |  Branch (1732:20): [True: 7.07k, False: 814k]
  ------------------
 1733|  7.07k|                   if (minus)
  ------------------
  |  Branch (1733:24): [True: 12, False: 7.06k]
  ------------------
 1734|     12|                       cont = handler.Int64(static_cast<int64_t>(~i64 + 1));
 1735|  7.06k|                   else
 1736|  7.06k|                       cont = handler.Uint64(i64);
 1737|  7.07k|               }
 1738|   814k|               else {
 1739|   814k|                   if (minus)
  ------------------
  |  Branch (1739:24): [True: 155, False: 814k]
  ------------------
 1740|    155|                       cont = handler.Int(static_cast<int32_t>(~i + 1));
 1741|   814k|                   else
 1742|   814k|                       cont = handler.Uint(i);
 1743|   814k|               }
 1744|   821k|           }
 1745|   828k|        }
 1746|   828k|        if (RAPIDJSON_UNLIKELY(!cont))
  ------------------
  |  |  505|   828k|#define RAPIDJSON_UNLIKELY(x) __builtin_expect(!!(x), 0)
  |  |  ------------------
  |  |  |  Branch (505:31): [True: 0, False: 828k]
  |  |  ------------------
  ------------------
 1747|       |            RAPIDJSON_PARSE_ERROR(kParseErrorTermination, startOffset);
  ------------------
  |  |  120|      0|    RAPIDJSON_MULTILINEMACRO_BEGIN \
  |  |  ------------------
  |  |  |  |  516|      0|#define RAPIDJSON_MULTILINEMACRO_BEGIN do {
  |  |  ------------------
  |  |  121|      0|    RAPIDJSON_PARSE_ERROR_NORETURN(parseErrorCode, offset); \
  |  |  ------------------
  |  |  |  |  101|      0|    RAPIDJSON_MULTILINEMACRO_BEGIN \
  |  |  |  |  ------------------
  |  |  |  |  |  |  516|      0|#define RAPIDJSON_MULTILINEMACRO_BEGIN do {
  |  |  |  |  ------------------
  |  |  |  |  102|      0|    RAPIDJSON_ASSERT(!HasParseError()); /* Error can only be assigned once */ \
  |  |  |  |  ------------------
  |  |  |  |  |  |  437|      0|#define RAPIDJSON_ASSERT(x) assert(x)
  |  |  |  |  ------------------
  |  |  |  |  103|      0|    SetParseError(parseErrorCode, offset); \
  |  |  |  |  104|      0|    RAPIDJSON_MULTILINEMACRO_END
  |  |  |  |  ------------------
  |  |  |  |  |  |  517|      0|#define RAPIDJSON_MULTILINEMACRO_END \
  |  |  |  |  |  |  518|      0|} while((void)0, 0)
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  Branch (518:9): [Folded, False: 0]
  |  |  |  |  |  |  ------------------
  |  |  |  |  ------------------
  |  |  ------------------
  |  |  122|      0|    RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; \
  |  |  ------------------
  |  |  |  |   66|      0|    RAPIDJSON_PARSE_ERROR_EARLY_RETURN(RAPIDJSON_NOTHING)
  |  |  |  |  ------------------
  |  |  |  |  |  |   61|      0|    RAPIDJSON_MULTILINEMACRO_BEGIN \
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  516|      0|#define RAPIDJSON_MULTILINEMACRO_BEGIN do {
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |   62|      0|    if (RAPIDJSON_UNLIKELY(HasParseError())) { return value; } \
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  505|      0|#define RAPIDJSON_UNLIKELY(x) __builtin_expect(!!(x), 0)
  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  |  Branch (505:31): [True: 0, False: 0]
  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |   63|      0|    RAPIDJSON_MULTILINEMACRO_END
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  517|      0|#define RAPIDJSON_MULTILINEMACRO_END \
  |  |  |  |  |  |  |  |  518|      0|} while((void)0, 0)
  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  |  Branch (518:9): [Folded, False: 0]
  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  ------------------
  |  |  |  |  ------------------
  |  |  ------------------
  |  |  123|      0|    RAPIDJSON_MULTILINEMACRO_END
  |  |  ------------------
  |  |  |  |  517|      0|#define RAPIDJSON_MULTILINEMACRO_END \
  |  |  |  |  518|      0|} while((void)0, 0)
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (518:9): [Folded, False: 0]
  |  |  |  |  ------------------
  |  |  ------------------
  ------------------
  |  Branch (1747:13): [True: 0, False: 0]
  ------------------
 1748|   828k|    }
_ZN9rapidjson13GenericReaderINS_4UTF8IcEES2_NS_12CrtAllocatorEE12NumberStreamINS_25GenericInsituStringStreamIS2_EEcLb0ELb0EE4TellEv:
 1422|   828k|        size_t Tell() { return is.Tell(); }
_ZN9rapidjson13GenericReaderINS_4UTF8IcEES2_NS_12CrtAllocatorEE7ConsumeINS4_12NumberStreamINS_25GenericInsituStringStreamIS2_EEcLb0ELb0EEEEEbRT_NSA_2ChE:
  895|  3.31M|    RAPIDJSON_FORCEINLINE static bool Consume(InputStream& is, typename InputStream::Ch expect) {
  896|  3.31M|        if (RAPIDJSON_LIKELY(is.Peek() == expect)) {
  ------------------
  |  |  492|  3.31M|#define RAPIDJSON_LIKELY(x) __builtin_expect(!!(x), 1)
  |  |  ------------------
  |  |  |  Branch (492:29): [True: 10.0k, False: 3.30M]
  |  |  ------------------
  ------------------
  897|  10.0k|            is.Take();
  898|  10.0k|            return true;
  899|  10.0k|        }
  900|  3.30M|        else
  901|  3.30M|            return false;
  902|  3.31M|    }
_ZNK9rapidjson13GenericReaderINS_4UTF8IcEES2_NS_12CrtAllocatorEE12NumberStreamINS_25GenericInsituStringStreamIS2_EEcLb0ELb0EE4PeekEv:
 1417|  7.18M|        RAPIDJSON_FORCEINLINE Ch Peek() const { return is.Peek(); }
_ZN9rapidjson13GenericReaderINS_4UTF8IcEES2_NS_12CrtAllocatorEE12NumberStreamINS_25GenericInsituStringStreamIS2_EEcLb0ELb0EE8TakePushEv:
 1418|  1.09M|        RAPIDJSON_FORCEINLINE Ch TakePush() { return is.Take(); }
_ZN9rapidjson13GenericReaderINS_4UTF8IcEES2_NS_12CrtAllocatorEE12NumberStreamINS_25GenericInsituStringStreamIS2_EEcLb0ELb0EE6LengthEv:
 1423|  1.65M|        size_t Length() { return 0; }
_ZN9rapidjson13GenericReaderINS_4UTF8IcEES2_NS_12CrtAllocatorEE12NumberStreamINS_25GenericInsituStringStreamIS2_EEcLb0ELb0EE4TakeEv:
 1419|  11.0k|        RAPIDJSON_FORCEINLINE Ch Take() { return is.Take(); }
_ZN9rapidjson13GenericReaderINS_4UTF8IcEES2_NS_12CrtAllocatorEE12NumberStreamINS_25GenericInsituStringStreamIS2_EEcLb0ELb0EE3PopEv:
 1424|   828k|        const StackCharacter* Pop() { return 0; }
_ZN9rapidjson13GenericReaderINS_4UTF8IcEES2_NS_12CrtAllocatorEEC2EPS3_m:
  548|    102|        stack_(stackAllocator, stackCapacity), parseResult_(), state_(IterativeParsingStartState) {}
_ZN9rapidjson13GenericReaderINS_4UTF8IcEES2_NS_12CrtAllocatorEE16ClearStackOnExitC2ERS4_:
  702|    102|        explicit ClearStackOnExit(GenericReader& r) : r_(r) {}
_ZN9rapidjson8internal15StreamLocalCopyINS_25GenericInsituStringStreamINS_4UTF8IcEEEELi1EEC2ERS5_:
  233|  2.80M|    StreamLocalCopy(Stream& original) : s(original), original_(original) {}
_ZN9rapidjson8internal15StreamLocalCopyINS_25GenericInsituStringStreamINS_4UTF8IcEEEELi1EED2Ev:
  234|  2.80M|    ~StreamLocalCopy() { original_ = s; }
_ZN9rapidjson13GenericReaderINS_4UTF8IcEES2_NS_12CrtAllocatorEE12NumberStreamINS_25GenericInsituStringStreamIS2_EEcLb0ELb0EEC2ERS4_RS7_:
 1415|   828k|        NumberStream(GenericReader& reader, InputStream& s) : is(s) { (void)reader;  }
_ZN9rapidjson13GenericReaderINS_4UTF8IcEES2_NS_12CrtAllocatorEE16ClearStackOnExitD2Ev:
  703|    102|        ~ClearStackOnExit() { r_.ClearStack(); }

_ZN9rapidjson25GenericInsituStringStreamINS_4UTF8IcEEE4TakeEv:
  195|  2.85M|    Ch Take() { return *src_++; }
_ZN9rapidjson25GenericInsituStringStreamINS_4UTF8IcEEE8PutBeginEv:
  201|  13.5k|    Ch* PutBegin() { return dst_ = src_; }
_ZN9rapidjson25GenericInsituStringStreamINS_4UTF8IcEEE3PutEc:
  199|   255k|    void Put(Ch c) { RAPIDJSON_ASSERT(dst_ != 0); *dst_++ = c; }
  ------------------
  |  |  437|   255k|#define RAPIDJSON_ASSERT(x) assert(x)
  ------------------
  |  Branch (199:22): [True: 255k, False: 0]
  ------------------
_ZN9rapidjson25GenericInsituStringStreamINS_4UTF8IcEEE6PutEndEPc:
  202|  13.5k|    size_t PutEnd(Ch* begin) { return static_cast<size_t>(dst_ - begin); }
_ZN9rapidjson25GenericInsituStringStreamINS_4UTF8IcEEE4PeekEv:
  194|  12.2M|    Ch Peek() { return *src_; }
_ZN9rapidjson25GenericInsituStringStreamINS_4UTF8IcEEE4TellEv:
  196|  1.07M|    size_t Tell() { return static_cast<size_t>(src_ - head_); }
_ZN9rapidjson25GenericInsituStringStreamINS_4UTF8IcEEEC2EPc:
  191|    102|    GenericInsituStringStream(Ch *src) : src_(src), dst_(0), head_(src) {}

call_zopen64:
   31|    401|voidpf call_zopen64 (const zlib_filefunc64_32_def* pfilefunc, const void*filename, int mode) {
   32|    401|    if (pfilefunc->zfile_func64.zopen64_file != NULL)
  ------------------
  |  Branch (32:9): [True: 0, False: 401]
  ------------------
   33|      0|        return (*(pfilefunc->zfile_func64.zopen64_file)) (pfilefunc->zfile_func64.opaque,filename,mode);
   34|    401|    else
   35|    401|    {
   36|    401|        return (*(pfilefunc->zopen32_file))(pfilefunc->zfile_func64.opaque,(const char*)filename,mode);
   37|    401|    }
   38|    401|}
call_zseek64:
   40|  34.0k|long call_zseek64 (const zlib_filefunc64_32_def* pfilefunc,voidpf filestream, ZPOS64_T offset, int origin) {
   41|  34.0k|    if (pfilefunc->zfile_func64.zseek64_file != NULL)
  ------------------
  |  Branch (41:9): [True: 0, False: 34.0k]
  ------------------
   42|      0|        return (*(pfilefunc->zfile_func64.zseek64_file)) (pfilefunc->zfile_func64.opaque,filestream,offset,origin);
   43|  34.0k|    else
   44|  34.0k|    {
   45|  34.0k|        uLong offsetTruncated = (uLong)offset;
   46|  34.0k|        if (offsetTruncated != offset)
  ------------------
  |  Branch (46:13): [True: 0, False: 34.0k]
  ------------------
   47|      0|            return -1;
   48|  34.0k|        else
   49|  34.0k|            return (*(pfilefunc->zseek32_file))(pfilefunc->zfile_func64.opaque,filestream,offsetTruncated,origin);
   50|  34.0k|    }
   51|  34.0k|}
call_ztell64:
   53|    802|ZPOS64_T call_ztell64 (const zlib_filefunc64_32_def* pfilefunc, voidpf filestream) {
   54|    802|    if (pfilefunc->zfile_func64.zseek64_file != NULL)
  ------------------
  |  Branch (54:9): [True: 0, False: 802]
  ------------------
   55|      0|        return (*(pfilefunc->zfile_func64.ztell64_file)) (pfilefunc->zfile_func64.opaque,filestream);
   56|    802|    else
   57|    802|    {
   58|    802|        uLong tell_uLong = (uLong)(*(pfilefunc->ztell32_file))(pfilefunc->zfile_func64.opaque,filestream);
   59|    802|        if ((tell_uLong) == MAXU32)
  ------------------
  |  |  106|    802|#define MAXU32 (0xffffffff)
  ------------------
  |  Branch (59:13): [True: 0, False: 802]
  ------------------
   60|      0|            return (ZPOS64_T)-1;
   61|    802|        else
   62|    802|            return tell_uLong;
   63|    802|    }
   64|    802|}
fill_zlib_filefunc64_32_def_from_filefunc32:
   66|    401|void fill_zlib_filefunc64_32_def_from_filefunc32(zlib_filefunc64_32_def* p_filefunc64_32, const zlib_filefunc_def* p_filefunc32) {
   67|    401|    p_filefunc64_32->zfile_func64.zopen64_file = NULL;
   68|    401|    p_filefunc64_32->zopen32_file = p_filefunc32->zopen_file;
   69|    401|    p_filefunc64_32->zfile_func64.zread_file = p_filefunc32->zread_file;
   70|    401|    p_filefunc64_32->zfile_func64.zwrite_file = p_filefunc32->zwrite_file;
   71|    401|    p_filefunc64_32->zfile_func64.ztell64_file = NULL;
   72|       |    p_filefunc64_32->zfile_func64.zseek64_file = NULL;
   73|    401|    p_filefunc64_32->zfile_func64.zclose_file = p_filefunc32->zclose_file;
   74|    401|    p_filefunc64_32->zfile_func64.zerror_file = p_filefunc32->zerror_file;
   75|    401|    p_filefunc64_32->zfile_func64.opaque = p_filefunc32->opaque;
   76|    401|    p_filefunc64_32->zseek32_file = p_filefunc32->zseek_file;
   77|    401|    p_filefunc64_32->ztell32_file = p_filefunc32->ztell_file;
   78|    401|}

unzOpen2:
  673|    401|                                zlib_filefunc_def* pzlib_filefunc32_def) {
  674|    401|    if (pzlib_filefunc32_def != NULL)
  ------------------
  |  Branch (674:9): [True: 401, False: 0]
  ------------------
  675|    401|    {
  676|    401|        zlib_filefunc64_32_def zlib_filefunc64_32_def_fill;
  677|    401|        fill_zlib_filefunc64_32_def_from_filefunc32(&zlib_filefunc64_32_def_fill,pzlib_filefunc32_def);
  678|    401|        return unzOpenInternal(path, &zlib_filefunc64_32_def_fill, 0);
  679|    401|    }
  680|      0|    else
  681|      0|        return unzOpenInternal(path, NULL, 0);
  682|    401|}
unzClose:
  711|     27|extern int ZEXPORT unzClose(unzFile file) {
  712|     27|    unz64_s* s;
  713|     27|    if (file==NULL)
  ------------------
  |  Branch (713:9): [True: 0, False: 27]
  ------------------
  714|      0|        return UNZ_PARAMERROR;
  ------------------
  |  |   78|      0|#define UNZ_PARAMERROR                  (-102)
  ------------------
  715|     27|    s=(unz64_s*)file;
  716|       |
  717|     27|    if (s->pfile_in_zip_read!=NULL)
  ------------------
  |  Branch (717:9): [True: 0, False: 27]
  ------------------
  718|      0|        unzCloseCurrentFile(file);
  719|       |
  720|     27|    ZCLOSE64(s->z_filefunc, s->filestream);
  ------------------
  |  |  193|     27|#define ZCLOSE64(filefunc,filestream)             ((*((filefunc).zfile_func64.zclose_file))  ((filefunc).zfile_func64.opaque,filestream))
  ------------------
  721|     27|    free(s);
  722|     27|    return UNZ_OK;
  ------------------
  |  |   74|     27|#define UNZ_OK                          (0)
  ------------------
  723|     27|}
unzGetCurrentFileInfo:
 1024|    314|                                         char* szComment,  uLong commentBufferSize) {
 1025|    314|    int err;
 1026|    314|    unz_file_info64 file_info64;
 1027|    314|    err = unz64local_GetCurrentFileInfoInternal(file,&file_info64,NULL,
 1028|    314|                                                szFileName,fileNameBufferSize,
 1029|    314|                                                extraField,extraFieldBufferSize,
 1030|    314|                                                szComment,commentBufferSize);
 1031|    314|    if ((err==UNZ_OK) && (pfile_info != NULL))
  ------------------
  |  |   74|    314|#define UNZ_OK                          (0)
  ------------------
  |  Branch (1031:9): [True: 312, False: 2]
  |  Branch (1031:26): [True: 312, False: 0]
  ------------------
 1032|    312|    {
 1033|    312|        pfile_info->version = file_info64.version;
 1034|    312|        pfile_info->version_needed = file_info64.version_needed;
 1035|    312|        pfile_info->flag = file_info64.flag;
 1036|    312|        pfile_info->compression_method = file_info64.compression_method;
 1037|    312|        pfile_info->dosDate = file_info64.dosDate;
 1038|    312|        pfile_info->crc = file_info64.crc;
 1039|       |
 1040|    312|        pfile_info->size_filename = file_info64.size_filename;
 1041|    312|        pfile_info->size_file_extra = file_info64.size_file_extra;
 1042|    312|        pfile_info->size_file_comment = file_info64.size_file_comment;
 1043|       |
 1044|    312|        pfile_info->disk_num_start = file_info64.disk_num_start;
 1045|    312|        pfile_info->internal_fa = file_info64.internal_fa;
 1046|    312|        pfile_info->external_fa = file_info64.external_fa;
 1047|       |
 1048|    312|        pfile_info->tmu_date = file_info64.tmu_date;
 1049|       |
 1050|       |
 1051|    312|        pfile_info->compressed_size = (uLong)file_info64.compressed_size;
 1052|    312|        pfile_info->uncompressed_size = (uLong)file_info64.uncompressed_size;
 1053|       |
 1054|    312|    }
 1055|    314|    return err;
 1056|    314|}
unzGoToFirstFile:
 1061|     47|extern int ZEXPORT unzGoToFirstFile(unzFile file) {
 1062|     47|    int err=UNZ_OK;
  ------------------
  |  |   74|     47|#define UNZ_OK                          (0)
  ------------------
 1063|     47|    unz64_s* s;
 1064|     47|    if (file==NULL)
  ------------------
  |  Branch (1064:9): [True: 0, False: 47]
  ------------------
 1065|      0|        return UNZ_PARAMERROR;
  ------------------
  |  |   78|      0|#define UNZ_PARAMERROR                  (-102)
  ------------------
 1066|     47|    s=(unz64_s*)file;
 1067|     47|    s->pos_in_central_dir=s->offset_central_dir;
 1068|     47|    s->num_file=0;
 1069|     47|    err=unz64local_GetCurrentFileInfoInternal(file,&s->cur_file_info,
 1070|     47|                                             &s->cur_file_info_internal,
 1071|     47|                                             NULL,0,NULL,0,NULL,0);
 1072|     47|    s->current_file_ok = (err == UNZ_OK);
  ------------------
  |  |   74|     47|#define UNZ_OK                          (0)
  ------------------
 1073|     47|    return err;
 1074|     47|}
unzGoToNextFile:
 1081|    314|extern int ZEXPORT unzGoToNextFile(unzFile file) {
 1082|    314|    unz64_s* s;
 1083|    314|    int err;
 1084|       |
 1085|    314|    if (file==NULL)
  ------------------
  |  Branch (1085:9): [True: 0, False: 314]
  ------------------
 1086|      0|        return UNZ_PARAMERROR;
  ------------------
  |  |   78|      0|#define UNZ_PARAMERROR                  (-102)
  ------------------
 1087|    314|    s=(unz64_s*)file;
 1088|    314|    if (!s->current_file_ok)
  ------------------
  |  Branch (1088:9): [True: 2, False: 312]
  ------------------
 1089|      2|        return UNZ_END_OF_LIST_OF_FILE;
  ------------------
  |  |   75|      2|#define UNZ_END_OF_LIST_OF_FILE         (-100)
  ------------------
 1090|    312|    if (s->gi.number_entry != 0xffff)    /* 2^16 files overflow hack */
  ------------------
  |  Branch (1090:9): [True: 312, False: 0]
  ------------------
 1091|    312|      if (s->num_file+1==s->gi.number_entry)
  ------------------
  |  Branch (1091:11): [True: 18, False: 294]
  ------------------
 1092|     18|        return UNZ_END_OF_LIST_OF_FILE;
  ------------------
  |  |   75|     18|#define UNZ_END_OF_LIST_OF_FILE         (-100)
  ------------------
 1093|       |
 1094|    294|    s->pos_in_central_dir += SIZECENTRALDIRITEM + s->cur_file_info.size_filename +
  ------------------
  |  |  113|    294|#define SIZECENTRALDIRITEM (0x2e)
  ------------------
 1095|    294|            s->cur_file_info.size_file_extra + s->cur_file_info.size_file_comment ;
 1096|    294|    s->num_file++;
 1097|    294|    err = unz64local_GetCurrentFileInfoInternal(file,&s->cur_file_info,
 1098|    294|                                               &s->cur_file_info_internal,
 1099|    294|                                               NULL,0,NULL,0,NULL,0);
 1100|    294|    s->current_file_ok = (err == UNZ_OK);
  ------------------
  |  |   74|    294|#define UNZ_OK                          (0)
  ------------------
 1101|    294|    return err;
 1102|    312|}
unzGetFilePos64:
 1188|    312|extern int ZEXPORT unzGetFilePos64(unzFile file, unz64_file_pos* file_pos) {
 1189|    312|    unz64_s* s;
 1190|       |
 1191|    312|    if (file==NULL || file_pos==NULL)
  ------------------
  |  Branch (1191:9): [True: 0, False: 312]
  |  Branch (1191:23): [True: 0, False: 312]
  ------------------
 1192|      0|        return UNZ_PARAMERROR;
  ------------------
  |  |   78|      0|#define UNZ_PARAMERROR                  (-102)
  ------------------
 1193|    312|    s=(unz64_s*)file;
 1194|    312|    if (!s->current_file_ok)
  ------------------
  |  Branch (1194:9): [True: 0, False: 312]
  ------------------
 1195|      0|        return UNZ_END_OF_LIST_OF_FILE;
  ------------------
  |  |   75|      0|#define UNZ_END_OF_LIST_OF_FILE         (-100)
  ------------------
 1196|       |
 1197|    312|    file_pos->pos_in_zip_directory  = s->pos_in_central_dir;
 1198|    312|    file_pos->num_of_file           = s->num_file;
 1199|       |
 1200|    312|    return UNZ_OK;
  ------------------
  |  |   74|    312|#define UNZ_OK                          (0)
  ------------------
 1201|    312|}
unzGetFilePos:
 1203|    312|extern int ZEXPORT unzGetFilePos(unzFile file, unz_file_pos* file_pos) {
 1204|    312|    unz64_file_pos file_pos64;
 1205|    312|    int err = unzGetFilePos64(file,&file_pos64);
 1206|    312|    if (err==UNZ_OK)
  ------------------
  |  |   74|    312|#define UNZ_OK                          (0)
  ------------------
  |  Branch (1206:9): [True: 312, False: 0]
  ------------------
 1207|    312|    {
 1208|    312|        file_pos->pos_in_zip_directory = (uLong)file_pos64.pos_in_zip_directory;
 1209|    312|        file_pos->num_of_file = (uLong)file_pos64.num_of_file;
 1210|    312|    }
 1211|    312|    return err;
 1212|    312|}
unzGoToFilePos64:
 1214|      9|extern int ZEXPORT unzGoToFilePos64(unzFile file, const unz64_file_pos* file_pos) {
 1215|      9|    unz64_s* s;
 1216|      9|    int err;
 1217|       |
 1218|      9|    if (file==NULL || file_pos==NULL)
  ------------------
  |  Branch (1218:9): [True: 0, False: 9]
  |  Branch (1218:23): [True: 0, False: 9]
  ------------------
 1219|      0|        return UNZ_PARAMERROR;
  ------------------
  |  |   78|      0|#define UNZ_PARAMERROR                  (-102)
  ------------------
 1220|      9|    s=(unz64_s*)file;
 1221|       |
 1222|       |    /* jump to the right spot */
 1223|      9|    s->pos_in_central_dir = file_pos->pos_in_zip_directory;
 1224|      9|    s->num_file           = file_pos->num_of_file;
 1225|       |
 1226|       |    /* set the current file */
 1227|      9|    err = unz64local_GetCurrentFileInfoInternal(file,&s->cur_file_info,
 1228|      9|                                               &s->cur_file_info_internal,
 1229|      9|                                               NULL,0,NULL,0,NULL,0);
 1230|       |    /* return results */
 1231|      9|    s->current_file_ok = (err == UNZ_OK);
  ------------------
  |  |   74|      9|#define UNZ_OK                          (0)
  ------------------
 1232|      9|    return err;
 1233|      9|}
unzGoToFilePos:
 1235|      9|extern int ZEXPORT unzGoToFilePos(unzFile file, unz_file_pos* file_pos) {
 1236|      9|    unz64_file_pos file_pos64;
 1237|      9|    if (file_pos == NULL)
  ------------------
  |  Branch (1237:9): [True: 0, False: 9]
  ------------------
 1238|      0|        return UNZ_PARAMERROR;
  ------------------
  |  |   78|      0|#define UNZ_PARAMERROR                  (-102)
  ------------------
 1239|       |
 1240|      9|    file_pos64.pos_in_zip_directory = file_pos->pos_in_zip_directory;
 1241|      9|    file_pos64.num_of_file = file_pos->num_of_file;
 1242|      9|    return unzGoToFilePos64(file,&file_pos64);
 1243|      9|}
unzOpenCurrentFile3:
 1344|      9|                                       int* level, int raw, const char* password) {
 1345|      9|    int err=UNZ_OK;
  ------------------
  |  |   74|      9|#define UNZ_OK                          (0)
  ------------------
 1346|      9|    uInt iSizeVar;
 1347|      9|    unz64_s* s;
 1348|      9|    file_in_zip64_read_info_s* pfile_in_zip_read_info;
 1349|      9|    ZPOS64_T offset_local_extrafield;  /* offset of the local extra field */
 1350|      9|    uInt  size_local_extrafield;    /* size of the local extra field */
 1351|       |#    ifndef NOUNCRYPT
 1352|       |    char source[12];
 1353|       |#    else
 1354|      9|    if (password != NULL)
  ------------------
  |  Branch (1354:9): [True: 0, False: 9]
  ------------------
 1355|      0|        return UNZ_PARAMERROR;
  ------------------
  |  |   78|      0|#define UNZ_PARAMERROR                  (-102)
  ------------------
 1356|      9|#    endif
 1357|       |
 1358|      9|    if (file==NULL)
  ------------------
  |  Branch (1358:9): [True: 0, False: 9]
  ------------------
 1359|      0|        return UNZ_PARAMERROR;
  ------------------
  |  |   78|      0|#define UNZ_PARAMERROR                  (-102)
  ------------------
 1360|      9|    s=(unz64_s*)file;
 1361|      9|    if (!s->current_file_ok)
  ------------------
  |  Branch (1361:9): [True: 0, False: 9]
  ------------------
 1362|      0|        return UNZ_PARAMERROR;
  ------------------
  |  |   78|      0|#define UNZ_PARAMERROR                  (-102)
  ------------------
 1363|       |
 1364|      9|    if (s->pfile_in_zip_read != NULL)
  ------------------
  |  Branch (1364:9): [True: 0, False: 9]
  ------------------
 1365|      0|        unzCloseCurrentFile(file);
 1366|       |
 1367|      9|    if (unz64local_CheckCurrentFileCoherencyHeader(s,&iSizeVar, &offset_local_extrafield,&size_local_extrafield)!=UNZ_OK)
  ------------------
  |  |   74|      9|#define UNZ_OK                          (0)
  ------------------
  |  Branch (1367:9): [True: 1, False: 8]
  ------------------
 1368|      1|        return UNZ_BADZIPFILE;
  ------------------
  |  |   79|      1|#define UNZ_BADZIPFILE                  (-103)
  ------------------
 1369|       |
 1370|      8|    pfile_in_zip_read_info = (file_in_zip64_read_info_s*)ALLOC(sizeof(file_in_zip64_read_info_s));
  ------------------
  |  |  110|      8|# define ALLOC(size) (malloc(size))
  ------------------
 1371|      8|    if (pfile_in_zip_read_info==NULL)
  ------------------
  |  Branch (1371:9): [True: 0, False: 8]
  ------------------
 1372|      0|        return UNZ_INTERNALERROR;
  ------------------
  |  |   80|      0|#define UNZ_INTERNALERROR               (-104)
  ------------------
 1373|       |
 1374|      8|    pfile_in_zip_read_info->read_buffer=(char*)ALLOC(UNZ_BUFSIZE);
  ------------------
  |  |  110|      8|# define ALLOC(size) (malloc(size))
  ------------------
 1375|      8|    pfile_in_zip_read_info->offset_local_extrafield = offset_local_extrafield;
 1376|      8|    pfile_in_zip_read_info->size_local_extrafield = size_local_extrafield;
 1377|      8|    pfile_in_zip_read_info->pos_local_extrafield=0;
 1378|      8|    pfile_in_zip_read_info->raw=raw;
 1379|       |
 1380|      8|    if (pfile_in_zip_read_info->read_buffer==NULL)
  ------------------
  |  Branch (1380:9): [True: 0, False: 8]
  ------------------
 1381|      0|    {
 1382|      0|        free(pfile_in_zip_read_info);
 1383|      0|        return UNZ_INTERNALERROR;
  ------------------
  |  |   80|      0|#define UNZ_INTERNALERROR               (-104)
  ------------------
 1384|      0|    }
 1385|       |
 1386|      8|    pfile_in_zip_read_info->stream_initialised=0;
 1387|       |
 1388|      8|    if (method!=NULL)
  ------------------
  |  Branch (1388:9): [True: 0, False: 8]
  ------------------
 1389|      0|        *method = (int)s->cur_file_info.compression_method;
 1390|       |
 1391|      8|    if (level!=NULL)
  ------------------
  |  Branch (1391:9): [True: 0, False: 8]
  ------------------
 1392|      0|    {
 1393|      0|        *level = 6;
 1394|      0|        switch (s->cur_file_info.flag & 0x06)
  ------------------
  |  Branch (1394:17): [True: 0, False: 0]
  ------------------
 1395|      0|        {
 1396|      0|          case 6 : *level = 1; break;
  ------------------
  |  Branch (1396:11): [True: 0, False: 0]
  ------------------
 1397|      0|          case 4 : *level = 2; break;
  ------------------
  |  Branch (1397:11): [True: 0, False: 0]
  ------------------
 1398|      0|          case 2 : *level = 9; break;
  ------------------
  |  Branch (1398:11): [True: 0, False: 0]
  ------------------
 1399|      0|        }
 1400|      0|    }
 1401|       |
 1402|      8|    if ((s->cur_file_info.compression_method!=0) &&
  ------------------
  |  Branch (1402:9): [True: 8, False: 0]
  ------------------
 1403|       |/* #ifdef HAVE_BZIP2 */
 1404|      8|        (s->cur_file_info.compression_method!=Z_BZIP2ED) &&
  ------------------
  |  |   62|      8|#define Z_BZIP2ED 12
  ------------------
  |  Branch (1404:9): [True: 8, False: 0]
  ------------------
 1405|       |/* #endif */
 1406|      8|        (s->cur_file_info.compression_method!=Z_DEFLATED))
  ------------------
  |  |  209|      8|#define Z_DEFLATED   8
  ------------------
  |  Branch (1406:9): [True: 0, False: 8]
  ------------------
 1407|       |
 1408|      0|        err=UNZ_BADZIPFILE;
  ------------------
  |  |   79|      0|#define UNZ_BADZIPFILE                  (-103)
  ------------------
 1409|       |
 1410|      8|    pfile_in_zip_read_info->crc32_wait=s->cur_file_info.crc;
 1411|      8|    pfile_in_zip_read_info->crc32=0;
 1412|      8|    pfile_in_zip_read_info->total_out_64=0;
 1413|      8|    pfile_in_zip_read_info->compression_method = s->cur_file_info.compression_method;
 1414|      8|    pfile_in_zip_read_info->filestream=s->filestream;
 1415|      8|    pfile_in_zip_read_info->z_filefunc=s->z_filefunc;
 1416|      8|    pfile_in_zip_read_info->byte_before_the_zipfile=s->byte_before_the_zipfile;
 1417|       |
 1418|      8|    pfile_in_zip_read_info->stream.total_out = 0;
 1419|       |
 1420|      8|    if ((s->cur_file_info.compression_method==Z_BZIP2ED) && (!raw))
  ------------------
  |  |   62|      8|#define Z_BZIP2ED 12
  ------------------
  |  Branch (1420:9): [True: 0, False: 8]
  |  Branch (1420:61): [True: 0, False: 0]
  ------------------
 1421|      0|    {
 1422|       |#ifdef HAVE_BZIP2
 1423|       |      pfile_in_zip_read_info->bstream.bzalloc = (void *(*) (void *, int, int))0;
 1424|       |      pfile_in_zip_read_info->bstream.bzfree = (free_func)0;
 1425|       |      pfile_in_zip_read_info->bstream.opaque = (voidpf)0;
 1426|       |      pfile_in_zip_read_info->bstream.state = (voidpf)0;
 1427|       |
 1428|       |      pfile_in_zip_read_info->stream.zalloc = (alloc_func)0;
 1429|       |      pfile_in_zip_read_info->stream.zfree = (free_func)0;
 1430|       |      pfile_in_zip_read_info->stream.opaque = (voidpf)0;
 1431|       |      pfile_in_zip_read_info->stream.next_in = (voidpf)0;
 1432|       |      pfile_in_zip_read_info->stream.avail_in = 0;
 1433|       |
 1434|       |      err=BZ2_bzDecompressInit(&pfile_in_zip_read_info->bstream, 0, 0);
 1435|       |      if (err == Z_OK)
 1436|       |        pfile_in_zip_read_info->stream_initialised=Z_BZIP2ED;
 1437|       |      else
 1438|       |      {
 1439|       |        free(pfile_in_zip_read_info->read_buffer);
 1440|       |        free(pfile_in_zip_read_info);
 1441|       |        return err;
 1442|       |      }
 1443|       |#else
 1444|      0|      pfile_in_zip_read_info->raw=1;
 1445|      0|#endif
 1446|      0|    }
 1447|      8|    else if ((s->cur_file_info.compression_method==Z_DEFLATED) && (!raw))
  ------------------
  |  |  209|      8|#define Z_DEFLATED   8
  ------------------
  |  Branch (1447:14): [True: 8, False: 0]
  |  Branch (1447:67): [True: 8, False: 0]
  ------------------
 1448|      8|    {
 1449|      8|      pfile_in_zip_read_info->stream.zalloc = (alloc_func)0;
 1450|      8|      pfile_in_zip_read_info->stream.zfree = (free_func)0;
 1451|      8|      pfile_in_zip_read_info->stream.opaque = (voidpf)0;
 1452|      8|      pfile_in_zip_read_info->stream.next_in = 0;
 1453|      8|      pfile_in_zip_read_info->stream.avail_in = 0;
 1454|       |
 1455|      8|      err=inflateInit2(&pfile_in_zip_read_info->stream, -MAX_WBITS);
  ------------------
  |  | 1818|      8|          inflateInit2_((strm), (windowBits), ZLIB_VERSION, \
  |  |  ------------------
  |  |  |  |   40|      8|#define ZLIB_VERSION "1.2.13"
  |  |  ------------------
  |  | 1819|      8|                        (int)sizeof(z_stream))
  ------------------
 1456|      8|      if (err == Z_OK)
  ------------------
  |  |  177|      8|#define Z_OK            0
  ------------------
  |  Branch (1456:11): [True: 8, False: 0]
  ------------------
 1457|      8|        pfile_in_zip_read_info->stream_initialised=Z_DEFLATED;
  ------------------
  |  |  209|      8|#define Z_DEFLATED   8
  ------------------
 1458|      0|      else
 1459|      0|      {
 1460|      0|        free(pfile_in_zip_read_info->read_buffer);
 1461|      0|        free(pfile_in_zip_read_info);
 1462|      0|        return err;
 1463|      0|      }
 1464|       |        /* windowBits is passed < 0 to tell that there is no zlib header.
 1465|       |         * Note that in this case inflate *requires* an extra "dummy" byte
 1466|       |         * after the compressed stream in order to complete decompression and
 1467|       |         * return Z_STREAM_END.
 1468|       |         * In unzip, i don't wait absolutely Z_STREAM_END because I known the
 1469|       |         * size of both compressed and uncompressed data
 1470|       |         */
 1471|      8|    }
 1472|      8|    pfile_in_zip_read_info->rest_read_compressed =
 1473|      8|            s->cur_file_info.compressed_size ;
 1474|      8|    pfile_in_zip_read_info->rest_read_uncompressed =
 1475|      8|            s->cur_file_info.uncompressed_size ;
 1476|       |
 1477|       |
 1478|      8|    pfile_in_zip_read_info->pos_in_zipfile =
 1479|      8|            s->cur_file_info_internal.offset_curfile + SIZEZIPLOCALHEADER +
  ------------------
  |  |  114|      8|#define SIZEZIPLOCALHEADER (0x1e)
  ------------------
 1480|      8|              iSizeVar;
 1481|       |
 1482|      8|    pfile_in_zip_read_info->stream.avail_in = (uInt)0;
 1483|       |
 1484|      8|    s->pfile_in_zip_read = pfile_in_zip_read_info;
 1485|      8|                s->encrypted = 0;
 1486|       |
 1487|       |#    ifndef NOUNCRYPT
 1488|       |    if (password != NULL)
 1489|       |    {
 1490|       |        int i;
 1491|       |        s->pcrc_32_tab = get_crc_table();
 1492|       |        init_keys(password,s->keys,s->pcrc_32_tab);
 1493|       |        if (ZSEEK64(s->z_filefunc, s->filestream,
 1494|       |                  s->pfile_in_zip_read->pos_in_zipfile +
 1495|       |                     s->pfile_in_zip_read->byte_before_the_zipfile,
 1496|       |                  SEEK_SET)!=0)
 1497|       |            return UNZ_INTERNALERROR;
 1498|       |        if(ZREAD64(s->z_filefunc, s->filestream,source, 12)<12)
 1499|       |            return UNZ_INTERNALERROR;
 1500|       |
 1501|       |        for (i = 0; i<12; i++)
 1502|       |            zdecode(s->keys,s->pcrc_32_tab,source[i]);
 1503|       |
 1504|       |        s->pfile_in_zip_read->pos_in_zipfile+=12;
 1505|       |        s->encrypted=1;
 1506|       |    }
 1507|       |#    endif
 1508|       |
 1509|       |
 1510|      8|    return UNZ_OK;
  ------------------
  |  |   74|      8|#define UNZ_OK                          (0)
  ------------------
 1511|      8|}
unzOpenCurrentFile:
 1513|      9|extern int ZEXPORT unzOpenCurrentFile(unzFile file) {
 1514|      9|    return unzOpenCurrentFile3(file, NULL, NULL, 0, NULL);
 1515|      9|}
unzReadCurrentFile:
 1552|     16|extern int ZEXPORT unzReadCurrentFile(unzFile file, voidp buf, unsigned len) {
 1553|     16|    int err=UNZ_OK;
  ------------------
  |  |   74|     16|#define UNZ_OK                          (0)
  ------------------
 1554|     16|    uInt iRead = 0;
 1555|     16|    unz64_s* s;
 1556|     16|    file_in_zip64_read_info_s* pfile_in_zip_read_info;
 1557|     16|    if (file==NULL)
  ------------------
  |  Branch (1557:9): [True: 0, False: 16]
  ------------------
 1558|      0|        return UNZ_PARAMERROR;
  ------------------
  |  |   78|      0|#define UNZ_PARAMERROR                  (-102)
  ------------------
 1559|     16|    s=(unz64_s*)file;
 1560|     16|    pfile_in_zip_read_info=s->pfile_in_zip_read;
 1561|       |
 1562|     16|    if (pfile_in_zip_read_info==NULL)
  ------------------
  |  Branch (1562:9): [True: 0, False: 16]
  ------------------
 1563|      0|        return UNZ_PARAMERROR;
  ------------------
  |  |   78|      0|#define UNZ_PARAMERROR                  (-102)
  ------------------
 1564|       |
 1565|       |
 1566|     16|    if (pfile_in_zip_read_info->read_buffer == NULL)
  ------------------
  |  Branch (1566:9): [True: 0, False: 16]
  ------------------
 1567|      0|        return UNZ_END_OF_LIST_OF_FILE;
  ------------------
  |  |   75|      0|#define UNZ_END_OF_LIST_OF_FILE         (-100)
  ------------------
 1568|     16|    if (len==0)
  ------------------
  |  Branch (1568:9): [True: 0, False: 16]
  ------------------
 1569|      0|        return 0;
 1570|       |
 1571|     16|    pfile_in_zip_read_info->stream.next_out = (Bytef*)buf;
 1572|       |
 1573|     16|    pfile_in_zip_read_info->stream.avail_out = (uInt)len;
 1574|       |
 1575|     16|    if ((len>pfile_in_zip_read_info->rest_read_uncompressed) &&
  ------------------
  |  Branch (1575:9): [True: 0, False: 16]
  ------------------
 1576|      0|        (!(pfile_in_zip_read_info->raw)))
  ------------------
  |  Branch (1576:9): [True: 0, False: 0]
  ------------------
 1577|      0|        pfile_in_zip_read_info->stream.avail_out =
 1578|      0|            (uInt)pfile_in_zip_read_info->rest_read_uncompressed;
 1579|       |
 1580|     16|    if ((len>pfile_in_zip_read_info->rest_read_compressed+
  ------------------
  |  Branch (1580:9): [True: 12, False: 4]
  ------------------
 1581|     16|           pfile_in_zip_read_info->stream.avail_in) &&
 1582|     12|         (pfile_in_zip_read_info->raw))
  ------------------
  |  Branch (1582:10): [True: 0, False: 12]
  ------------------
 1583|      0|        pfile_in_zip_read_info->stream.avail_out =
 1584|      0|            (uInt)pfile_in_zip_read_info->rest_read_compressed+
 1585|      0|            pfile_in_zip_read_info->stream.avail_in;
 1586|       |
 1587|     38|    while (pfile_in_zip_read_info->stream.avail_out>0)
  ------------------
  |  Branch (1587:12): [True: 30, False: 8]
  ------------------
 1588|     30|    {
 1589|     30|        if ((pfile_in_zip_read_info->stream.avail_in==0) &&
  ------------------
  |  Branch (1589:13): [True: 22, False: 8]
  ------------------
 1590|     22|            (pfile_in_zip_read_info->rest_read_compressed>0))
  ------------------
  |  Branch (1590:13): [True: 22, False: 0]
  ------------------
 1591|     22|        {
 1592|     22|            uInt uReadThis = UNZ_BUFSIZE;
  ------------------
  |  |  102|     22|#define UNZ_BUFSIZE (16384)
  ------------------
 1593|     22|            if (pfile_in_zip_read_info->rest_read_compressed<uReadThis)
  ------------------
  |  Branch (1593:17): [True: 8, False: 14]
  ------------------
 1594|      8|                uReadThis = (uInt)pfile_in_zip_read_info->rest_read_compressed;
 1595|     22|            if (uReadThis == 0)
  ------------------
  |  Branch (1595:17): [True: 0, False: 22]
  ------------------
 1596|      0|                return UNZ_EOF;
  ------------------
  |  |   77|      0|#define UNZ_EOF                         (0)
  ------------------
 1597|     22|            if (ZSEEK64(pfile_in_zip_read_info->z_filefunc,
  ------------------
  |  |  204|     22|#define ZSEEK64(filefunc,filestream,pos,mode)   (call_zseek64((&(filefunc)),(filestream),(pos),(mode)))
  ------------------
  |  Branch (1597:17): [True: 0, False: 22]
  ------------------
 1598|     22|                      pfile_in_zip_read_info->filestream,
 1599|     22|                      pfile_in_zip_read_info->pos_in_zipfile +
 1600|     22|                         pfile_in_zip_read_info->byte_before_the_zipfile,
 1601|     22|                         ZLIB_FILEFUNC_SEEK_SET)!=0)
 1602|      0|                return UNZ_ERRNO;
  ------------------
  |  |   76|      0|#define UNZ_ERRNO                       (Z_ERRNO)
  |  |  ------------------
  |  |  |  |  180|      0|#define Z_ERRNO        (-1)
  |  |  ------------------
  ------------------
 1603|     22|            if (ZREAD64(pfile_in_zip_read_info->z_filefunc,
  ------------------
  |  |  189|     22|#define ZREAD64(filefunc,filestream,buf,size)     ((*((filefunc).zfile_func64.zread_file))   ((filefunc).zfile_func64.opaque,filestream,buf,size))
  ------------------
  |  Branch (1603:17): [True: 0, False: 22]
  ------------------
 1604|     22|                      pfile_in_zip_read_info->filestream,
 1605|     22|                      pfile_in_zip_read_info->read_buffer,
 1606|     22|                      uReadThis)!=uReadThis)
 1607|      0|                return UNZ_ERRNO;
  ------------------
  |  |   76|      0|#define UNZ_ERRNO                       (Z_ERRNO)
  |  |  ------------------
  |  |  |  |  180|      0|#define Z_ERRNO        (-1)
  |  |  ------------------
  ------------------
 1608|       |
 1609|       |
 1610|       |#            ifndef NOUNCRYPT
 1611|       |            if(s->encrypted)
 1612|       |            {
 1613|       |                uInt i;
 1614|       |                for(i=0;i<uReadThis;i++)
 1615|       |                  pfile_in_zip_read_info->read_buffer[i] =
 1616|       |                      zdecode(s->keys,s->pcrc_32_tab,
 1617|       |                              pfile_in_zip_read_info->read_buffer[i]);
 1618|       |            }
 1619|       |#            endif
 1620|       |
 1621|       |
 1622|     22|            pfile_in_zip_read_info->pos_in_zipfile += uReadThis;
 1623|       |
 1624|     22|            pfile_in_zip_read_info->rest_read_compressed-=uReadThis;
 1625|       |
 1626|     22|            pfile_in_zip_read_info->stream.next_in =
 1627|     22|                (Bytef*)pfile_in_zip_read_info->read_buffer;
 1628|     22|            pfile_in_zip_read_info->stream.avail_in = (uInt)uReadThis;
 1629|     22|        }
 1630|       |
 1631|     30|        if ((pfile_in_zip_read_info->compression_method==0) || (pfile_in_zip_read_info->raw))
  ------------------
  |  Branch (1631:13): [True: 0, False: 30]
  |  Branch (1631:64): [True: 0, False: 30]
  ------------------
 1632|      0|        {
 1633|      0|            uInt uDoCopy,i ;
 1634|       |
 1635|      0|            if ((pfile_in_zip_read_info->stream.avail_in == 0) &&
  ------------------
  |  Branch (1635:17): [True: 0, False: 0]
  ------------------
 1636|      0|                (pfile_in_zip_read_info->rest_read_compressed == 0))
  ------------------
  |  Branch (1636:17): [True: 0, False: 0]
  ------------------
 1637|      0|                return (iRead==0) ? UNZ_EOF : (int)iRead;
  ------------------
  |  |   77|      0|#define UNZ_EOF                         (0)
  ------------------
  |  Branch (1637:24): [True: 0, False: 0]
  ------------------
 1638|       |
 1639|      0|            if (pfile_in_zip_read_info->stream.avail_out <
  ------------------
  |  Branch (1639:17): [True: 0, False: 0]
  ------------------
 1640|      0|                            pfile_in_zip_read_info->stream.avail_in)
 1641|      0|                uDoCopy = pfile_in_zip_read_info->stream.avail_out ;
 1642|      0|            else
 1643|      0|                uDoCopy = pfile_in_zip_read_info->stream.avail_in ;
 1644|       |
 1645|      0|            for (i=0;i<uDoCopy;i++)
  ------------------
  |  Branch (1645:22): [True: 0, False: 0]
  ------------------
 1646|      0|                *(pfile_in_zip_read_info->stream.next_out+i) =
 1647|      0|                        *(pfile_in_zip_read_info->stream.next_in+i);
 1648|       |
 1649|      0|            pfile_in_zip_read_info->total_out_64 = pfile_in_zip_read_info->total_out_64 + uDoCopy;
 1650|       |
 1651|      0|            pfile_in_zip_read_info->crc32 = crc32(pfile_in_zip_read_info->crc32,
 1652|      0|                                pfile_in_zip_read_info->stream.next_out,
 1653|      0|                                uDoCopy);
 1654|      0|            pfile_in_zip_read_info->rest_read_uncompressed-=uDoCopy;
 1655|      0|            pfile_in_zip_read_info->stream.avail_in -= uDoCopy;
 1656|      0|            pfile_in_zip_read_info->stream.avail_out -= uDoCopy;
 1657|      0|            pfile_in_zip_read_info->stream.next_out += uDoCopy;
 1658|      0|            pfile_in_zip_read_info->stream.next_in += uDoCopy;
 1659|      0|            pfile_in_zip_read_info->stream.total_out += uDoCopy;
 1660|      0|            iRead += uDoCopy;
 1661|      0|        }
 1662|     30|        else if (pfile_in_zip_read_info->compression_method==Z_BZIP2ED)
  ------------------
  |  |   62|     30|#define Z_BZIP2ED 12
  ------------------
  |  Branch (1662:18): [True: 0, False: 30]
  ------------------
 1663|      0|        {
 1664|       |#ifdef HAVE_BZIP2
 1665|       |            uLong uTotalOutBefore,uTotalOutAfter;
 1666|       |            const Bytef *bufBefore;
 1667|       |            uLong uOutThis;
 1668|       |
 1669|       |            pfile_in_zip_read_info->bstream.next_in        = (char*)pfile_in_zip_read_info->stream.next_in;
 1670|       |            pfile_in_zip_read_info->bstream.avail_in       = pfile_in_zip_read_info->stream.avail_in;
 1671|       |            pfile_in_zip_read_info->bstream.total_in_lo32  = pfile_in_zip_read_info->stream.total_in;
 1672|       |            pfile_in_zip_read_info->bstream.total_in_hi32  = 0;
 1673|       |            pfile_in_zip_read_info->bstream.next_out       = (char*)pfile_in_zip_read_info->stream.next_out;
 1674|       |            pfile_in_zip_read_info->bstream.avail_out      = pfile_in_zip_read_info->stream.avail_out;
 1675|       |            pfile_in_zip_read_info->bstream.total_out_lo32 = pfile_in_zip_read_info->stream.total_out;
 1676|       |            pfile_in_zip_read_info->bstream.total_out_hi32 = 0;
 1677|       |
 1678|       |            uTotalOutBefore = pfile_in_zip_read_info->bstream.total_out_lo32;
 1679|       |            bufBefore = (const Bytef *)pfile_in_zip_read_info->bstream.next_out;
 1680|       |
 1681|       |            err=BZ2_bzDecompress(&pfile_in_zip_read_info->bstream);
 1682|       |
 1683|       |            uTotalOutAfter = pfile_in_zip_read_info->bstream.total_out_lo32;
 1684|       |            uOutThis = uTotalOutAfter-uTotalOutBefore;
 1685|       |
 1686|       |            pfile_in_zip_read_info->total_out_64 = pfile_in_zip_read_info->total_out_64 + uOutThis;
 1687|       |
 1688|       |            pfile_in_zip_read_info->crc32 = crc32(pfile_in_zip_read_info->crc32,bufBefore, (uInt)(uOutThis));
 1689|       |            pfile_in_zip_read_info->rest_read_uncompressed -= uOutThis;
 1690|       |            iRead += (uInt)(uTotalOutAfter - uTotalOutBefore);
 1691|       |
 1692|       |            pfile_in_zip_read_info->stream.next_in   = (Bytef*)pfile_in_zip_read_info->bstream.next_in;
 1693|       |            pfile_in_zip_read_info->stream.avail_in  = pfile_in_zip_read_info->bstream.avail_in;
 1694|       |            pfile_in_zip_read_info->stream.total_in  = pfile_in_zip_read_info->bstream.total_in_lo32;
 1695|       |            pfile_in_zip_read_info->stream.next_out  = (Bytef*)pfile_in_zip_read_info->bstream.next_out;
 1696|       |            pfile_in_zip_read_info->stream.avail_out = pfile_in_zip_read_info->bstream.avail_out;
 1697|       |            pfile_in_zip_read_info->stream.total_out = pfile_in_zip_read_info->bstream.total_out_lo32;
 1698|       |
 1699|       |            if (err==BZ_STREAM_END)
 1700|       |              return (iRead==0) ? UNZ_EOF : iRead;
 1701|       |            if (err!=BZ_OK)
 1702|       |              break;
 1703|       |#endif
 1704|      0|        } // end Z_BZIP2ED
 1705|     30|        else
 1706|     30|        {
 1707|     30|            ZPOS64_T uTotalOutBefore,uTotalOutAfter;
 1708|     30|            const Bytef *bufBefore;
 1709|     30|            ZPOS64_T uOutThis;
 1710|     30|            int flush=Z_SYNC_FLUSH;
  ------------------
  |  |  170|     30|#define Z_SYNC_FLUSH    2
  ------------------
 1711|       |
 1712|     30|            uTotalOutBefore = pfile_in_zip_read_info->stream.total_out;
 1713|     30|            bufBefore = pfile_in_zip_read_info->stream.next_out;
 1714|       |
 1715|       |            /*
 1716|       |            if ((pfile_in_zip_read_info->rest_read_uncompressed ==
 1717|       |                     pfile_in_zip_read_info->stream.avail_out) &&
 1718|       |                (pfile_in_zip_read_info->rest_read_compressed == 0))
 1719|       |                flush = Z_FINISH;
 1720|       |            */
 1721|     30|            err=inflate(&pfile_in_zip_read_info->stream,flush);
 1722|       |
 1723|     30|            if ((err>=0) && (pfile_in_zip_read_info->stream.msg!=NULL))
  ------------------
  |  Branch (1723:17): [True: 30, False: 0]
  |  Branch (1723:29): [True: 0, False: 30]
  ------------------
 1724|      0|              err = Z_DATA_ERROR;
  ------------------
  |  |  182|      0|#define Z_DATA_ERROR   (-3)
  ------------------
 1725|       |
 1726|     30|            uTotalOutAfter = pfile_in_zip_read_info->stream.total_out;
 1727|       |            /* Detect overflow, because z_stream.total_out is uLong (32 bits) */
 1728|     30|            if (uTotalOutAfter<uTotalOutBefore)
  ------------------
  |  Branch (1728:17): [True: 0, False: 30]
  ------------------
 1729|      0|                uTotalOutAfter += 1LL << 32; /* Add maximum value of uLong + 1 */
 1730|     30|            uOutThis = uTotalOutAfter-uTotalOutBefore;
 1731|       |
 1732|     30|            pfile_in_zip_read_info->total_out_64 = pfile_in_zip_read_info->total_out_64 + uOutThis;
 1733|       |
 1734|     30|            pfile_in_zip_read_info->crc32 =
 1735|     30|                crc32(pfile_in_zip_read_info->crc32,bufBefore,
 1736|     30|                        (uInt)(uOutThis));
 1737|       |
 1738|     30|            pfile_in_zip_read_info->rest_read_uncompressed -=
 1739|     30|                uOutThis;
 1740|       |
 1741|     30|            iRead += (uInt)(uTotalOutAfter - uTotalOutBefore);
 1742|       |
 1743|     30|            if (err==Z_STREAM_END)
  ------------------
  |  |  178|     30|#define Z_STREAM_END    1
  ------------------
  |  Branch (1743:17): [True: 8, False: 22]
  ------------------
 1744|      8|                return (iRead==0) ? UNZ_EOF : (int)iRead;
  ------------------
  |  |   77|      0|#define UNZ_EOF                         (0)
  ------------------
  |  Branch (1744:24): [True: 0, False: 8]
  ------------------
 1745|     22|            if (err!=Z_OK)
  ------------------
  |  |  177|     22|#define Z_OK            0
  ------------------
  |  Branch (1745:17): [True: 0, False: 22]
  ------------------
 1746|      0|                break;
 1747|     22|        }
 1748|     30|    }
 1749|       |
 1750|      8|    if (err==Z_OK)
  ------------------
  |  |  177|      8|#define Z_OK            0
  ------------------
  |  Branch (1750:9): [True: 8, False: 0]
  ------------------
 1751|      8|        return (int)iRead;
 1752|      0|    return err;
 1753|      8|}
unzCloseCurrentFile:
 1870|      8|extern int ZEXPORT unzCloseCurrentFile(unzFile file) {
 1871|      8|    int err=UNZ_OK;
  ------------------
  |  |   74|      8|#define UNZ_OK                          (0)
  ------------------
 1872|       |
 1873|      8|    unz64_s* s;
 1874|      8|    file_in_zip64_read_info_s* pfile_in_zip_read_info;
 1875|      8|    if (file==NULL)
  ------------------
  |  Branch (1875:9): [True: 0, False: 8]
  ------------------
 1876|      0|        return UNZ_PARAMERROR;
  ------------------
  |  |   78|      0|#define UNZ_PARAMERROR                  (-102)
  ------------------
 1877|      8|    s=(unz64_s*)file;
 1878|      8|    pfile_in_zip_read_info=s->pfile_in_zip_read;
 1879|       |
 1880|      8|    if (pfile_in_zip_read_info==NULL)
  ------------------
  |  Branch (1880:9): [True: 0, False: 8]
  ------------------
 1881|      0|        return UNZ_PARAMERROR;
  ------------------
  |  |   78|      0|#define UNZ_PARAMERROR                  (-102)
  ------------------
 1882|       |
 1883|       |
 1884|      8|    if ((pfile_in_zip_read_info->rest_read_uncompressed == 0) &&
  ------------------
  |  Branch (1884:9): [True: 8, False: 0]
  ------------------
 1885|      8|        (!pfile_in_zip_read_info->raw))
  ------------------
  |  Branch (1885:9): [True: 8, False: 0]
  ------------------
 1886|      8|    {
 1887|      8|        if (pfile_in_zip_read_info->crc32 != pfile_in_zip_read_info->crc32_wait)
  ------------------
  |  Branch (1887:13): [True: 0, False: 8]
  ------------------
 1888|      0|            err=UNZ_CRCERROR;
  ------------------
  |  |   81|      0|#define UNZ_CRCERROR                    (-105)
  ------------------
 1889|      8|    }
 1890|       |
 1891|       |
 1892|      8|    free(pfile_in_zip_read_info->read_buffer);
 1893|      8|    pfile_in_zip_read_info->read_buffer = NULL;
 1894|      8|    if (pfile_in_zip_read_info->stream_initialised == Z_DEFLATED)
  ------------------
  |  |  209|      8|#define Z_DEFLATED   8
  ------------------
  |  Branch (1894:9): [True: 8, False: 0]
  ------------------
 1895|      8|        inflateEnd(&pfile_in_zip_read_info->stream);
 1896|       |#ifdef HAVE_BZIP2
 1897|       |    else if (pfile_in_zip_read_info->stream_initialised == Z_BZIP2ED)
 1898|       |        BZ2_bzDecompressEnd(&pfile_in_zip_read_info->bstream);
 1899|       |#endif
 1900|       |
 1901|       |
 1902|      8|    pfile_in_zip_read_info->stream_initialised = 0;
 1903|      8|    free(pfile_in_zip_read_info);
 1904|       |
 1905|      8|    s->pfile_in_zip_read=NULL;
 1906|       |
 1907|      8|    return err;
 1908|      8|}
unzip.c:unzOpenInternal:
  494|    401|                              int is64bitOpenFunction) {
  495|    401|    unz64_s us;
  496|    401|    unz64_s *s;
  497|    401|    ZPOS64_T central_pos;
  498|    401|    uLong   uL;
  499|       |
  500|    401|    uLong number_disk;          /* number of the current disk, used for
  501|       |                                   spanning ZIP, unsupported, always 0*/
  502|    401|    uLong number_disk_with_CD;  /* number the disk with central dir, used
  503|       |                                   for spanning ZIP, unsupported, always 0*/
  504|    401|    ZPOS64_T number_entry_CD;      /* total number of entries in
  505|       |                                   the central dir
  506|       |                                   (same than number_entry on nospan) */
  507|       |
  508|    401|    int err=UNZ_OK;
  ------------------
  |  |   74|    401|#define UNZ_OK                          (0)
  ------------------
  509|       |
  510|    401|    if (unz_copyright[0]!=' ')
  ------------------
  |  Branch (510:9): [Folded, False: 401]
  ------------------
  511|      0|        return NULL;
  512|       |
  513|    401|    us.z_filefunc.zseek32_file = NULL;
  514|    401|    us.z_filefunc.ztell32_file = NULL;
  515|    401|    if (pzlib_filefunc64_32_def==NULL)
  ------------------
  |  Branch (515:9): [True: 0, False: 401]
  ------------------
  516|      0|        fill_fopen64_filefunc(&us.z_filefunc.zfile_func64);
  517|    401|    else
  518|    401|        us.z_filefunc = *pzlib_filefunc64_32_def;
  519|    401|    us.is64bitOpenFunction = is64bitOpenFunction;
  520|       |
  521|       |
  522|       |
  523|    401|    us.filestream = ZOPEN64(us.z_filefunc,
  ------------------
  |  |  202|    401|#define ZOPEN64(filefunc,filename,mode)         (call_zopen64((&(filefunc)),(filename),(mode)))
  ------------------
  524|    401|                                                 path,
  525|    401|                                                 ZLIB_FILEFUNC_MODE_READ |
  526|    401|                                                 ZLIB_FILEFUNC_MODE_EXISTING);
  527|    401|    if (us.filestream==NULL)
  ------------------
  |  Branch (527:9): [True: 0, False: 401]
  ------------------
  528|      0|        return NULL;
  529|       |
  530|    401|    central_pos = unz64local_SearchCentralDir64(&us.z_filefunc,us.filestream);
  531|    401|    if (central_pos!=CENTRALDIRINVALID)
  ------------------
  |  |  320|    401|#define CENTRALDIRINVALID ((ZPOS64_T)(-1))
  ------------------
  |  Branch (531:9): [True: 0, False: 401]
  ------------------
  532|      0|    {
  533|      0|        uLong uS;
  534|      0|        ZPOS64_T uL64;
  535|       |
  536|      0|        us.isZip64 = 1;
  537|       |
  538|      0|        if (ZSEEK64(us.z_filefunc, us.filestream,
  ------------------
  |  |  204|      0|#define ZSEEK64(filefunc,filestream,pos,mode)   (call_zseek64((&(filefunc)),(filestream),(pos),(mode)))
  ------------------
  |  Branch (538:13): [True: 0, False: 0]
  ------------------
  539|      0|                                      central_pos,ZLIB_FILEFUNC_SEEK_SET)!=0)
  540|      0|        err=UNZ_ERRNO;
  ------------------
  |  |   76|      0|#define UNZ_ERRNO                       (Z_ERRNO)
  |  |  ------------------
  |  |  |  |  180|      0|#define Z_ERRNO        (-1)
  |  |  ------------------
  ------------------
  541|       |
  542|       |        /* the signature, already checked */
  543|      0|        if (unz64local_getLong(&us.z_filefunc, us.filestream,&uL)!=UNZ_OK)
  ------------------
  |  |   74|      0|#define UNZ_OK                          (0)
  ------------------
  |  Branch (543:13): [True: 0, False: 0]
  ------------------
  544|      0|            err=UNZ_ERRNO;
  ------------------
  |  |   76|      0|#define UNZ_ERRNO                       (Z_ERRNO)
  |  |  ------------------
  |  |  |  |  180|      0|#define Z_ERRNO        (-1)
  |  |  ------------------
  ------------------
  545|       |
  546|       |        /* size of zip64 end of central directory record */
  547|      0|        if (unz64local_getLong64(&us.z_filefunc, us.filestream,&uL64)!=UNZ_OK)
  ------------------
  |  |   74|      0|#define UNZ_OK                          (0)
  ------------------
  |  Branch (547:13): [True: 0, False: 0]
  ------------------
  548|      0|            err=UNZ_ERRNO;
  ------------------
  |  |   76|      0|#define UNZ_ERRNO                       (Z_ERRNO)
  |  |  ------------------
  |  |  |  |  180|      0|#define Z_ERRNO        (-1)
  |  |  ------------------
  ------------------
  549|       |
  550|       |        /* version made by */
  551|      0|        if (unz64local_getShort(&us.z_filefunc, us.filestream,&uS)!=UNZ_OK)
  ------------------
  |  |   74|      0|#define UNZ_OK                          (0)
  ------------------
  |  Branch (551:13): [True: 0, False: 0]
  ------------------
  552|      0|            err=UNZ_ERRNO;
  ------------------
  |  |   76|      0|#define UNZ_ERRNO                       (Z_ERRNO)
  |  |  ------------------
  |  |  |  |  180|      0|#define Z_ERRNO        (-1)
  |  |  ------------------
  ------------------
  553|       |
  554|       |        /* version needed to extract */
  555|      0|        if (unz64local_getShort(&us.z_filefunc, us.filestream,&uS)!=UNZ_OK)
  ------------------
  |  |   74|      0|#define UNZ_OK                          (0)
  ------------------
  |  Branch (555:13): [True: 0, False: 0]
  ------------------
  556|      0|            err=UNZ_ERRNO;
  ------------------
  |  |   76|      0|#define UNZ_ERRNO                       (Z_ERRNO)
  |  |  ------------------
  |  |  |  |  180|      0|#define Z_ERRNO        (-1)
  |  |  ------------------
  ------------------
  557|       |
  558|       |        /* number of this disk */
  559|      0|        if (unz64local_getLong(&us.z_filefunc, us.filestream,&number_disk)!=UNZ_OK)
  ------------------
  |  |   74|      0|#define UNZ_OK                          (0)
  ------------------
  |  Branch (559:13): [True: 0, False: 0]
  ------------------
  560|      0|            err=UNZ_ERRNO;
  ------------------
  |  |   76|      0|#define UNZ_ERRNO                       (Z_ERRNO)
  |  |  ------------------
  |  |  |  |  180|      0|#define Z_ERRNO        (-1)
  |  |  ------------------
  ------------------
  561|       |
  562|       |        /* number of the disk with the start of the central directory */
  563|      0|        if (unz64local_getLong(&us.z_filefunc, us.filestream,&number_disk_with_CD)!=UNZ_OK)
  ------------------
  |  |   74|      0|#define UNZ_OK                          (0)
  ------------------
  |  Branch (563:13): [True: 0, False: 0]
  ------------------
  564|      0|            err=UNZ_ERRNO;
  ------------------
  |  |   76|      0|#define UNZ_ERRNO                       (Z_ERRNO)
  |  |  ------------------
  |  |  |  |  180|      0|#define Z_ERRNO        (-1)
  |  |  ------------------
  ------------------
  565|       |
  566|       |        /* total number of entries in the central directory on this disk */
  567|      0|        if (unz64local_getLong64(&us.z_filefunc, us.filestream,&us.gi.number_entry)!=UNZ_OK)
  ------------------
  |  |   74|      0|#define UNZ_OK                          (0)
  ------------------
  |  Branch (567:13): [True: 0, False: 0]
  ------------------
  568|      0|            err=UNZ_ERRNO;
  ------------------
  |  |   76|      0|#define UNZ_ERRNO                       (Z_ERRNO)
  |  |  ------------------
  |  |  |  |  180|      0|#define Z_ERRNO        (-1)
  |  |  ------------------
  ------------------
  569|       |
  570|       |        /* total number of entries in the central directory */
  571|      0|        if (unz64local_getLong64(&us.z_filefunc, us.filestream,&number_entry_CD)!=UNZ_OK)
  ------------------
  |  |   74|      0|#define UNZ_OK                          (0)
  ------------------
  |  Branch (571:13): [True: 0, False: 0]
  ------------------
  572|      0|            err=UNZ_ERRNO;
  ------------------
  |  |   76|      0|#define UNZ_ERRNO                       (Z_ERRNO)
  |  |  ------------------
  |  |  |  |  180|      0|#define Z_ERRNO        (-1)
  |  |  ------------------
  ------------------
  573|       |
  574|      0|        if ((number_entry_CD!=us.gi.number_entry) ||
  ------------------
  |  Branch (574:13): [True: 0, False: 0]
  ------------------
  575|      0|            (number_disk_with_CD!=0) ||
  ------------------
  |  Branch (575:13): [True: 0, False: 0]
  ------------------
  576|      0|            (number_disk!=0))
  ------------------
  |  Branch (576:13): [True: 0, False: 0]
  ------------------
  577|      0|            err=UNZ_BADZIPFILE;
  ------------------
  |  |   79|      0|#define UNZ_BADZIPFILE                  (-103)
  ------------------
  578|       |
  579|       |        /* size of the central directory */
  580|      0|        if (unz64local_getLong64(&us.z_filefunc, us.filestream,&us.size_central_dir)!=UNZ_OK)
  ------------------
  |  |   74|      0|#define UNZ_OK                          (0)
  ------------------
  |  Branch (580:13): [True: 0, False: 0]
  ------------------
  581|      0|            err=UNZ_ERRNO;
  ------------------
  |  |   76|      0|#define UNZ_ERRNO                       (Z_ERRNO)
  |  |  ------------------
  |  |  |  |  180|      0|#define Z_ERRNO        (-1)
  |  |  ------------------
  ------------------
  582|       |
  583|       |        /* offset of start of central directory with respect to the
  584|       |          starting disk number */
  585|      0|        if (unz64local_getLong64(&us.z_filefunc, us.filestream,&us.offset_central_dir)!=UNZ_OK)
  ------------------
  |  |   74|      0|#define UNZ_OK                          (0)
  ------------------
  |  Branch (585:13): [True: 0, False: 0]
  ------------------
  586|      0|            err=UNZ_ERRNO;
  ------------------
  |  |   76|      0|#define UNZ_ERRNO                       (Z_ERRNO)
  |  |  ------------------
  |  |  |  |  180|      0|#define Z_ERRNO        (-1)
  |  |  ------------------
  ------------------
  587|       |
  588|      0|        us.gi.size_comment = 0;
  589|      0|    }
  590|    401|    else
  591|    401|    {
  592|    401|        central_pos = unz64local_SearchCentralDir(&us.z_filefunc,us.filestream);
  593|    401|        if (central_pos==CENTRALDIRINVALID)
  ------------------
  |  |  320|    401|#define CENTRALDIRINVALID ((ZPOS64_T)(-1))
  ------------------
  |  Branch (593:13): [True: 372, False: 29]
  ------------------
  594|    372|            err=UNZ_ERRNO;
  ------------------
  |  |   76|    372|#define UNZ_ERRNO                       (Z_ERRNO)
  |  |  ------------------
  |  |  |  |  180|    372|#define Z_ERRNO        (-1)
  |  |  ------------------
  ------------------
  595|       |
  596|    401|        us.isZip64 = 0;
  597|       |
  598|    401|        if (ZSEEK64(us.z_filefunc, us.filestream,
  ------------------
  |  |  204|    401|#define ZSEEK64(filefunc,filestream,pos,mode)   (call_zseek64((&(filefunc)),(filestream),(pos),(mode)))
  ------------------
  |  Branch (598:13): [True: 372, False: 29]
  ------------------
  599|    401|                                        central_pos,ZLIB_FILEFUNC_SEEK_SET)!=0)
  600|    372|            err=UNZ_ERRNO;
  ------------------
  |  |   76|    372|#define UNZ_ERRNO                       (Z_ERRNO)
  |  |  ------------------
  |  |  |  |  180|    372|#define Z_ERRNO        (-1)
  |  |  ------------------
  ------------------
  601|       |
  602|       |        /* the signature, already checked */
  603|    401|        if (unz64local_getLong(&us.z_filefunc, us.filestream,&uL)!=UNZ_OK)
  ------------------
  |  |   74|    401|#define UNZ_OK                          (0)
  ------------------
  |  Branch (603:13): [True: 0, False: 401]
  ------------------
  604|      0|            err=UNZ_ERRNO;
  ------------------
  |  |   76|      0|#define UNZ_ERRNO                       (Z_ERRNO)
  |  |  ------------------
  |  |  |  |  180|      0|#define Z_ERRNO        (-1)
  |  |  ------------------
  ------------------
  605|       |
  606|       |        /* number of this disk */
  607|    401|        if (unz64local_getShort(&us.z_filefunc, us.filestream,&number_disk)!=UNZ_OK)
  ------------------
  |  |   74|    401|#define UNZ_OK                          (0)
  ------------------
  |  Branch (607:13): [True: 0, False: 401]
  ------------------
  608|      0|            err=UNZ_ERRNO;
  ------------------
  |  |   76|      0|#define UNZ_ERRNO                       (Z_ERRNO)
  |  |  ------------------
  |  |  |  |  180|      0|#define Z_ERRNO        (-1)
  |  |  ------------------
  ------------------
  609|       |
  610|       |        /* number of the disk with the start of the central directory */
  611|    401|        if (unz64local_getShort(&us.z_filefunc, us.filestream,&number_disk_with_CD)!=UNZ_OK)
  ------------------
  |  |   74|    401|#define UNZ_OK                          (0)
  ------------------
  |  Branch (611:13): [True: 0, False: 401]
  ------------------
  612|      0|            err=UNZ_ERRNO;
  ------------------
  |  |   76|      0|#define UNZ_ERRNO                       (Z_ERRNO)
  |  |  ------------------
  |  |  |  |  180|      0|#define Z_ERRNO        (-1)
  |  |  ------------------
  ------------------
  613|       |
  614|       |        /* total number of entries in the central dir on this disk */
  615|    401|        if (unz64local_getShort(&us.z_filefunc, us.filestream,&uL)!=UNZ_OK)
  ------------------
  |  |   74|    401|#define UNZ_OK                          (0)
  ------------------
  |  Branch (615:13): [True: 0, False: 401]
  ------------------
  616|      0|            err=UNZ_ERRNO;
  ------------------
  |  |   76|      0|#define UNZ_ERRNO                       (Z_ERRNO)
  |  |  ------------------
  |  |  |  |  180|      0|#define Z_ERRNO        (-1)
  |  |  ------------------
  ------------------
  617|    401|        us.gi.number_entry = uL;
  618|       |
  619|       |        /* total number of entries in the central dir */
  620|    401|        if (unz64local_getShort(&us.z_filefunc, us.filestream,&uL)!=UNZ_OK)
  ------------------
  |  |   74|    401|#define UNZ_OK                          (0)
  ------------------
  |  Branch (620:13): [True: 0, False: 401]
  ------------------
  621|      0|            err=UNZ_ERRNO;
  ------------------
  |  |   76|      0|#define UNZ_ERRNO                       (Z_ERRNO)
  |  |  ------------------
  |  |  |  |  180|      0|#define Z_ERRNO        (-1)
  |  |  ------------------
  ------------------
  622|    401|        number_entry_CD = uL;
  623|       |
  624|    401|        if ((number_entry_CD!=us.gi.number_entry) ||
  ------------------
  |  Branch (624:13): [True: 292, False: 109]
  ------------------
  625|    109|            (number_disk_with_CD!=0) ||
  ------------------
  |  Branch (625:13): [True: 64, False: 45]
  ------------------
  626|     45|            (number_disk!=0))
  ------------------
  |  Branch (626:13): [True: 0, False: 45]
  ------------------
  627|    356|            err=UNZ_BADZIPFILE;
  ------------------
  |  |   79|    356|#define UNZ_BADZIPFILE                  (-103)
  ------------------
  628|       |
  629|       |        /* size of the central directory */
  630|    401|        if (unz64local_getLong(&us.z_filefunc, us.filestream,&uL)!=UNZ_OK)
  ------------------
  |  |   74|    401|#define UNZ_OK                          (0)
  ------------------
  |  Branch (630:13): [True: 0, False: 401]
  ------------------
  631|      0|            err=UNZ_ERRNO;
  ------------------
  |  |   76|      0|#define UNZ_ERRNO                       (Z_ERRNO)
  |  |  ------------------
  |  |  |  |  180|      0|#define Z_ERRNO        (-1)
  |  |  ------------------
  ------------------
  632|    401|        us.size_central_dir = uL;
  633|       |
  634|       |        /* offset of start of central directory with respect to the
  635|       |            starting disk number */
  636|    401|        if (unz64local_getLong(&us.z_filefunc, us.filestream,&uL)!=UNZ_OK)
  ------------------
  |  |   74|    401|#define UNZ_OK                          (0)
  ------------------
  |  Branch (636:13): [True: 0, False: 401]
  ------------------
  637|      0|            err=UNZ_ERRNO;
  ------------------
  |  |   76|      0|#define UNZ_ERRNO                       (Z_ERRNO)
  |  |  ------------------
  |  |  |  |  180|      0|#define Z_ERRNO        (-1)
  |  |  ------------------
  ------------------
  638|    401|        us.offset_central_dir = uL;
  639|       |
  640|       |        /* zipfile comment length */
  641|    401|        if (unz64local_getShort(&us.z_filefunc, us.filestream,&us.gi.size_comment)!=UNZ_OK)
  ------------------
  |  |   74|    401|#define UNZ_OK                          (0)
  ------------------
  |  Branch (641:13): [True: 0, False: 401]
  ------------------
  642|      0|            err=UNZ_ERRNO;
  ------------------
  |  |   76|      0|#define UNZ_ERRNO                       (Z_ERRNO)
  |  |  ------------------
  |  |  |  |  180|      0|#define Z_ERRNO        (-1)
  |  |  ------------------
  ------------------
  643|    401|    }
  644|       |
  645|    401|    if ((central_pos<us.offset_central_dir+us.size_central_dir) &&
  ------------------
  |  Branch (645:9): [True: 0, False: 401]
  ------------------
  646|      0|        (err==UNZ_OK))
  ------------------
  |  |   74|      0|#define UNZ_OK                          (0)
  ------------------
  |  Branch (646:9): [True: 0, False: 0]
  ------------------
  647|      0|        err=UNZ_BADZIPFILE;
  ------------------
  |  |   79|      0|#define UNZ_BADZIPFILE                  (-103)
  ------------------
  648|       |
  649|    401|    if (err!=UNZ_OK)
  ------------------
  |  |   74|    401|#define UNZ_OK                          (0)
  ------------------
  |  Branch (649:9): [True: 374, False: 27]
  ------------------
  650|    374|    {
  651|    374|        ZCLOSE64(us.z_filefunc, us.filestream);
  ------------------
  |  |  193|    374|#define ZCLOSE64(filefunc,filestream)             ((*((filefunc).zfile_func64.zclose_file))  ((filefunc).zfile_func64.opaque,filestream))
  ------------------
  652|    374|        return NULL;
  653|    374|    }
  654|       |
  655|     27|    us.byte_before_the_zipfile = central_pos -
  656|     27|                            (us.offset_central_dir+us.size_central_dir);
  657|     27|    us.central_pos = central_pos;
  658|     27|    us.pfile_in_zip_read = NULL;
  659|     27|    us.encrypted = 0;
  660|       |
  661|       |
  662|     27|    s=(unz64_s*)ALLOC(sizeof(unz64_s));
  ------------------
  |  |  110|     27|# define ALLOC(size) (malloc(size))
  ------------------
  663|     27|    if( s != NULL)
  ------------------
  |  Branch (663:9): [True: 27, False: 0]
  ------------------
  664|     27|    {
  665|     27|        *s=us;
  666|     27|        unzGoToFirstFile((unzFile)s);
  667|     27|    }
  668|     27|    return (unzFile)s;
  669|    401|}
unzip.c:unz64local_SearchCentralDir64:
  388|    401|                                             voidpf filestream) {
  389|    401|    unsigned char* buf;
  390|    401|    ZPOS64_T uSizeFile;
  391|    401|    ZPOS64_T uBackRead;
  392|    401|    ZPOS64_T uMaxBack=0xffff; /* maximum size of global comment */
  393|    401|    ZPOS64_T uPosFound=CENTRALDIRINVALID;
  ------------------
  |  |  320|    401|#define CENTRALDIRINVALID ((ZPOS64_T)(-1))
  ------------------
  394|    401|    uLong uL;
  395|    401|                ZPOS64_T relativeOffset;
  396|       |
  397|    401|    if (ZSEEK64(*pzlib_filefunc_def,filestream,0,ZLIB_FILEFUNC_SEEK_END) != 0)
  ------------------
  |  |  204|    401|#define ZSEEK64(filefunc,filestream,pos,mode)   (call_zseek64((&(filefunc)),(filestream),(pos),(mode)))
  ------------------
  |  Branch (397:9): [True: 0, False: 401]
  ------------------
  398|      0|        return CENTRALDIRINVALID;
  ------------------
  |  |  320|      0|#define CENTRALDIRINVALID ((ZPOS64_T)(-1))
  ------------------
  399|       |
  400|       |
  401|    401|    uSizeFile = ZTELL64(*pzlib_filefunc_def,filestream);
  ------------------
  |  |  203|    401|#define ZTELL64(filefunc,filestream)            (call_ztell64((&(filefunc)),(filestream)))
  ------------------
  402|       |
  403|    401|    if (uMaxBack>uSizeFile)
  ------------------
  |  Branch (403:9): [True: 235, False: 166]
  ------------------
  404|    235|        uMaxBack = uSizeFile;
  405|       |
  406|    401|    buf = (unsigned char*)ALLOC(BUFREADCOMMENT+4);
  ------------------
  |  |  110|    401|# define ALLOC(size) (malloc(size))
  ------------------
  407|    401|    if (buf==NULL)
  ------------------
  |  Branch (407:9): [True: 0, False: 401]
  ------------------
  408|      0|        return CENTRALDIRINVALID;
  ------------------
  |  |  320|      0|#define CENTRALDIRINVALID ((ZPOS64_T)(-1))
  ------------------
  409|       |
  410|    401|    uBackRead = 4;
  411|  16.9k|    while (uBackRead<uMaxBack)
  ------------------
  |  Branch (411:12): [True: 16.5k, False: 399]
  ------------------
  412|  16.5k|    {
  413|  16.5k|        uLong uReadSize;
  414|  16.5k|        ZPOS64_T uReadPos;
  415|  16.5k|        int i;
  416|  16.5k|        if (uBackRead+BUFREADCOMMENT>uMaxBack)
  ------------------
  |  |  316|  16.5k|#define BUFREADCOMMENT (0x400)
  ------------------
  |  Branch (416:13): [True: 398, False: 16.1k]
  ------------------
  417|    398|            uBackRead = uMaxBack;
  418|  16.1k|        else
  419|  16.1k|            uBackRead+=BUFREADCOMMENT;
  ------------------
  |  |  316|  16.1k|#define BUFREADCOMMENT (0x400)
  ------------------
  420|  16.5k|        uReadPos = uSizeFile-uBackRead ;
  421|       |
  422|  16.5k|        uReadSize = ((BUFREADCOMMENT+4) < (uSizeFile-uReadPos)) ?
  ------------------
  |  |  316|  16.5k|#define BUFREADCOMMENT (0x400)
  ------------------
  |  Branch (422:21): [True: 16.1k, False: 401]
  ------------------
  423|  16.1k|                     (BUFREADCOMMENT+4) : (uLong)(uSizeFile-uReadPos);
  ------------------
  |  |  316|  16.1k|#define BUFREADCOMMENT (0x400)
  ------------------
  424|  16.5k|        if (ZSEEK64(*pzlib_filefunc_def,filestream,uReadPos,ZLIB_FILEFUNC_SEEK_SET)!=0)
  ------------------
  |  |  204|  16.5k|#define ZSEEK64(filefunc,filestream,pos,mode)   (call_zseek64((&(filefunc)),(filestream),(pos),(mode)))
  ------------------
  |  Branch (424:13): [True: 0, False: 16.5k]
  ------------------
  425|      0|            break;
  426|       |
  427|  16.5k|        if (ZREAD64(*pzlib_filefunc_def,filestream,buf,uReadSize)!=uReadSize)
  ------------------
  |  |  189|  16.5k|#define ZREAD64(filefunc,filestream,buf,size)     ((*((filefunc).zfile_func64.zread_file))   ((filefunc).zfile_func64.opaque,filestream,buf,size))
  ------------------
  |  Branch (427:13): [True: 0, False: 16.5k]
  ------------------
  428|      0|            break;
  429|       |
  430|  16.9M|        for (i=(int)uReadSize-3; (i--)>0;)
  ------------------
  |  Branch (430:34): [True: 16.9M, False: 16.5k]
  ------------------
  431|  16.9M|            if (((*(buf+i))==0x50) && ((*(buf+i+1))==0x4b) &&
  ------------------
  |  Branch (431:17): [True: 23.4k, False: 16.9M]
  |  Branch (431:39): [True: 1.86k, False: 21.6k]
  ------------------
  432|  1.86k|                ((*(buf+i+2))==0x06) && ((*(buf+i+3))==0x07))
  ------------------
  |  Branch (432:17): [True: 2, False: 1.85k]
  |  Branch (432:41): [True: 2, False: 0]
  ------------------
  433|      2|            {
  434|      2|                uPosFound = uReadPos+(unsigned)i;
  435|      2|                break;
  436|      2|            }
  437|       |
  438|  16.5k|        if (uPosFound!=CENTRALDIRINVALID)
  ------------------
  |  |  320|  16.5k|#define CENTRALDIRINVALID ((ZPOS64_T)(-1))
  ------------------
  |  Branch (438:13): [True: 2, False: 16.5k]
  ------------------
  439|      2|            break;
  440|  16.5k|    }
  441|    401|    free(buf);
  442|    401|    if (uPosFound == CENTRALDIRINVALID)
  ------------------
  |  |  320|    401|#define CENTRALDIRINVALID ((ZPOS64_T)(-1))
  ------------------
  |  Branch (442:9): [True: 399, False: 2]
  ------------------
  443|    399|        return CENTRALDIRINVALID;
  ------------------
  |  |  320|    399|#define CENTRALDIRINVALID ((ZPOS64_T)(-1))
  ------------------
  444|       |
  445|       |    /* Zip64 end of central directory locator */
  446|      2|    if (ZSEEK64(*pzlib_filefunc_def,filestream, uPosFound,ZLIB_FILEFUNC_SEEK_SET)!=0)
  ------------------
  |  |  204|      2|#define ZSEEK64(filefunc,filestream,pos,mode)   (call_zseek64((&(filefunc)),(filestream),(pos),(mode)))
  ------------------
  |  Branch (446:9): [True: 0, False: 2]
  ------------------
  447|      0|        return CENTRALDIRINVALID;
  ------------------
  |  |  320|      0|#define CENTRALDIRINVALID ((ZPOS64_T)(-1))
  ------------------
  448|       |
  449|       |    /* the signature, already checked */
  450|      2|    if (unz64local_getLong(pzlib_filefunc_def,filestream,&uL)!=UNZ_OK)
  ------------------
  |  |   74|      2|#define UNZ_OK                          (0)
  ------------------
  |  Branch (450:9): [True: 0, False: 2]
  ------------------
  451|      0|        return CENTRALDIRINVALID;
  ------------------
  |  |  320|      0|#define CENTRALDIRINVALID ((ZPOS64_T)(-1))
  ------------------
  452|       |
  453|       |    /* number of the disk with the start of the zip64 end of central directory */
  454|      2|    if (unz64local_getLong(pzlib_filefunc_def,filestream,&uL)!=UNZ_OK)
  ------------------
  |  |   74|      2|#define UNZ_OK                          (0)
  ------------------
  |  Branch (454:9): [True: 0, False: 2]
  ------------------
  455|      0|        return CENTRALDIRINVALID;
  ------------------
  |  |  320|      0|#define CENTRALDIRINVALID ((ZPOS64_T)(-1))
  ------------------
  456|      2|    if (uL != 0)
  ------------------
  |  Branch (456:9): [True: 2, False: 0]
  ------------------
  457|      2|        return CENTRALDIRINVALID;
  ------------------
  |  |  320|      2|#define CENTRALDIRINVALID ((ZPOS64_T)(-1))
  ------------------
  458|       |
  459|       |    /* relative offset of the zip64 end of central directory record */
  460|      0|    if (unz64local_getLong64(pzlib_filefunc_def,filestream,&relativeOffset)!=UNZ_OK)
  ------------------
  |  |   74|      0|#define UNZ_OK                          (0)
  ------------------
  |  Branch (460:9): [True: 0, False: 0]
  ------------------
  461|      0|        return CENTRALDIRINVALID;
  ------------------
  |  |  320|      0|#define CENTRALDIRINVALID ((ZPOS64_T)(-1))
  ------------------
  462|       |
  463|       |    /* total number of disks */
  464|      0|    if (unz64local_getLong(pzlib_filefunc_def,filestream,&uL)!=UNZ_OK)
  ------------------
  |  |   74|      0|#define UNZ_OK                          (0)
  ------------------
  |  Branch (464:9): [True: 0, False: 0]
  ------------------
  465|      0|        return CENTRALDIRINVALID;
  ------------------
  |  |  320|      0|#define CENTRALDIRINVALID ((ZPOS64_T)(-1))
  ------------------
  466|      0|    if (uL != 1)
  ------------------
  |  Branch (466:9): [True: 0, False: 0]
  ------------------
  467|      0|        return CENTRALDIRINVALID;
  ------------------
  |  |  320|      0|#define CENTRALDIRINVALID ((ZPOS64_T)(-1))
  ------------------
  468|       |
  469|       |    /* Goto end of central directory record */
  470|      0|    if (ZSEEK64(*pzlib_filefunc_def,filestream, relativeOffset,ZLIB_FILEFUNC_SEEK_SET)!=0)
  ------------------
  |  |  204|      0|#define ZSEEK64(filefunc,filestream,pos,mode)   (call_zseek64((&(filefunc)),(filestream),(pos),(mode)))
  ------------------
  |  Branch (470:9): [True: 0, False: 0]
  ------------------
  471|      0|        return CENTRALDIRINVALID;
  ------------------
  |  |  320|      0|#define CENTRALDIRINVALID ((ZPOS64_T)(-1))
  ------------------
  472|       |
  473|       |     /* the signature */
  474|      0|    if (unz64local_getLong(pzlib_filefunc_def,filestream,&uL)!=UNZ_OK)
  ------------------
  |  |   74|      0|#define UNZ_OK                          (0)
  ------------------
  |  Branch (474:9): [True: 0, False: 0]
  ------------------
  475|      0|        return CENTRALDIRINVALID;
  ------------------
  |  |  320|      0|#define CENTRALDIRINVALID ((ZPOS64_T)(-1))
  ------------------
  476|       |
  477|      0|    if (uL != 0x06064b50)
  ------------------
  |  Branch (477:9): [True: 0, False: 0]
  ------------------
  478|      0|        return CENTRALDIRINVALID;
  ------------------
  |  |  320|      0|#define CENTRALDIRINVALID ((ZPOS64_T)(-1))
  ------------------
  479|       |
  480|      0|    return relativeOffset;
  481|      0|}
unzip.c:unz64local_getLong:
  222|  5.90k|                             uLong *pX) {
  223|  5.90k|    unsigned char c[4];
  224|  5.90k|    int err = (int)ZREAD64(*pzlib_filefunc_def,filestream,c,4);
  ------------------
  |  |  189|  5.90k|#define ZREAD64(filefunc,filestream,buf,size)     ((*((filefunc).zfile_func64.zread_file))   ((filefunc).zfile_func64.opaque,filestream,buf,size))
  ------------------
  225|  5.90k|    if (err==4)
  ------------------
  |  Branch (225:9): [True: 5.90k, False: 0]
  ------------------
  226|  5.90k|    {
  227|  5.90k|        *pX = c[0] | ((uLong)c[1] << 8) | ((uLong)c[2] << 16) | ((uLong)c[3] << 24);
  228|  5.90k|        return UNZ_OK;
  ------------------
  |  |   74|  5.90k|#define UNZ_OK                          (0)
  ------------------
  229|  5.90k|    }
  230|      0|    else
  231|      0|    {
  232|      0|        *pX = 0;
  233|      0|        if (ZERROR64(*pzlib_filefunc_def,filestream))
  ------------------
  |  |  194|      0|#define ZERROR64(filefunc,filestream)             ((*((filefunc).zfile_func64.zerror_file))  ((filefunc).zfile_func64.opaque,filestream))
  |  |  ------------------
  |  |  |  Branch (194:51): [True: 0, False: 0]
  |  |  ------------------
  ------------------
  234|      0|            return UNZ_ERRNO;
  ------------------
  |  |   76|      0|#define UNZ_ERRNO                       (Z_ERRNO)
  |  |  ------------------
  |  |  |  |  180|      0|#define Z_ERRNO        (-1)
  |  |  ------------------
  ------------------
  235|      0|        else
  236|      0|            return UNZ_EOF;
  ------------------
  |  |   77|      0|#define UNZ_EOF                         (0)
  ------------------
  237|      0|    }
  238|  5.90k|}
unzip.c:unz64local_getShort:
  202|  8.15k|                              uLong *pX) {
  203|  8.15k|    unsigned char c[2];
  204|  8.15k|    int err = (int)ZREAD64(*pzlib_filefunc_def,filestream,c,2);
  ------------------
  |  |  189|  8.15k|#define ZREAD64(filefunc,filestream,buf,size)     ((*((filefunc).zfile_func64.zread_file))   ((filefunc).zfile_func64.opaque,filestream,buf,size))
  ------------------
  205|  8.15k|    if (err==2)
  ------------------
  |  Branch (205:9): [True: 8.15k, False: 0]
  ------------------
  206|  8.15k|    {
  207|  8.15k|        *pX = c[0] | ((uLong)c[1] << 8);
  208|  8.15k|        return UNZ_OK;
  ------------------
  |  |   74|  8.15k|#define UNZ_OK                          (0)
  ------------------
  209|  8.15k|    }
  210|      0|    else
  211|      0|    {
  212|      0|        *pX = 0;
  213|      0|        if (ZERROR64(*pzlib_filefunc_def,filestream))
  ------------------
  |  |  194|      0|#define ZERROR64(filefunc,filestream)             ((*((filefunc).zfile_func64.zerror_file))  ((filefunc).zfile_func64.opaque,filestream))
  |  |  ------------------
  |  |  |  Branch (194:51): [True: 0, False: 0]
  |  |  ------------------
  ------------------
  214|      0|            return UNZ_ERRNO;
  ------------------
  |  |   76|      0|#define UNZ_ERRNO                       (Z_ERRNO)
  |  |  ------------------
  |  |  |  |  180|      0|#define Z_ERRNO        (-1)
  |  |  ------------------
  ------------------
  215|      0|        else
  216|      0|            return UNZ_EOF;
  ------------------
  |  |   77|      0|#define UNZ_EOF                         (0)
  ------------------
  217|      0|    }
  218|  8.15k|}
unzip.c:unz64local_SearchCentralDir:
  327|    401|local ZPOS64_T unz64local_SearchCentralDir(const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream) {
  328|    401|    unsigned char* buf;
  329|    401|    ZPOS64_T uSizeFile;
  330|    401|    ZPOS64_T uBackRead;
  331|    401|    ZPOS64_T uMaxBack=0xffff; /* maximum size of global comment */
  332|    401|    ZPOS64_T uPosFound=CENTRALDIRINVALID;
  ------------------
  |  |  320|    401|#define CENTRALDIRINVALID ((ZPOS64_T)(-1))
  ------------------
  333|       |
  334|    401|    if (ZSEEK64(*pzlib_filefunc_def,filestream,0,ZLIB_FILEFUNC_SEEK_END) != 0)
  ------------------
  |  |  204|    401|#define ZSEEK64(filefunc,filestream,pos,mode)   (call_zseek64((&(filefunc)),(filestream),(pos),(mode)))
  ------------------
  |  Branch (334:9): [True: 0, False: 401]
  ------------------
  335|      0|        return CENTRALDIRINVALID;
  ------------------
  |  |  320|      0|#define CENTRALDIRINVALID ((ZPOS64_T)(-1))
  ------------------
  336|       |
  337|       |
  338|    401|    uSizeFile = ZTELL64(*pzlib_filefunc_def,filestream);
  ------------------
  |  |  203|    401|#define ZTELL64(filefunc,filestream)            (call_ztell64((&(filefunc)),(filestream)))
  ------------------
  339|       |
  340|    401|    if (uMaxBack>uSizeFile)
  ------------------
  |  Branch (340:9): [True: 235, False: 166]
  ------------------
  341|    235|        uMaxBack = uSizeFile;
  342|       |
  343|    401|    buf = (unsigned char*)ALLOC(BUFREADCOMMENT+4);
  ------------------
  |  |  110|    401|# define ALLOC(size) (malloc(size))
  ------------------
  344|    401|    if (buf==NULL)
  ------------------
  |  Branch (344:9): [True: 0, False: 401]
  ------------------
  345|      0|        return CENTRALDIRINVALID;
  ------------------
  |  |  320|      0|#define CENTRALDIRINVALID ((ZPOS64_T)(-1))
  ------------------
  346|       |
  347|    401|    uBackRead = 4;
  348|  15.8k|    while (uBackRead<uMaxBack)
  ------------------
  |  Branch (348:12): [True: 15.4k, False: 372]
  ------------------
  349|  15.4k|    {
  350|  15.4k|        uLong uReadSize;
  351|  15.4k|        ZPOS64_T uReadPos ;
  352|  15.4k|        int i;
  353|  15.4k|        if (uBackRead+BUFREADCOMMENT>uMaxBack)
  ------------------
  |  |  316|  15.4k|#define BUFREADCOMMENT (0x400)
  ------------------
  |  Branch (353:13): [True: 371, False: 15.1k]
  ------------------
  354|    371|            uBackRead = uMaxBack;
  355|  15.1k|        else
  356|  15.1k|            uBackRead+=BUFREADCOMMENT;
  ------------------
  |  |  316|  15.1k|#define BUFREADCOMMENT (0x400)
  ------------------
  357|  15.4k|        uReadPos = uSizeFile-uBackRead ;
  358|       |
  359|  15.4k|        uReadSize = ((BUFREADCOMMENT+4) < (uSizeFile-uReadPos)) ?
  ------------------
  |  |  316|  15.4k|#define BUFREADCOMMENT (0x400)
  ------------------
  |  Branch (359:21): [True: 15.0k, False: 401]
  ------------------
  360|  15.0k|                     (BUFREADCOMMENT+4) : (uLong)(uSizeFile-uReadPos);
  ------------------
  |  |  316|  15.0k|#define BUFREADCOMMENT (0x400)
  ------------------
  361|  15.4k|        if (ZSEEK64(*pzlib_filefunc_def,filestream,uReadPos,ZLIB_FILEFUNC_SEEK_SET)!=0)
  ------------------
  |  |  204|  15.4k|#define ZSEEK64(filefunc,filestream,pos,mode)   (call_zseek64((&(filefunc)),(filestream),(pos),(mode)))
  ------------------
  |  Branch (361:13): [True: 0, False: 15.4k]
  ------------------
  362|      0|            break;
  363|       |
  364|  15.4k|        if (ZREAD64(*pzlib_filefunc_def,filestream,buf,uReadSize)!=uReadSize)
  ------------------
  |  |  189|  15.4k|#define ZREAD64(filefunc,filestream,buf,size)     ((*((filefunc).zfile_func64.zread_file))   ((filefunc).zfile_func64.opaque,filestream,buf,size))
  ------------------
  |  Branch (364:13): [True: 0, False: 15.4k]
  ------------------
  365|      0|            break;
  366|       |
  367|  15.8M|        for (i=(int)uReadSize-3; (i--)>0;)
  ------------------
  |  Branch (367:34): [True: 15.8M, False: 15.4k]
  ------------------
  368|  15.8M|            if (((*(buf+i))==0x50) && ((*(buf+i+1))==0x4b) &&
  ------------------
  |  Branch (368:17): [True: 18.6k, False: 15.8M]
  |  Branch (368:39): [True: 736, False: 17.9k]
  ------------------
  369|    736|                ((*(buf+i+2))==0x05) && ((*(buf+i+3))==0x06))
  ------------------
  |  Branch (369:17): [True: 29, False: 707]
  |  Branch (369:41): [True: 29, False: 0]
  ------------------
  370|     29|            {
  371|     29|                uPosFound = uReadPos+(unsigned)i;
  372|     29|                break;
  373|     29|            }
  374|       |
  375|  15.4k|        if (uPosFound!=CENTRALDIRINVALID)
  ------------------
  |  |  320|  15.4k|#define CENTRALDIRINVALID ((ZPOS64_T)(-1))
  ------------------
  |  Branch (375:13): [True: 29, False: 15.4k]
  ------------------
  376|     29|            break;
  377|  15.4k|    }
  378|    401|    free(buf);
  379|    401|    return uPosFound;
  380|    401|}
unzip.c:unz64local_GetCurrentFileInfoInternal:
  776|    664|                                                uLong commentBufferSize) {
  777|    664|    unz64_s* s;
  778|    664|    unz_file_info64 file_info;
  779|    664|    unz_file_info64_internal file_info_internal;
  780|    664|    int err=UNZ_OK;
  ------------------
  |  |   74|    664|#define UNZ_OK                          (0)
  ------------------
  781|    664|    uLong uMagic;
  782|    664|    long lSeek=0;
  783|    664|    uLong uL;
  784|       |
  785|    664|    if (file==NULL)
  ------------------
  |  Branch (785:9): [True: 0, False: 664]
  ------------------
  786|      0|        return UNZ_PARAMERROR;
  ------------------
  |  |   78|      0|#define UNZ_PARAMERROR                  (-102)
  ------------------
  787|    664|    s=(unz64_s*)file;
  788|    664|    if (ZSEEK64(s->z_filefunc, s->filestream,
  ------------------
  |  |  204|    664|#define ZSEEK64(filefunc,filestream,pos,mode)   (call_zseek64((&(filefunc)),(filestream),(pos),(mode)))
  ------------------
  |  Branch (788:9): [True: 0, False: 664]
  ------------------
  789|    664|              s->pos_in_central_dir+s->byte_before_the_zipfile,
  790|    664|              ZLIB_FILEFUNC_SEEK_SET)!=0)
  791|      0|        err=UNZ_ERRNO;
  ------------------
  |  |   76|      0|#define UNZ_ERRNO                       (Z_ERRNO)
  |  |  ------------------
  |  |  |  |  180|      0|#define Z_ERRNO        (-1)
  |  |  ------------------
  ------------------
  792|       |
  793|       |
  794|       |    /* we check the magic */
  795|    664|    if (err==UNZ_OK)
  ------------------
  |  |   74|    664|#define UNZ_OK                          (0)
  ------------------
  |  Branch (795:9): [True: 664, False: 0]
  ------------------
  796|    664|    {
  797|    664|        if (unz64local_getLong(&s->z_filefunc, s->filestream,&uMagic) != UNZ_OK)
  ------------------
  |  |   74|    664|#define UNZ_OK                          (0)
  ------------------
  |  Branch (797:13): [True: 0, False: 664]
  ------------------
  798|      0|            err=UNZ_ERRNO;
  ------------------
  |  |   76|      0|#define UNZ_ERRNO                       (Z_ERRNO)
  |  |  ------------------
  |  |  |  |  180|      0|#define Z_ERRNO        (-1)
  |  |  ------------------
  ------------------
  799|    664|        else if (uMagic!=0x02014b50)
  ------------------
  |  Branch (799:18): [True: 4, False: 660]
  ------------------
  800|      4|            err=UNZ_BADZIPFILE;
  ------------------
  |  |   79|      4|#define UNZ_BADZIPFILE                  (-103)
  ------------------
  801|    664|    }
  802|       |
  803|    664|    if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.version) != UNZ_OK)
  ------------------
  |  |   74|    664|#define UNZ_OK                          (0)
  ------------------
  |  Branch (803:9): [True: 0, False: 664]
  ------------------
  804|      0|        err=UNZ_ERRNO;
  ------------------
  |  |   76|      0|#define UNZ_ERRNO                       (Z_ERRNO)
  |  |  ------------------
  |  |  |  |  180|      0|#define Z_ERRNO        (-1)
  |  |  ------------------
  ------------------
  805|       |
  806|    664|    if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.version_needed) != UNZ_OK)
  ------------------
  |  |   74|    664|#define UNZ_OK                          (0)
  ------------------
  |  Branch (806:9): [True: 0, False: 664]
  ------------------
  807|      0|        err=UNZ_ERRNO;
  ------------------
  |  |   76|      0|#define UNZ_ERRNO                       (Z_ERRNO)
  |  |  ------------------
  |  |  |  |  180|      0|#define Z_ERRNO        (-1)
  |  |  ------------------
  ------------------
  808|       |
  809|    664|    if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.flag) != UNZ_OK)
  ------------------
  |  |   74|    664|#define UNZ_OK                          (0)
  ------------------
  |  Branch (809:9): [True: 0, False: 664]
  ------------------
  810|      0|        err=UNZ_ERRNO;
  ------------------
  |  |   76|      0|#define UNZ_ERRNO                       (Z_ERRNO)
  |  |  ------------------
  |  |  |  |  180|      0|#define Z_ERRNO        (-1)
  |  |  ------------------
  ------------------
  811|       |
  812|    664|    if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.compression_method) != UNZ_OK)
  ------------------
  |  |   74|    664|#define UNZ_OK                          (0)
  ------------------
  |  Branch (812:9): [True: 0, False: 664]
  ------------------
  813|      0|        err=UNZ_ERRNO;
  ------------------
  |  |   76|      0|#define UNZ_ERRNO                       (Z_ERRNO)
  |  |  ------------------
  |  |  |  |  180|      0|#define Z_ERRNO        (-1)
  |  |  ------------------
  ------------------
  814|       |
  815|    664|    if (unz64local_getLong(&s->z_filefunc, s->filestream,&file_info.dosDate) != UNZ_OK)
  ------------------
  |  |   74|    664|#define UNZ_OK                          (0)
  ------------------
  |  Branch (815:9): [True: 0, False: 664]
  ------------------
  816|      0|        err=UNZ_ERRNO;
  ------------------
  |  |   76|      0|#define UNZ_ERRNO                       (Z_ERRNO)
  |  |  ------------------
  |  |  |  |  180|      0|#define Z_ERRNO        (-1)
  |  |  ------------------
  ------------------
  817|       |
  818|    664|    unz64local_DosDateToTmuDate(file_info.dosDate,&file_info.tmu_date);
  819|       |
  820|    664|    if (unz64local_getLong(&s->z_filefunc, s->filestream,&file_info.crc) != UNZ_OK)
  ------------------
  |  |   74|    664|#define UNZ_OK                          (0)
  ------------------
  |  Branch (820:9): [True: 0, False: 664]
  ------------------
  821|      0|        err=UNZ_ERRNO;
  ------------------
  |  |   76|      0|#define UNZ_ERRNO                       (Z_ERRNO)
  |  |  ------------------
  |  |  |  |  180|      0|#define Z_ERRNO        (-1)
  |  |  ------------------
  ------------------
  822|       |
  823|    664|    if (unz64local_getLong(&s->z_filefunc, s->filestream,&uL) != UNZ_OK)
  ------------------
  |  |   74|    664|#define UNZ_OK                          (0)
  ------------------
  |  Branch (823:9): [True: 0, False: 664]
  ------------------
  824|      0|        err=UNZ_ERRNO;
  ------------------
  |  |   76|      0|#define UNZ_ERRNO                       (Z_ERRNO)
  |  |  ------------------
  |  |  |  |  180|      0|#define Z_ERRNO        (-1)
  |  |  ------------------
  ------------------
  825|    664|    file_info.compressed_size = uL;
  826|       |
  827|    664|    if (unz64local_getLong(&s->z_filefunc, s->filestream,&uL) != UNZ_OK)
  ------------------
  |  |   74|    664|#define UNZ_OK                          (0)
  ------------------
  |  Branch (827:9): [True: 0, False: 664]
  ------------------
  828|      0|        err=UNZ_ERRNO;
  ------------------
  |  |   76|      0|#define UNZ_ERRNO                       (Z_ERRNO)
  |  |  ------------------
  |  |  |  |  180|      0|#define Z_ERRNO        (-1)
  |  |  ------------------
  ------------------
  829|    664|    file_info.uncompressed_size = uL;
  830|       |
  831|    664|    if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.size_filename) != UNZ_OK)
  ------------------
  |  |   74|    664|#define UNZ_OK                          (0)
  ------------------
  |  Branch (831:9): [True: 0, False: 664]
  ------------------
  832|      0|        err=UNZ_ERRNO;
  ------------------
  |  |   76|      0|#define UNZ_ERRNO                       (Z_ERRNO)
  |  |  ------------------
  |  |  |  |  180|      0|#define Z_ERRNO        (-1)
  |  |  ------------------
  ------------------
  833|       |
  834|    664|    if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.size_file_extra) != UNZ_OK)
  ------------------
  |  |   74|    664|#define UNZ_OK                          (0)
  ------------------
  |  Branch (834:9): [True: 0, False: 664]
  ------------------
  835|      0|        err=UNZ_ERRNO;
  ------------------
  |  |   76|      0|#define UNZ_ERRNO                       (Z_ERRNO)
  |  |  ------------------
  |  |  |  |  180|      0|#define Z_ERRNO        (-1)
  |  |  ------------------
  ------------------
  836|       |
  837|    664|    if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.size_file_comment) != UNZ_OK)
  ------------------
  |  |   74|    664|#define UNZ_OK                          (0)
  ------------------
  |  Branch (837:9): [True: 0, False: 664]
  ------------------
  838|      0|        err=UNZ_ERRNO;
  ------------------
  |  |   76|      0|#define UNZ_ERRNO                       (Z_ERRNO)
  |  |  ------------------
  |  |  |  |  180|      0|#define Z_ERRNO        (-1)
  |  |  ------------------
  ------------------
  839|       |
  840|    664|    if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.disk_num_start) != UNZ_OK)
  ------------------
  |  |   74|    664|#define UNZ_OK                          (0)
  ------------------
  |  Branch (840:9): [True: 0, False: 664]
  ------------------
  841|      0|        err=UNZ_ERRNO;
  ------------------
  |  |   76|      0|#define UNZ_ERRNO                       (Z_ERRNO)
  |  |  ------------------
  |  |  |  |  180|      0|#define Z_ERRNO        (-1)
  |  |  ------------------
  ------------------
  842|       |
  843|    664|    if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.internal_fa) != UNZ_OK)
  ------------------
  |  |   74|    664|#define UNZ_OK                          (0)
  ------------------
  |  Branch (843:9): [True: 0, False: 664]
  ------------------
  844|      0|        err=UNZ_ERRNO;
  ------------------
  |  |   76|      0|#define UNZ_ERRNO                       (Z_ERRNO)
  |  |  ------------------
  |  |  |  |  180|      0|#define Z_ERRNO        (-1)
  |  |  ------------------
  ------------------
  845|       |
  846|    664|    if (unz64local_getLong(&s->z_filefunc, s->filestream,&file_info.external_fa) != UNZ_OK)
  ------------------
  |  |   74|    664|#define UNZ_OK                          (0)
  ------------------
  |  Branch (846:9): [True: 0, False: 664]
  ------------------
  847|      0|        err=UNZ_ERRNO;
  ------------------
  |  |   76|      0|#define UNZ_ERRNO                       (Z_ERRNO)
  |  |  ------------------
  |  |  |  |  180|      0|#define Z_ERRNO        (-1)
  |  |  ------------------
  ------------------
  848|       |
  849|       |                // relative offset of local header
  850|    664|    if (unz64local_getLong(&s->z_filefunc, s->filestream,&uL) != UNZ_OK)
  ------------------
  |  |   74|    664|#define UNZ_OK                          (0)
  ------------------
  |  Branch (850:9): [True: 0, False: 664]
  ------------------
  851|      0|        err=UNZ_ERRNO;
  ------------------
  |  |   76|      0|#define UNZ_ERRNO                       (Z_ERRNO)
  |  |  ------------------
  |  |  |  |  180|      0|#define Z_ERRNO        (-1)
  |  |  ------------------
  ------------------
  852|    664|    file_info_internal.offset_curfile = uL;
  853|       |
  854|    664|    lSeek+=file_info.size_filename;
  855|    664|    if ((err==UNZ_OK) && (szFileName!=NULL))
  ------------------
  |  |   74|    664|#define UNZ_OK                          (0)
  ------------------
  |  Branch (855:9): [True: 660, False: 4]
  |  Branch (855:26): [True: 312, False: 348]
  ------------------
  856|    312|    {
  857|    312|        uLong uSizeRead ;
  858|    312|        if (file_info.size_filename<fileNameBufferSize)
  ------------------
  |  Branch (858:13): [True: 312, False: 0]
  ------------------
  859|    312|        {
  860|    312|            *(szFileName+file_info.size_filename)='\0';
  861|    312|            uSizeRead = file_info.size_filename;
  862|    312|        }
  863|      0|        else
  864|      0|            uSizeRead = fileNameBufferSize;
  865|       |
  866|    312|        if ((file_info.size_filename>0) && (fileNameBufferSize>0))
  ------------------
  |  Branch (866:13): [True: 312, False: 0]
  |  Branch (866:44): [True: 312, False: 0]
  ------------------
  867|    312|            if (ZREAD64(s->z_filefunc, s->filestream,szFileName,uSizeRead)!=uSizeRead)
  ------------------
  |  |  189|    312|#define ZREAD64(filefunc,filestream,buf,size)     ((*((filefunc).zfile_func64.zread_file))   ((filefunc).zfile_func64.opaque,filestream,buf,size))
  ------------------
  |  Branch (867:17): [True: 0, False: 312]
  ------------------
  868|      0|                err=UNZ_ERRNO;
  ------------------
  |  |   76|      0|#define UNZ_ERRNO                       (Z_ERRNO)
  |  |  ------------------
  |  |  |  |  180|      0|#define Z_ERRNO        (-1)
  |  |  ------------------
  ------------------
  869|    312|        lSeek -= uSizeRead;
  870|    312|    }
  871|       |
  872|       |    // Read extrafield
  873|    664|    if ((err==UNZ_OK) && (extraField!=NULL))
  ------------------
  |  |   74|    664|#define UNZ_OK                          (0)
  ------------------
  |  Branch (873:9): [True: 660, False: 4]
  |  Branch (873:26): [True: 0, False: 660]
  ------------------
  874|      0|    {
  875|      0|        ZPOS64_T uSizeRead ;
  876|      0|        if (file_info.size_file_extra<extraFieldBufferSize)
  ------------------
  |  Branch (876:13): [True: 0, False: 0]
  ------------------
  877|      0|            uSizeRead = file_info.size_file_extra;
  878|      0|        else
  879|      0|            uSizeRead = extraFieldBufferSize;
  880|       |
  881|      0|        if (lSeek!=0)
  ------------------
  |  Branch (881:13): [True: 0, False: 0]
  ------------------
  882|      0|        {
  883|      0|            if (ZSEEK64(s->z_filefunc, s->filestream,(ZPOS64_T)lSeek,ZLIB_FILEFUNC_SEEK_CUR)==0)
  ------------------
  |  |  204|      0|#define ZSEEK64(filefunc,filestream,pos,mode)   (call_zseek64((&(filefunc)),(filestream),(pos),(mode)))
  ------------------
  |  Branch (883:17): [True: 0, False: 0]
  ------------------
  884|      0|                lSeek=0;
  885|      0|            else
  886|      0|                err=UNZ_ERRNO;
  ------------------
  |  |   76|      0|#define UNZ_ERRNO                       (Z_ERRNO)
  |  |  ------------------
  |  |  |  |  180|      0|#define Z_ERRNO        (-1)
  |  |  ------------------
  ------------------
  887|      0|        }
  888|       |
  889|      0|        if ((file_info.size_file_extra>0) && (extraFieldBufferSize>0))
  ------------------
  |  Branch (889:13): [True: 0, False: 0]
  |  Branch (889:46): [True: 0, False: 0]
  ------------------
  890|      0|            if (ZREAD64(s->z_filefunc, s->filestream,extraField,(uLong)uSizeRead)!=uSizeRead)
  ------------------
  |  |  189|      0|#define ZREAD64(filefunc,filestream,buf,size)     ((*((filefunc).zfile_func64.zread_file))   ((filefunc).zfile_func64.opaque,filestream,buf,size))
  ------------------
  |  Branch (890:17): [True: 0, False: 0]
  ------------------
  891|      0|                err=UNZ_ERRNO;
  ------------------
  |  |   76|      0|#define UNZ_ERRNO                       (Z_ERRNO)
  |  |  ------------------
  |  |  |  |  180|      0|#define Z_ERRNO        (-1)
  |  |  ------------------
  ------------------
  892|       |
  893|      0|        lSeek += file_info.size_file_extra - (uLong)uSizeRead;
  894|      0|    }
  895|    664|    else
  896|    664|        lSeek += file_info.size_file_extra;
  897|       |
  898|       |
  899|    664|    if ((err==UNZ_OK) && (file_info.size_file_extra != 0))
  ------------------
  |  |   74|    664|#define UNZ_OK                          (0)
  ------------------
  |  Branch (899:9): [True: 660, False: 4]
  |  Branch (899:26): [True: 62, False: 598]
  ------------------
  900|     62|    {
  901|     62|                                uLong acc = 0;
  902|       |
  903|       |        // since lSeek now points to after the extra field we need to move back
  904|     62|        lSeek -= file_info.size_file_extra;
  905|       |
  906|     62|        if (lSeek!=0)
  ------------------
  |  Branch (906:13): [True: 34, False: 28]
  ------------------
  907|     34|        {
  908|     34|            if (ZSEEK64(s->z_filefunc, s->filestream,(ZPOS64_T)lSeek,ZLIB_FILEFUNC_SEEK_CUR)==0)
  ------------------
  |  |  204|     34|#define ZSEEK64(filefunc,filestream,pos,mode)   (call_zseek64((&(filefunc)),(filestream),(pos),(mode)))
  ------------------
  |  Branch (908:17): [True: 34, False: 0]
  ------------------
  909|     34|                lSeek=0;
  910|      0|            else
  911|      0|                err=UNZ_ERRNO;
  ------------------
  |  |   76|      0|#define UNZ_ERRNO                       (Z_ERRNO)
  |  |  ------------------
  |  |  |  |  180|      0|#define Z_ERRNO        (-1)
  |  |  ------------------
  ------------------
  912|     34|        }
  913|       |
  914|    124|        while(acc < file_info.size_file_extra)
  ------------------
  |  Branch (914:15): [True: 62, False: 62]
  ------------------
  915|     62|        {
  916|     62|            uLong headerId;
  917|     62|                                                uLong dataSize;
  918|       |
  919|     62|            if (unz64local_getShort(&s->z_filefunc, s->filestream,&headerId) != UNZ_OK)
  ------------------
  |  |   74|     62|#define UNZ_OK                          (0)
  ------------------
  |  Branch (919:17): [True: 0, False: 62]
  ------------------
  920|      0|                err=UNZ_ERRNO;
  ------------------
  |  |   76|      0|#define UNZ_ERRNO                       (Z_ERRNO)
  |  |  ------------------
  |  |  |  |  180|      0|#define Z_ERRNO        (-1)
  |  |  ------------------
  ------------------
  921|       |
  922|     62|            if (unz64local_getShort(&s->z_filefunc, s->filestream,&dataSize) != UNZ_OK)
  ------------------
  |  |   74|     62|#define UNZ_OK                          (0)
  ------------------
  |  Branch (922:17): [True: 0, False: 62]
  ------------------
  923|      0|                err=UNZ_ERRNO;
  ------------------
  |  |   76|      0|#define UNZ_ERRNO                       (Z_ERRNO)
  |  |  ------------------
  |  |  |  |  180|      0|#define Z_ERRNO        (-1)
  |  |  ------------------
  ------------------
  924|       |
  925|       |            /* ZIP64 extra fields */
  926|     62|            if (headerId == 0x0001)
  ------------------
  |  Branch (926:17): [True: 0, False: 62]
  ------------------
  927|      0|            {
  928|      0|                if(file_info.uncompressed_size == MAXU32)
  ------------------
  |  |  106|      0|#define MAXU32 (0xffffffff)
  ------------------
  |  Branch (928:20): [True: 0, False: 0]
  ------------------
  929|      0|                {
  930|      0|                    if (unz64local_getLong64(&s->z_filefunc, s->filestream,&file_info.uncompressed_size) != UNZ_OK)
  ------------------
  |  |   74|      0|#define UNZ_OK                          (0)
  ------------------
  |  Branch (930:25): [True: 0, False: 0]
  ------------------
  931|      0|                        err=UNZ_ERRNO;
  ------------------
  |  |   76|      0|#define UNZ_ERRNO                       (Z_ERRNO)
  |  |  ------------------
  |  |  |  |  180|      0|#define Z_ERRNO        (-1)
  |  |  ------------------
  ------------------
  932|      0|                }
  933|       |
  934|      0|                if(file_info.compressed_size == MAXU32)
  ------------------
  |  |  106|      0|#define MAXU32 (0xffffffff)
  ------------------
  |  Branch (934:20): [True: 0, False: 0]
  ------------------
  935|      0|                {
  936|      0|                    if (unz64local_getLong64(&s->z_filefunc, s->filestream,&file_info.compressed_size) != UNZ_OK)
  ------------------
  |  |   74|      0|#define UNZ_OK                          (0)
  ------------------
  |  Branch (936:25): [True: 0, False: 0]
  ------------------
  937|      0|                        err=UNZ_ERRNO;
  ------------------
  |  |   76|      0|#define UNZ_ERRNO                       (Z_ERRNO)
  |  |  ------------------
  |  |  |  |  180|      0|#define Z_ERRNO        (-1)
  |  |  ------------------
  ------------------
  938|      0|                }
  939|       |
  940|      0|                if(file_info_internal.offset_curfile == MAXU32)
  ------------------
  |  |  106|      0|#define MAXU32 (0xffffffff)
  ------------------
  |  Branch (940:20): [True: 0, False: 0]
  ------------------
  941|      0|                {
  942|       |                    /* Relative Header offset */
  943|      0|                    if (unz64local_getLong64(&s->z_filefunc, s->filestream,&file_info_internal.offset_curfile) != UNZ_OK)
  ------------------
  |  |   74|      0|#define UNZ_OK                          (0)
  ------------------
  |  Branch (943:25): [True: 0, False: 0]
  ------------------
  944|      0|                        err=UNZ_ERRNO;
  ------------------
  |  |   76|      0|#define UNZ_ERRNO                       (Z_ERRNO)
  |  |  ------------------
  |  |  |  |  180|      0|#define Z_ERRNO        (-1)
  |  |  ------------------
  ------------------
  945|      0|                }
  946|       |
  947|      0|                if(file_info.disk_num_start == 0xffff)
  ------------------
  |  Branch (947:20): [True: 0, False: 0]
  ------------------
  948|      0|                {
  949|       |                    /* Disk Start Number */
  950|      0|                    if (unz64local_getLong(&s->z_filefunc, s->filestream,&file_info.disk_num_start) != UNZ_OK)
  ------------------
  |  |   74|      0|#define UNZ_OK                          (0)
  ------------------
  |  Branch (950:25): [True: 0, False: 0]
  ------------------
  951|      0|                        err=UNZ_ERRNO;
  ------------------
  |  |   76|      0|#define UNZ_ERRNO                       (Z_ERRNO)
  |  |  ------------------
  |  |  |  |  180|      0|#define Z_ERRNO        (-1)
  |  |  ------------------
  ------------------
  952|      0|                }
  953|       |
  954|      0|            }
  955|     62|            else
  956|     62|            {
  957|     62|                if (ZSEEK64(s->z_filefunc, s->filestream,dataSize,ZLIB_FILEFUNC_SEEK_CUR)!=0)
  ------------------
  |  |  204|     62|#define ZSEEK64(filefunc,filestream,pos,mode)   (call_zseek64((&(filefunc)),(filestream),(pos),(mode)))
  ------------------
  |  Branch (957:21): [True: 0, False: 62]
  ------------------
  958|      0|                    err=UNZ_ERRNO;
  ------------------
  |  |   76|      0|#define UNZ_ERRNO                       (Z_ERRNO)
  |  |  ------------------
  |  |  |  |  180|      0|#define Z_ERRNO        (-1)
  |  |  ------------------
  ------------------
  959|     62|            }
  960|       |
  961|     62|            acc += 2 + 2 + dataSize;
  962|     62|        }
  963|     62|    }
  964|       |
  965|    664|    if ((err==UNZ_OK) && (szComment!=NULL))
  ------------------
  |  |   74|    664|#define UNZ_OK                          (0)
  ------------------
  |  Branch (965:9): [True: 660, False: 4]
  |  Branch (965:26): [True: 0, False: 660]
  ------------------
  966|      0|    {
  967|      0|        uLong uSizeRead ;
  968|      0|        if (file_info.size_file_comment<commentBufferSize)
  ------------------
  |  Branch (968:13): [True: 0, False: 0]
  ------------------
  969|      0|        {
  970|      0|            *(szComment+file_info.size_file_comment)='\0';
  971|      0|            uSizeRead = file_info.size_file_comment;
  972|      0|        }
  973|      0|        else
  974|      0|            uSizeRead = commentBufferSize;
  975|       |
  976|      0|        if (lSeek!=0)
  ------------------
  |  Branch (976:13): [True: 0, False: 0]
  ------------------
  977|      0|        {
  978|      0|            if (ZSEEK64(s->z_filefunc, s->filestream,(ZPOS64_T)lSeek,ZLIB_FILEFUNC_SEEK_CUR)==0)
  ------------------
  |  |  204|      0|#define ZSEEK64(filefunc,filestream,pos,mode)   (call_zseek64((&(filefunc)),(filestream),(pos),(mode)))
  ------------------
  |  Branch (978:17): [True: 0, False: 0]
  ------------------
  979|      0|                lSeek=0;
  980|      0|            else
  981|      0|                err=UNZ_ERRNO;
  ------------------
  |  |   76|      0|#define UNZ_ERRNO                       (Z_ERRNO)
  |  |  ------------------
  |  |  |  |  180|      0|#define Z_ERRNO        (-1)
  |  |  ------------------
  ------------------
  982|      0|        }
  983|       |
  984|      0|        if ((file_info.size_file_comment>0) && (commentBufferSize>0))
  ------------------
  |  Branch (984:13): [True: 0, False: 0]
  |  Branch (984:48): [True: 0, False: 0]
  ------------------
  985|      0|            if (ZREAD64(s->z_filefunc, s->filestream,szComment,uSizeRead)!=uSizeRead)
  ------------------
  |  |  189|      0|#define ZREAD64(filefunc,filestream,buf,size)     ((*((filefunc).zfile_func64.zread_file))   ((filefunc).zfile_func64.opaque,filestream,buf,size))
  ------------------
  |  Branch (985:17): [True: 0, False: 0]
  ------------------
  986|      0|                err=UNZ_ERRNO;
  ------------------
  |  |   76|      0|#define UNZ_ERRNO                       (Z_ERRNO)
  |  |  ------------------
  |  |  |  |  180|      0|#define Z_ERRNO        (-1)
  |  |  ------------------
  ------------------
  987|      0|        lSeek+=file_info.size_file_comment - uSizeRead;
  988|      0|    }
  989|    664|    else
  990|    664|        lSeek+=file_info.size_file_comment;
  991|       |
  992|       |
  993|    664|    if ((err==UNZ_OK) && (pfile_info!=NULL))
  ------------------
  |  |   74|    664|#define UNZ_OK                          (0)
  ------------------
  |  Branch (993:9): [True: 660, False: 4]
  |  Branch (993:26): [True: 660, False: 0]
  ------------------
  994|    660|        *pfile_info=file_info;
  995|       |
  996|    664|    if ((err==UNZ_OK) && (pfile_info_internal!=NULL))
  ------------------
  |  |   74|    664|#define UNZ_OK                          (0)
  ------------------
  |  Branch (996:9): [True: 660, False: 4]
  |  Branch (996:26): [True: 348, False: 312]
  ------------------
  997|    348|        *pfile_info_internal=file_info_internal;
  998|       |
  999|    664|    return err;
 1000|    664|}
unzip.c:unz64local_DosDateToTmuDate:
  752|    664|local void unz64local_DosDateToTmuDate(ZPOS64_T ulDosDate, tm_unz* ptm) {
  753|    664|    ZPOS64_T uDate;
  754|    664|    uDate = (ZPOS64_T)(ulDosDate>>16);
  755|    664|    ptm->tm_mday = (int)(uDate&0x1f) ;
  756|    664|    ptm->tm_mon =  (int)((((uDate)&0x1E0)/0x20)-1) ;
  757|    664|    ptm->tm_year = (int)(((uDate&0x0FE00)/0x0200)+1980) ;
  758|       |
  759|    664|    ptm->tm_hour = (int) ((ulDosDate &0xF800)/0x800);
  760|    664|    ptm->tm_min =  (int) ((ulDosDate&0x7E0)/0x20) ;
  761|    664|    ptm->tm_sec =  (int) (2*(ulDosDate&0x1f)) ;
  762|    664|}
unzip.c:unz64local_CheckCurrentFileCoherencyHeader:
 1259|      9|                                                     uInt  * psize_local_extrafield) {
 1260|      9|    uLong uMagic,uData,uFlags;
 1261|      9|    uLong size_filename;
 1262|      9|    uLong size_extra_field;
 1263|      9|    int err=UNZ_OK;
  ------------------
  |  |   74|      9|#define UNZ_OK                          (0)
  ------------------
 1264|       |
 1265|      9|    *piSizeVar = 0;
 1266|      9|    *poffset_local_extrafield = 0;
 1267|      9|    *psize_local_extrafield = 0;
 1268|       |
 1269|      9|    if (ZSEEK64(s->z_filefunc, s->filestream,s->cur_file_info_internal.offset_curfile +
  ------------------
  |  |  204|      9|#define ZSEEK64(filefunc,filestream,pos,mode)   (call_zseek64((&(filefunc)),(filestream),(pos),(mode)))
  ------------------
  |  Branch (1269:9): [True: 0, False: 9]
  ------------------
 1270|      9|                                s->byte_before_the_zipfile,ZLIB_FILEFUNC_SEEK_SET)!=0)
 1271|      0|        return UNZ_ERRNO;
  ------------------
  |  |   76|      0|#define UNZ_ERRNO                       (Z_ERRNO)
  |  |  ------------------
  |  |  |  |  180|      0|#define Z_ERRNO        (-1)
  |  |  ------------------
  ------------------
 1272|       |
 1273|       |
 1274|      9|    if (err==UNZ_OK)
  ------------------
  |  |   74|      9|#define UNZ_OK                          (0)
  ------------------
  |  Branch (1274:9): [True: 9, False: 0]
  ------------------
 1275|      9|    {
 1276|      9|        if (unz64local_getLong(&s->z_filefunc, s->filestream,&uMagic) != UNZ_OK)
  ------------------
  |  |   74|      9|#define UNZ_OK                          (0)
  ------------------
  |  Branch (1276:13): [True: 0, False: 9]
  ------------------
 1277|      0|            err=UNZ_ERRNO;
  ------------------
  |  |   76|      0|#define UNZ_ERRNO                       (Z_ERRNO)
  |  |  ------------------
  |  |  |  |  180|      0|#define Z_ERRNO        (-1)
  |  |  ------------------
  ------------------
 1278|      9|        else if (uMagic!=0x04034b50)
  ------------------
  |  Branch (1278:18): [True: 1, False: 8]
  ------------------
 1279|      1|            err=UNZ_BADZIPFILE;
  ------------------
  |  |   79|      1|#define UNZ_BADZIPFILE                  (-103)
  ------------------
 1280|      9|    }
 1281|       |
 1282|      9|    if (unz64local_getShort(&s->z_filefunc, s->filestream,&uData) != UNZ_OK)
  ------------------
  |  |   74|      9|#define UNZ_OK                          (0)
  ------------------
  |  Branch (1282:9): [True: 0, False: 9]
  ------------------
 1283|      0|        err=UNZ_ERRNO;
  ------------------
  |  |   76|      0|#define UNZ_ERRNO                       (Z_ERRNO)
  |  |  ------------------
  |  |  |  |  180|      0|#define Z_ERRNO        (-1)
  |  |  ------------------
  ------------------
 1284|       |/*
 1285|       |    else if ((err==UNZ_OK) && (uData!=s->cur_file_info.wVersion))
 1286|       |        err=UNZ_BADZIPFILE;
 1287|       |*/
 1288|      9|    if (unz64local_getShort(&s->z_filefunc, s->filestream,&uFlags) != UNZ_OK)
  ------------------
  |  |   74|      9|#define UNZ_OK                          (0)
  ------------------
  |  Branch (1288:9): [True: 0, False: 9]
  ------------------
 1289|      0|        err=UNZ_ERRNO;
  ------------------
  |  |   76|      0|#define UNZ_ERRNO                       (Z_ERRNO)
  |  |  ------------------
  |  |  |  |  180|      0|#define Z_ERRNO        (-1)
  |  |  ------------------
  ------------------
 1290|       |
 1291|      9|    if (unz64local_getShort(&s->z_filefunc, s->filestream,&uData) != UNZ_OK)
  ------------------
  |  |   74|      9|#define UNZ_OK                          (0)
  ------------------
  |  Branch (1291:9): [True: 0, False: 9]
  ------------------
 1292|      0|        err=UNZ_ERRNO;
  ------------------
  |  |   76|      0|#define UNZ_ERRNO                       (Z_ERRNO)
  |  |  ------------------
  |  |  |  |  180|      0|#define Z_ERRNO        (-1)
  |  |  ------------------
  ------------------
 1293|      9|    else if ((err==UNZ_OK) && (uData!=s->cur_file_info.compression_method))
  ------------------
  |  |   74|      9|#define UNZ_OK                          (0)
  ------------------
  |  Branch (1293:14): [True: 8, False: 1]
  |  Branch (1293:31): [True: 0, False: 8]
  ------------------
 1294|      0|        err=UNZ_BADZIPFILE;
  ------------------
  |  |   79|      0|#define UNZ_BADZIPFILE                  (-103)
  ------------------
 1295|       |
 1296|      9|    if ((err==UNZ_OK) && (s->cur_file_info.compression_method!=0) &&
  ------------------
  |  |   74|      9|#define UNZ_OK                          (0)
  ------------------
  |  Branch (1296:9): [True: 8, False: 1]
  |  Branch (1296:26): [True: 8, False: 0]
  ------------------
 1297|       |/* #ifdef HAVE_BZIP2 */
 1298|      8|                         (s->cur_file_info.compression_method!=Z_BZIP2ED) &&
  ------------------
  |  |   62|      8|#define Z_BZIP2ED 12
  ------------------
  |  Branch (1298:26): [True: 8, False: 0]
  ------------------
 1299|       |/* #endif */
 1300|      8|                         (s->cur_file_info.compression_method!=Z_DEFLATED))
  ------------------
  |  |  209|      8|#define Z_DEFLATED   8
  ------------------
  |  Branch (1300:26): [True: 0, False: 8]
  ------------------
 1301|      0|        err=UNZ_BADZIPFILE;
  ------------------
  |  |   79|      0|#define UNZ_BADZIPFILE                  (-103)
  ------------------
 1302|       |
 1303|      9|    if (unz64local_getLong(&s->z_filefunc, s->filestream,&uData) != UNZ_OK) /* date/time */
  ------------------
  |  |   74|      9|#define UNZ_OK                          (0)
  ------------------
  |  Branch (1303:9): [True: 0, False: 9]
  ------------------
 1304|      0|        err=UNZ_ERRNO;
  ------------------
  |  |   76|      0|#define UNZ_ERRNO                       (Z_ERRNO)
  |  |  ------------------
  |  |  |  |  180|      0|#define Z_ERRNO        (-1)
  |  |  ------------------
  ------------------
 1305|       |
 1306|      9|    if (unz64local_getLong(&s->z_filefunc, s->filestream,&uData) != UNZ_OK) /* crc */
  ------------------
  |  |   74|      9|#define UNZ_OK                          (0)
  ------------------
  |  Branch (1306:9): [True: 0, False: 9]
  ------------------
 1307|      0|        err=UNZ_ERRNO;
  ------------------
  |  |   76|      0|#define UNZ_ERRNO                       (Z_ERRNO)
  |  |  ------------------
  |  |  |  |  180|      0|#define Z_ERRNO        (-1)
  |  |  ------------------
  ------------------
 1308|      9|    else if ((err==UNZ_OK) && (uData!=s->cur_file_info.crc) && ((uFlags & 8)==0))
  ------------------
  |  |   74|      9|#define UNZ_OK                          (0)
  ------------------
  |  Branch (1308:14): [True: 8, False: 1]
  |  Branch (1308:31): [True: 0, False: 8]
  |  Branch (1308:64): [True: 0, False: 0]
  ------------------
 1309|      0|        err=UNZ_BADZIPFILE;
  ------------------
  |  |   79|      0|#define UNZ_BADZIPFILE                  (-103)
  ------------------
 1310|       |
 1311|      9|    if (unz64local_getLong(&s->z_filefunc, s->filestream,&uData) != UNZ_OK) /* size compr */
  ------------------
  |  |   74|      9|#define UNZ_OK                          (0)
  ------------------
  |  Branch (1311:9): [True: 0, False: 9]
  ------------------
 1312|      0|        err=UNZ_ERRNO;
  ------------------
  |  |   76|      0|#define UNZ_ERRNO                       (Z_ERRNO)
  |  |  ------------------
  |  |  |  |  180|      0|#define Z_ERRNO        (-1)
  |  |  ------------------
  ------------------
 1313|      9|    else if (uData != 0xFFFFFFFF && (err==UNZ_OK) && (uData!=s->cur_file_info.compressed_size) && ((uFlags & 8)==0))
  ------------------
  |  |   74|      9|#define UNZ_OK                          (0)
  ------------------
  |  Branch (1313:14): [True: 9, False: 0]
  |  Branch (1313:37): [True: 8, False: 1]
  |  Branch (1313:54): [True: 0, False: 8]
  |  Branch (1313:99): [True: 0, False: 0]
  ------------------
 1314|      0|        err=UNZ_BADZIPFILE;
  ------------------
  |  |   79|      0|#define UNZ_BADZIPFILE                  (-103)
  ------------------
 1315|       |
 1316|      9|    if (unz64local_getLong(&s->z_filefunc, s->filestream,&uData) != UNZ_OK) /* size uncompr */
  ------------------
  |  |   74|      9|#define UNZ_OK                          (0)
  ------------------
  |  Branch (1316:9): [True: 0, False: 9]
  ------------------
 1317|      0|        err=UNZ_ERRNO;
  ------------------
  |  |   76|      0|#define UNZ_ERRNO                       (Z_ERRNO)
  |  |  ------------------
  |  |  |  |  180|      0|#define Z_ERRNO        (-1)
  |  |  ------------------
  ------------------
 1318|      9|    else if (uData != 0xFFFFFFFF && (err==UNZ_OK) && (uData!=s->cur_file_info.uncompressed_size) && ((uFlags & 8)==0))
  ------------------
  |  |   74|      9|#define UNZ_OK                          (0)
  ------------------
  |  Branch (1318:14): [True: 9, False: 0]
  |  Branch (1318:37): [True: 8, False: 1]
  |  Branch (1318:54): [True: 0, False: 8]
  |  Branch (1318:101): [True: 0, False: 0]
  ------------------
 1319|      0|        err=UNZ_BADZIPFILE;
  ------------------
  |  |   79|      0|#define UNZ_BADZIPFILE                  (-103)
  ------------------
 1320|       |
 1321|      9|    if (unz64local_getShort(&s->z_filefunc, s->filestream,&size_filename) != UNZ_OK)
  ------------------
  |  |   74|      9|#define UNZ_OK                          (0)
  ------------------
  |  Branch (1321:9): [True: 0, False: 9]
  ------------------
 1322|      0|        err=UNZ_ERRNO;
  ------------------
  |  |   76|      0|#define UNZ_ERRNO                       (Z_ERRNO)
  |  |  ------------------
  |  |  |  |  180|      0|#define Z_ERRNO        (-1)
  |  |  ------------------
  ------------------
 1323|      9|    else if ((err==UNZ_OK) && (size_filename!=s->cur_file_info.size_filename))
  ------------------
  |  |   74|      9|#define UNZ_OK                          (0)
  ------------------
  |  Branch (1323:14): [True: 8, False: 1]
  |  Branch (1323:31): [True: 0, False: 8]
  ------------------
 1324|      0|        err=UNZ_BADZIPFILE;
  ------------------
  |  |   79|      0|#define UNZ_BADZIPFILE                  (-103)
  ------------------
 1325|       |
 1326|      9|    *piSizeVar += (uInt)size_filename;
 1327|       |
 1328|      9|    if (unz64local_getShort(&s->z_filefunc, s->filestream,&size_extra_field) != UNZ_OK)
  ------------------
  |  |   74|      9|#define UNZ_OK                          (0)
  ------------------
  |  Branch (1328:9): [True: 0, False: 9]
  ------------------
 1329|      0|        err=UNZ_ERRNO;
  ------------------
  |  |   76|      0|#define UNZ_ERRNO                       (Z_ERRNO)
  |  |  ------------------
  |  |  |  |  180|      0|#define Z_ERRNO        (-1)
  |  |  ------------------
  ------------------
 1330|      9|    *poffset_local_extrafield= s->cur_file_info_internal.offset_curfile +
 1331|      9|                                    SIZEZIPLOCALHEADER + size_filename;
  ------------------
  |  |  114|      9|#define SIZEZIPLOCALHEADER (0x1e)
  ------------------
 1332|      9|    *psize_local_extrafield = (uInt)size_extra_field;
 1333|       |
 1334|      9|    *piSizeVar += (uInt)size_extra_field;
 1335|       |
 1336|      9|    return err;
 1337|      9|}

_ZN4utf818invalid_code_pointC2Ej:
   44|      2|        invalid_code_point(uint32_t codepoint) : cp(codepoint) {}
_ZNK4utf818invalid_code_point4whatEv:
   45|      4|        virtual const char* what() const UTF_CPP_NOEXCEPT UTF_CPP_OVERRIDE { return "Invalid code point"; }
_ZN4utf88utf16to8INSt3__111__wrap_iterIPcEENS1_20back_insert_iteratorINS1_6vectorIhNS1_9allocatorIhEEEEEEEET0_T_SC_SB_:
  190|      1|    {
  191|  17.8k|        while (start != end) {
  ------------------
  |  Branch (191:16): [True: 17.8k, False: 1]
  ------------------
  192|  17.8k|            uint32_t cp = utf8::internal::mask16(*start++);
  193|       |            // Take care of surrogate pairs first
  194|  17.8k|            if (utf8::internal::is_lead_surrogate(cp)) {
  ------------------
  |  Branch (194:17): [True: 0, False: 17.8k]
  ------------------
  195|      0|                if (start != end) {
  ------------------
  |  Branch (195:21): [True: 0, False: 0]
  ------------------
  196|      0|                    uint32_t trail_surrogate = utf8::internal::mask16(*start++);
  197|      0|                    if (utf8::internal::is_trail_surrogate(trail_surrogate))
  ------------------
  |  Branch (197:25): [True: 0, False: 0]
  ------------------
  198|      0|                        cp = (cp << 10) + trail_surrogate + internal::SURROGATE_OFFSET;
  199|      0|                    else
  200|      0|                        throw invalid_utf16(static_cast<uint16_t>(trail_surrogate));
  201|      0|                }
  202|      0|                else
  203|      0|                    throw invalid_utf16(static_cast<uint16_t>(cp));
  204|       |
  205|      0|            }
  206|       |            // Lone trail surrogate
  207|  17.8k|            else if (utf8::internal::is_trail_surrogate(cp))
  ------------------
  |  Branch (207:22): [True: 0, False: 17.8k]
  ------------------
  208|      0|                throw invalid_utf16(static_cast<uint16_t>(cp));
  209|       |
  210|  17.8k|            result = utf8::append(cp, result);
  211|  17.8k|        }
  212|      1|        return result;
  213|      1|    }
_ZN4utf86appendINSt3__120back_insert_iteratorINS1_6vectorIhNS1_9allocatorIhEEEEEEEET_jS8_:
   75|  17.8k|    {
   76|  17.8k|        if (!utf8::internal::is_code_point_valid(cp))
  ------------------
  |  Branch (76:13): [True: 0, False: 17.8k]
  ------------------
   77|      0|            throw invalid_code_point(cp);
   78|       |
   79|  17.8k|        return internal::append(cp, result);
   80|  17.8k|    }
_ZN4utf88utf32to8IPhPKjEET_T0_S5_S4_:
  232|      2|    {
  233|      4|        while (start != end)
  ------------------
  |  Branch (233:16): [True: 2, False: 2]
  ------------------
  234|      2|            result = utf8::append(*(start++), result);
  235|       |
  236|      2|        return result;
  237|      2|    }
_ZN4utf86appendIPhEET_jS2_:
   75|      2|    {
   76|      2|        if (!utf8::internal::is_code_point_valid(cp))
  ------------------
  |  Branch (76:13): [True: 2, False: 0]
  ------------------
   77|      2|            throw invalid_code_point(cp);
   78|       |
   79|      0|        return internal::append(cp, result);
   80|      2|    }

_ZN4utf88internal19is_code_point_validIjEEbT_:
  111|  17.8k|    {
  112|  17.8k|        return (cp <= CODE_POINT_MAX && !utf8::internal::is_surrogate(cp));
  ------------------
  |  Branch (112:17): [True: 17.8k, False: 2]
  |  Branch (112:41): [True: 17.8k, False: 0]
  ------------------
  113|  17.8k|    }
_ZN4utf88internal12is_surrogateIjEEbT_:
  105|  17.8k|    {
  106|  17.8k|        return (cp >= LEAD_SURROGATE_MIN && cp <= TRAIL_SURROGATE_MAX);
  ------------------
  |  Branch (106:17): [True: 24, False: 17.8k]
  |  Branch (106:45): [True: 0, False: 24]
  ------------------
  107|  17.8k|    }
_ZN4utf88internal6mask16IcEEtT_:
   82|  17.8k|    {
   83|  17.8k|        return static_cast<uint16_t>(0xffff & oc);
   84|  17.8k|    }
_ZN4utf88internal17is_lead_surrogateIjEEbT_:
   93|  17.8k|    {
   94|  17.8k|        return (cp >= LEAD_SURROGATE_MIN && cp <= LEAD_SURROGATE_MAX);
  ------------------
  |  Branch (94:17): [True: 24, False: 17.8k]
  |  Branch (94:45): [True: 0, False: 24]
  ------------------
   95|  17.8k|    }
_ZN4utf88internal18is_trail_surrogateIjEEbT_:
   99|  17.8k|    {
  100|  17.8k|        return (cp >= TRAIL_SURROGATE_MIN && cp <= TRAIL_SURROGATE_MAX);
  ------------------
  |  Branch (100:17): [True: 24, False: 17.8k]
  |  Branch (100:46): [True: 0, False: 24]
  ------------------
  101|  17.8k|    }
_ZN4utf88internal6appendINSt3__16vectorIhNS2_9allocatorIhEEEEEENS2_20back_insert_iteratorIT_EEjS9_:
  336|  17.8k|            (uint32_t cp, std::back_insert_iterator<container_type> result) {
  337|  17.8k|        return append<std::back_insert_iterator<container_type>,
  338|  17.8k|            typename container_type::value_type>(cp, result);
  339|  17.8k|    }
_ZN4utf88internal6appendINSt3__120back_insert_iteratorINS2_6vectorIhNS2_9allocatorIhEEEEEEhEET_jS9_:
  304|  17.8k|    octet_iterator append(uint32_t cp, octet_iterator result) {
  305|  17.8k|        if (cp < 0x80)                        // one octet
  ------------------
  |  Branch (305:13): [True: 17.8k, False: 24]
  ------------------
  306|  17.8k|            *(result++) = static_cast<octet_type>(cp);
  307|     24|        else if (cp < 0x800) {                // two octets
  ------------------
  |  Branch (307:18): [True: 0, False: 24]
  ------------------
  308|      0|            *(result++) = static_cast<octet_type>((cp >> 6)          | 0xc0);
  309|      0|            *(result++) = static_cast<octet_type>((cp & 0x3f)        | 0x80);
  310|      0|        }
  311|     24|        else if (cp < 0x10000) {              // three octets
  ------------------
  |  Branch (311:18): [True: 24, False: 0]
  ------------------
  312|     24|            *(result++) = static_cast<octet_type>((cp >> 12)         | 0xe0);
  313|     24|            *(result++) = static_cast<octet_type>(((cp >> 6) & 0x3f) | 0x80);
  314|     24|            *(result++) = static_cast<octet_type>((cp & 0x3f)        | 0x80);
  315|     24|        }
  316|      0|        else {                                // four octets
  317|      0|            *(result++) = static_cast<octet_type>((cp >> 18)         | 0xf0);
  318|      0|            *(result++) = static_cast<octet_type>(((cp >> 12) & 0x3f)| 0x80);
  319|      0|            *(result++) = static_cast<octet_type>(((cp >> 6) & 0x3f) | 0x80);
  320|      0|            *(result++) = static_cast<octet_type>((cp & 0x3f)        | 0x80);
  321|      0|        }
  322|  17.8k|        return result;
  323|  17.8k|    }

crc32_z:
  752|  3.23k|{
  753|       |    /* Return initial CRC, if requested. */
  754|  3.23k|    if (buf == Z_NULL) return 0;
  ------------------
  |  |  212|  3.23k|#define Z_NULL  0  /* for initializing zalloc, zfree, opaque */
  ------------------
  |  Branch (754:9): [True: 36, False: 3.19k]
  ------------------
  755|       |
  756|       |#ifdef DYNAMIC_CRC_TABLE
  757|       |    once(&made, make_crc_table);
  758|       |#endif /* DYNAMIC_CRC_TABLE */
  759|       |
  760|       |    /* Pre-condition the CRC */
  761|  3.19k|    crc = (~crc) & 0xffffffff;
  762|       |
  763|  3.19k|#ifdef W
  764|       |
  765|       |    /* If provided enough bytes, do a braided CRC calculation. */
  766|  3.19k|    if (len >= N * W + W - 1) {
  ------------------
  |  |   57|  3.19k|#  define N 5
  ------------------
                  if (len >= N * W + W - 1) {
  ------------------
  |  |   83|  3.19k|#      define W 8
  ------------------
                  if (len >= N * W + W - 1) {
  ------------------
  |  |   83|  3.19k|#      define W 8
  ------------------
  |  Branch (766:9): [True: 3.17k, False: 18]
  ------------------
  767|  3.17k|        z_size_t blks;
  768|  3.17k|        z_word_t const *words;
  769|  3.17k|        unsigned endian;
  770|  3.17k|        int k;
  771|       |
  772|       |        /* Compute the CRC up to a z_word_t boundary. */
  773|  3.24k|        while (len && ((z_size_t)buf & (W - 1)) != 0) {
  ------------------
  |  |   83|  3.24k|#      define W 8
  ------------------
  |  Branch (773:16): [True: 3.24k, False: 0]
  |  Branch (773:23): [True: 64, False: 3.17k]
  ------------------
  774|     64|            len--;
  775|     64|            crc = (crc >> 8) ^ crc_table[(crc ^ *buf++) & 0xff];
  776|     64|        }
  777|       |
  778|       |        /* Compute the CRC on as many N z_word_t blocks as are available. */
  779|  3.17k|        blks = len / (N * W);
  ------------------
  |  |   57|  3.17k|#  define N 5
  ------------------
                      blks = len / (N * W);
  ------------------
  |  |   83|  3.17k|#      define W 8
  ------------------
  780|  3.17k|        len -= blks * N * W;
  ------------------
  |  |   57|  3.17k|#  define N 5
  ------------------
                      len -= blks * N * W;
  ------------------
  |  |   83|  3.17k|#      define W 8
  ------------------
  781|  3.17k|        words = (z_word_t const *)buf;
  782|       |
  783|       |        /* Do endian check at execution time instead of compile time, since ARM
  784|       |           processors can change the endianess at execution time. If the
  785|       |           compiler knows what the endianess will be, it can optimize out the
  786|       |           check and the unused branch. */
  787|  3.17k|        endian = 1;
  788|  3.17k|        if (*(unsigned char *)&endian) {
  ------------------
  |  Branch (788:13): [True: 3.17k, False: 0]
  ------------------
  789|       |            /* Little endian. */
  790|       |
  791|  3.17k|            z_crc_t crc0;
  792|  3.17k|            z_word_t word0;
  793|  3.17k|#if N > 1
  794|  3.17k|            z_crc_t crc1;
  795|  3.17k|            z_word_t word1;
  796|  3.17k|#if N > 2
  797|  3.17k|            z_crc_t crc2;
  798|  3.17k|            z_word_t word2;
  799|  3.17k|#if N > 3
  800|  3.17k|            z_crc_t crc3;
  801|  3.17k|            z_word_t word3;
  802|  3.17k|#if N > 4
  803|  3.17k|            z_crc_t crc4;
  804|  3.17k|            z_word_t word4;
  805|       |#if N > 5
  806|       |            z_crc_t crc5;
  807|       |            z_word_t word5;
  808|       |#endif
  809|  3.17k|#endif
  810|  3.17k|#endif
  811|  3.17k|#endif
  812|  3.17k|#endif
  813|       |
  814|       |            /* Initialize the CRC for each braid. */
  815|  3.17k|            crc0 = crc;
  816|  3.17k|#if N > 1
  817|  3.17k|            crc1 = 0;
  818|  3.17k|#if N > 2
  819|  3.17k|            crc2 = 0;
  820|  3.17k|#if N > 3
  821|  3.17k|            crc3 = 0;
  822|  3.17k|#if N > 4
  823|  3.17k|            crc4 = 0;
  824|       |#if N > 5
  825|       |            crc5 = 0;
  826|       |#endif
  827|  3.17k|#endif
  828|  3.17k|#endif
  829|  3.17k|#endif
  830|  3.17k|#endif
  831|       |
  832|       |            /*
  833|       |              Process the first blks-1 blocks, computing the CRCs on each braid
  834|       |              independently.
  835|       |             */
  836|  2.58M|            while (--blks) {
  ------------------
  |  Branch (836:20): [True: 2.58M, False: 3.17k]
  ------------------
  837|       |                /* Load the word for each braid into registers. */
  838|  2.58M|                word0 = crc0 ^ words[0];
  839|  2.58M|#if N > 1
  840|  2.58M|                word1 = crc1 ^ words[1];
  841|  2.58M|#if N > 2
  842|  2.58M|                word2 = crc2 ^ words[2];
  843|  2.58M|#if N > 3
  844|  2.58M|                word3 = crc3 ^ words[3];
  845|  2.58M|#if N > 4
  846|  2.58M|                word4 = crc4 ^ words[4];
  847|       |#if N > 5
  848|       |                word5 = crc5 ^ words[5];
  849|       |#endif
  850|  2.58M|#endif
  851|  2.58M|#endif
  852|  2.58M|#endif
  853|  2.58M|#endif
  854|  2.58M|                words += N;
  ------------------
  |  |   57|  2.58M|#  define N 5
  ------------------
  855|       |
  856|       |                /* Compute and update the CRC for each word. The loop should
  857|       |                   get unrolled. */
  858|  2.58M|                crc0 = crc_braid_table[0][word0 & 0xff];
  859|  2.58M|#if N > 1
  860|  2.58M|                crc1 = crc_braid_table[0][word1 & 0xff];
  861|  2.58M|#if N > 2
  862|  2.58M|                crc2 = crc_braid_table[0][word2 & 0xff];
  863|  2.58M|#if N > 3
  864|  2.58M|                crc3 = crc_braid_table[0][word3 & 0xff];
  865|  2.58M|#if N > 4
  866|  2.58M|                crc4 = crc_braid_table[0][word4 & 0xff];
  867|       |#if N > 5
  868|       |                crc5 = crc_braid_table[0][word5 & 0xff];
  869|       |#endif
  870|  2.58M|#endif
  871|  2.58M|#endif
  872|  2.58M|#endif
  873|  2.58M|#endif
  874|  20.6M|                for (k = 1; k < W; k++) {
  ------------------
  |  |   83|  20.6M|#      define W 8
  ------------------
  |  Branch (874:29): [True: 18.0M, False: 2.58M]
  ------------------
  875|  18.0M|                    crc0 ^= crc_braid_table[k][(word0 >> (k << 3)) & 0xff];
  876|  18.0M|#if N > 1
  877|  18.0M|                    crc1 ^= crc_braid_table[k][(word1 >> (k << 3)) & 0xff];
  878|  18.0M|#if N > 2
  879|  18.0M|                    crc2 ^= crc_braid_table[k][(word2 >> (k << 3)) & 0xff];
  880|  18.0M|#if N > 3
  881|  18.0M|                    crc3 ^= crc_braid_table[k][(word3 >> (k << 3)) & 0xff];
  882|  18.0M|#if N > 4
  883|  18.0M|                    crc4 ^= crc_braid_table[k][(word4 >> (k << 3)) & 0xff];
  884|       |#if N > 5
  885|       |                    crc5 ^= crc_braid_table[k][(word5 >> (k << 3)) & 0xff];
  886|       |#endif
  887|  18.0M|#endif
  888|  18.0M|#endif
  889|  18.0M|#endif
  890|  18.0M|#endif
  891|  18.0M|                }
  892|  2.58M|            }
  893|       |
  894|       |            /*
  895|       |              Process the last block, combining the CRCs of the N braids at the
  896|       |              same time.
  897|       |             */
  898|  3.17k|            crc = crc_word(crc0 ^ words[0]);
  899|  3.17k|#if N > 1
  900|  3.17k|            crc = crc_word(crc1 ^ words[1] ^ crc);
  901|  3.17k|#if N > 2
  902|  3.17k|            crc = crc_word(crc2 ^ words[2] ^ crc);
  903|  3.17k|#if N > 3
  904|  3.17k|            crc = crc_word(crc3 ^ words[3] ^ crc);
  905|  3.17k|#if N > 4
  906|  3.17k|            crc = crc_word(crc4 ^ words[4] ^ crc);
  907|       |#if N > 5
  908|       |            crc = crc_word(crc5 ^ words[5] ^ crc);
  909|       |#endif
  910|  3.17k|#endif
  911|  3.17k|#endif
  912|  3.17k|#endif
  913|  3.17k|#endif
  914|  3.17k|            words += N;
  ------------------
  |  |   57|  3.17k|#  define N 5
  ------------------
  915|  3.17k|        }
  916|      0|        else {
  917|       |            /* Big endian. */
  918|       |
  919|      0|            z_word_t crc0, word0, comb;
  920|      0|#if N > 1
  921|      0|            z_word_t crc1, word1;
  922|      0|#if N > 2
  923|      0|            z_word_t crc2, word2;
  924|      0|#if N > 3
  925|      0|            z_word_t crc3, word3;
  926|      0|#if N > 4
  927|      0|            z_word_t crc4, word4;
  928|       |#if N > 5
  929|       |            z_word_t crc5, word5;
  930|       |#endif
  931|      0|#endif
  932|      0|#endif
  933|      0|#endif
  934|      0|#endif
  935|       |
  936|       |            /* Initialize the CRC for each braid. */
  937|      0|            crc0 = byte_swap(crc);
  938|      0|#if N > 1
  939|      0|            crc1 = 0;
  940|      0|#if N > 2
  941|      0|            crc2 = 0;
  942|      0|#if N > 3
  943|      0|            crc3 = 0;
  944|      0|#if N > 4
  945|      0|            crc4 = 0;
  946|       |#if N > 5
  947|       |            crc5 = 0;
  948|       |#endif
  949|      0|#endif
  950|      0|#endif
  951|      0|#endif
  952|      0|#endif
  953|       |
  954|       |            /*
  955|       |              Process the first blks-1 blocks, computing the CRCs on each braid
  956|       |              independently.
  957|       |             */
  958|      0|            while (--blks) {
  ------------------
  |  Branch (958:20): [True: 0, False: 0]
  ------------------
  959|       |                /* Load the word for each braid into registers. */
  960|      0|                word0 = crc0 ^ words[0];
  961|      0|#if N > 1
  962|      0|                word1 = crc1 ^ words[1];
  963|      0|#if N > 2
  964|      0|                word2 = crc2 ^ words[2];
  965|      0|#if N > 3
  966|      0|                word3 = crc3 ^ words[3];
  967|      0|#if N > 4
  968|      0|                word4 = crc4 ^ words[4];
  969|       |#if N > 5
  970|       |                word5 = crc5 ^ words[5];
  971|       |#endif
  972|      0|#endif
  973|      0|#endif
  974|      0|#endif
  975|      0|#endif
  976|      0|                words += N;
  ------------------
  |  |   57|      0|#  define N 5
  ------------------
  977|       |
  978|       |                /* Compute and update the CRC for each word. The loop should
  979|       |                   get unrolled. */
  980|      0|                crc0 = crc_braid_big_table[0][word0 & 0xff];
  981|      0|#if N > 1
  982|      0|                crc1 = crc_braid_big_table[0][word1 & 0xff];
  983|      0|#if N > 2
  984|      0|                crc2 = crc_braid_big_table[0][word2 & 0xff];
  985|      0|#if N > 3
  986|      0|                crc3 = crc_braid_big_table[0][word3 & 0xff];
  987|      0|#if N > 4
  988|      0|                crc4 = crc_braid_big_table[0][word4 & 0xff];
  989|       |#if N > 5
  990|       |                crc5 = crc_braid_big_table[0][word5 & 0xff];
  991|       |#endif
  992|      0|#endif
  993|      0|#endif
  994|      0|#endif
  995|      0|#endif
  996|      0|                for (k = 1; k < W; k++) {
  ------------------
  |  |   83|      0|#      define W 8
  ------------------
  |  Branch (996:29): [True: 0, False: 0]
  ------------------
  997|      0|                    crc0 ^= crc_braid_big_table[k][(word0 >> (k << 3)) & 0xff];
  998|      0|#if N > 1
  999|      0|                    crc1 ^= crc_braid_big_table[k][(word1 >> (k << 3)) & 0xff];
 1000|      0|#if N > 2
 1001|      0|                    crc2 ^= crc_braid_big_table[k][(word2 >> (k << 3)) & 0xff];
 1002|      0|#if N > 3
 1003|      0|                    crc3 ^= crc_braid_big_table[k][(word3 >> (k << 3)) & 0xff];
 1004|      0|#if N > 4
 1005|      0|                    crc4 ^= crc_braid_big_table[k][(word4 >> (k << 3)) & 0xff];
 1006|       |#if N > 5
 1007|       |                    crc5 ^= crc_braid_big_table[k][(word5 >> (k << 3)) & 0xff];
 1008|       |#endif
 1009|      0|#endif
 1010|      0|#endif
 1011|      0|#endif
 1012|      0|#endif
 1013|      0|                }
 1014|      0|            }
 1015|       |
 1016|       |            /*
 1017|       |              Process the last block, combining the CRCs of the N braids at the
 1018|       |              same time.
 1019|       |             */
 1020|      0|            comb = crc_word_big(crc0 ^ words[0]);
 1021|      0|#if N > 1
 1022|      0|            comb = crc_word_big(crc1 ^ words[1] ^ comb);
 1023|      0|#if N > 2
 1024|      0|            comb = crc_word_big(crc2 ^ words[2] ^ comb);
 1025|      0|#if N > 3
 1026|      0|            comb = crc_word_big(crc3 ^ words[3] ^ comb);
 1027|      0|#if N > 4
 1028|      0|            comb = crc_word_big(crc4 ^ words[4] ^ comb);
 1029|       |#if N > 5
 1030|       |            comb = crc_word_big(crc5 ^ words[5] ^ comb);
 1031|       |#endif
 1032|      0|#endif
 1033|      0|#endif
 1034|      0|#endif
 1035|      0|#endif
 1036|      0|            words += N;
  ------------------
  |  |   57|      0|#  define N 5
  ------------------
 1037|      0|            crc = byte_swap(comb);
 1038|      0|        }
 1039|       |
 1040|       |        /*
 1041|       |          Update the pointer to the remaining bytes to process.
 1042|       |         */
 1043|  3.17k|        buf = (unsigned char const *)words;
 1044|  3.17k|    }
 1045|       |
 1046|  3.19k|#endif /* W */
 1047|       |
 1048|       |    /* Complete the computation of the CRC on any remaining bytes. */
 1049|  12.7k|    while (len >= 8) {
  ------------------
  |  Branch (1049:12): [True: 9.50k, False: 3.19k]
  ------------------
 1050|  9.50k|        len -= 8;
 1051|  9.50k|        crc = (crc >> 8) ^ crc_table[(crc ^ *buf++) & 0xff];
 1052|  9.50k|        crc = (crc >> 8) ^ crc_table[(crc ^ *buf++) & 0xff];
 1053|  9.50k|        crc = (crc >> 8) ^ crc_table[(crc ^ *buf++) & 0xff];
 1054|  9.50k|        crc = (crc >> 8) ^ crc_table[(crc ^ *buf++) & 0xff];
 1055|  9.50k|        crc = (crc >> 8) ^ crc_table[(crc ^ *buf++) & 0xff];
 1056|  9.50k|        crc = (crc >> 8) ^ crc_table[(crc ^ *buf++) & 0xff];
 1057|  9.50k|        crc = (crc >> 8) ^ crc_table[(crc ^ *buf++) & 0xff];
 1058|  9.50k|        crc = (crc >> 8) ^ crc_table[(crc ^ *buf++) & 0xff];
 1059|  9.50k|    }
 1060|  9.69k|    while (len) {
  ------------------
  |  Branch (1060:12): [True: 6.50k, False: 3.19k]
  ------------------
 1061|  6.50k|        len--;
 1062|  6.50k|        crc = (crc >> 8) ^ crc_table[(crc ^ *buf++) & 0xff];
 1063|  6.50k|    }
 1064|       |
 1065|       |    /* Return the CRC, post-conditioned. */
 1066|  3.19k|    return crc ^ 0xffffffff;
 1067|  3.23k|}
crc32:
 1076|  3.23k|{
 1077|  3.23k|    return crc32_z(crc, buf, len);
 1078|  3.23k|}
crc32.c:crc_word:
  728|  15.8k|{
  729|  15.8k|    int k;
  730|   143k|    for (k = 0; k < W; k++)
  ------------------
  |  |   83|   143k|#      define W 8
  ------------------
  |  Branch (730:17): [True: 127k, False: 15.8k]
  ------------------
  731|   127k|        data = (data >> 8) ^ crc_table[data & 0xff];
  732|  15.8k|    return (z_crc_t)data;
  733|  15.8k|}

inflate_fast:
   53|  3.23k|{
   54|  3.23k|    struct inflate_state FAR *state;
   55|  3.23k|    z_const unsigned char FAR *in;      /* local strm->next_in */
   56|  3.23k|    z_const unsigned char FAR *last;    /* have enough input while in < last */
   57|  3.23k|    unsigned char FAR *out;     /* local strm->next_out */
   58|  3.23k|    unsigned char FAR *beg;     /* inflate()'s initial strm->next_out */
   59|  3.23k|    unsigned char FAR *end;     /* while out < end, enough space available */
   60|       |#ifdef INFLATE_STRICT
   61|       |    unsigned dmax;              /* maximum distance from zlib header */
   62|       |#endif
   63|  3.23k|    unsigned wsize;             /* window size or zero if not using window */
   64|  3.23k|    unsigned whave;             /* valid bytes in the window */
   65|  3.23k|    unsigned wnext;             /* window write index */
   66|  3.23k|    unsigned char FAR *window;  /* allocated sliding window, if wsize != 0 */
   67|  3.23k|    unsigned long hold;         /* local strm->hold */
   68|  3.23k|    unsigned bits;              /* local strm->bits */
   69|  3.23k|    code const FAR *lcode;      /* local strm->lencode */
   70|  3.23k|    code const FAR *dcode;      /* local strm->distcode */
   71|  3.23k|    unsigned lmask;             /* mask for first level of length codes */
   72|  3.23k|    unsigned dmask;             /* mask for first level of distance codes */
   73|  3.23k|    code const *here;           /* retrieved table entry */
   74|  3.23k|    unsigned op;                /* code bits, operation, extra bits, or */
   75|       |                                /*  window position, window bytes to copy */
   76|  3.23k|    unsigned len;               /* match length, unused bytes */
   77|  3.23k|    unsigned dist;              /* match distance */
   78|  3.23k|    unsigned char FAR *from;    /* where to copy match from */
   79|       |
   80|       |    /* copy state to local variables */
   81|  3.23k|    state = (struct inflate_state FAR *)strm->state;
   82|  3.23k|    in = strm->next_in;
   83|  3.23k|    last = in + (strm->avail_in - 5);
   84|  3.23k|    out = strm->next_out;
   85|  3.23k|    beg = out - (start - strm->avail_out);
   86|  3.23k|    end = out + (strm->avail_out - 257);
   87|       |#ifdef INFLATE_STRICT
   88|       |    dmax = state->dmax;
   89|       |#endif
   90|  3.23k|    wsize = state->wsize;
   91|  3.23k|    whave = state->whave;
   92|  3.23k|    wnext = state->wnext;
   93|  3.23k|    window = state->window;
   94|  3.23k|    hold = state->hold;
   95|  3.23k|    bits = state->bits;
   96|  3.23k|    lcode = state->lencode;
   97|  3.23k|    dcode = state->distcode;
   98|  3.23k|    lmask = (1U << state->lenbits) - 1;
   99|  3.23k|    dmask = (1U << state->distbits) - 1;
  100|       |
  101|       |    /* decode literals and length/distances until end-of-block or not enough
  102|       |       input data or output space */
  103|  1.16M|    do {
  104|  1.16M|        if (bits < 15) {
  ------------------
  |  Branch (104:13): [True: 522k, False: 643k]
  ------------------
  105|   522k|            hold += (unsigned long)(*in++) << bits;
  106|   522k|            bits += 8;
  107|   522k|            hold += (unsigned long)(*in++) << bits;
  108|   522k|            bits += 8;
  109|   522k|        }
  110|  1.16M|        here = lcode + (hold & lmask);
  111|  1.23M|      dolen:
  112|  1.23M|        op = (unsigned)(here->bits);
  113|  1.23M|        hold >>= op;
  114|  1.23M|        bits -= op;
  115|  1.23M|        op = (unsigned)(here->op);
  116|  1.23M|        if (op == 0) {                          /* literal */
  ------------------
  |  Branch (116:13): [True: 321k, False: 909k]
  ------------------
  117|   321k|            Tracevv((stderr, here->val >= 0x20 && here->val < 0x7f ?
  118|   321k|                    "inflate:         literal '%c'\n" :
  119|   321k|                    "inflate:         literal 0x%02x\n", here->val));
  120|   321k|            *out++ = (unsigned char)(here->val);
  121|   321k|        }
  122|   909k|        else if (op & 16) {                     /* length base */
  ------------------
  |  Branch (122:18): [True: 843k, False: 65.3k]
  ------------------
  123|   843k|            len = (unsigned)(here->val);
  124|   843k|            op &= 15;                           /* number of extra bits */
  125|   843k|            if (op) {
  ------------------
  |  Branch (125:17): [True: 220k, False: 623k]
  ------------------
  126|   220k|                if (bits < op) {
  ------------------
  |  Branch (126:21): [True: 24, False: 220k]
  ------------------
  127|     24|                    hold += (unsigned long)(*in++) << bits;
  128|     24|                    bits += 8;
  129|     24|                }
  130|   220k|                len += (unsigned)hold & ((1U << op) - 1);
  131|   220k|                hold >>= op;
  132|   220k|                bits -= op;
  133|   220k|            }
  134|   843k|            Tracevv((stderr, "inflate:         length %u\n", len));
  135|   843k|            if (bits < 15) {
  ------------------
  |  Branch (135:17): [True: 168k, False: 674k]
  ------------------
  136|   168k|                hold += (unsigned long)(*in++) << bits;
  137|   168k|                bits += 8;
  138|   168k|                hold += (unsigned long)(*in++) << bits;
  139|   168k|                bits += 8;
  140|   168k|            }
  141|   843k|            here = dcode + (hold & dmask);
  142|   862k|          dodist:
  143|   862k|            op = (unsigned)(here->bits);
  144|   862k|            hold >>= op;
  145|   862k|            bits -= op;
  146|   862k|            op = (unsigned)(here->op);
  147|   862k|            if (op & 16) {                      /* distance base */
  ------------------
  |  Branch (147:17): [True: 843k, False: 18.7k]
  ------------------
  148|   843k|                dist = (unsigned)(here->val);
  149|   843k|                op &= 15;                       /* number of extra bits */
  150|   843k|                if (bits < op) {
  ------------------
  |  Branch (150:21): [True: 13.6k, False: 830k]
  ------------------
  151|  13.6k|                    hold += (unsigned long)(*in++) << bits;
  152|  13.6k|                    bits += 8;
  153|  13.6k|                    if (bits < op) {
  ------------------
  |  Branch (153:25): [True: 1.59k, False: 12.0k]
  ------------------
  154|  1.59k|                        hold += (unsigned long)(*in++) << bits;
  155|  1.59k|                        bits += 8;
  156|  1.59k|                    }
  157|  13.6k|                }
  158|   843k|                dist += (unsigned)hold & ((1U << op) - 1);
  159|       |#ifdef INFLATE_STRICT
  160|       |                if (dist > dmax) {
  161|       |                    strm->msg = (char *)"invalid distance too far back";
  162|       |                    state->mode = BAD;
  163|       |                    break;
  164|       |                }
  165|       |#endif
  166|   843k|                hold >>= op;
  167|   843k|                bits -= op;
  168|   843k|                Tracevv((stderr, "inflate:         distance %u\n", dist));
  169|   843k|                op = (unsigned)(out - beg);     /* max distance in output */
  170|   843k|                if (dist > op) {                /* see if copy from window */
  ------------------
  |  Branch (170:21): [True: 57.4k, False: 786k]
  ------------------
  171|  57.4k|                    op = dist - op;             /* distance back in window */
  172|  57.4k|                    if (op > whave) {
  ------------------
  |  Branch (172:25): [True: 0, False: 57.4k]
  ------------------
  173|      0|                        if (state->sane) {
  ------------------
  |  Branch (173:29): [True: 0, False: 0]
  ------------------
  174|      0|                            strm->msg =
  175|      0|                                (char *)"invalid distance too far back";
  176|      0|                            state->mode = BAD;
  177|      0|                            break;
  178|      0|                        }
  179|       |#ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR
  180|       |                        if (len <= op - whave) {
  181|       |                            do {
  182|       |                                *out++ = 0;
  183|       |                            } while (--len);
  184|       |                            continue;
  185|       |                        }
  186|       |                        len -= op - whave;
  187|       |                        do {
  188|       |                            *out++ = 0;
  189|       |                        } while (--op > whave);
  190|       |                        if (op == 0) {
  191|       |                            from = out - dist;
  192|       |                            do {
  193|       |                                *out++ = *from++;
  194|       |                            } while (--len);
  195|       |                            continue;
  196|       |                        }
  197|       |#endif
  198|      0|                    }
  199|  57.4k|                    from = window;
  200|  57.4k|                    if (wnext == 0) {           /* very common case */
  ------------------
  |  Branch (200:25): [True: 47.2k, False: 10.2k]
  ------------------
  201|  47.2k|                        from += wsize - op;
  202|  47.2k|                        if (op < len) {         /* some from window */
  ------------------
  |  Branch (202:29): [True: 309, False: 46.8k]
  ------------------
  203|    309|                            len -= op;
  204|  21.2k|                            do {
  205|  21.2k|                                *out++ = *from++;
  206|  21.2k|                            } while (--op);
  ------------------
  |  Branch (206:38): [True: 20.8k, False: 309]
  ------------------
  207|    309|                            from = out - dist;  /* rest from output */
  208|    309|                        }
  209|  47.2k|                    }
  210|  10.2k|                    else if (wnext < op) {      /* wrap around window */
  ------------------
  |  Branch (210:30): [True: 3.39k, False: 6.84k]
  ------------------
  211|  3.39k|                        from += wsize + wnext - op;
  212|  3.39k|                        op -= wnext;
  213|  3.39k|                        if (op < len) {         /* some from end of window */
  ------------------
  |  Branch (213:29): [True: 1, False: 3.39k]
  ------------------
  214|      1|                            len -= op;
  215|      1|                            do {
  216|      1|                                *out++ = *from++;
  217|      1|                            } while (--op);
  ------------------
  |  Branch (217:38): [True: 0, False: 1]
  ------------------
  218|      1|                            from = window;
  219|      1|                            if (wnext < len) {  /* some from start of window */
  ------------------
  |  Branch (219:33): [True: 0, False: 1]
  ------------------
  220|      0|                                op = wnext;
  221|      0|                                len -= op;
  222|      0|                                do {
  223|      0|                                    *out++ = *from++;
  224|      0|                                } while (--op);
  ------------------
  |  Branch (224:42): [True: 0, False: 0]
  ------------------
  225|      0|                                from = out - dist;      /* rest from output */
  226|      0|                            }
  227|      1|                        }
  228|  3.39k|                    }
  229|  6.84k|                    else {                      /* contiguous in window */
  230|  6.84k|                        from += wnext - op;
  231|  6.84k|                        if (op < len) {         /* some from window */
  ------------------
  |  Branch (231:29): [True: 9, False: 6.83k]
  ------------------
  232|      9|                            len -= op;
  233|     45|                            do {
  234|     45|                                *out++ = *from++;
  235|     45|                            } while (--op);
  ------------------
  |  Branch (235:38): [True: 36, False: 9]
  ------------------
  236|      9|                            from = out - dist;  /* rest from output */
  237|      9|                        }
  238|  6.84k|                    }
  239|   561k|                    while (len > 2) {
  ------------------
  |  Branch (239:28): [True: 504k, False: 57.4k]
  ------------------
  240|   504k|                        *out++ = *from++;
  241|   504k|                        *out++ = *from++;
  242|   504k|                        *out++ = *from++;
  243|   504k|                        len -= 3;
  244|   504k|                    }
  245|  57.4k|                    if (len) {
  ------------------
  |  Branch (245:25): [True: 42.5k, False: 14.8k]
  ------------------
  246|  42.5k|                        *out++ = *from++;
  247|  42.5k|                        if (len > 1)
  ------------------
  |  Branch (247:29): [True: 13.6k, False: 28.9k]
  ------------------
  248|  13.6k|                            *out++ = *from++;
  249|  42.5k|                    }
  250|  57.4k|                }
  251|   786k|                else {
  252|   786k|                    from = out - dist;          /* copy direct from output */
  253|  33.5M|                    do {                        /* minimum length is three */
  254|  33.5M|                        *out++ = *from++;
  255|  33.5M|                        *out++ = *from++;
  256|  33.5M|                        *out++ = *from++;
  257|  33.5M|                        len -= 3;
  258|  33.5M|                    } while (len > 2);
  ------------------
  |  Branch (258:30): [True: 32.7M, False: 786k]
  ------------------
  259|   786k|                    if (len) {
  ------------------
  |  Branch (259:25): [True: 196k, False: 589k]
  ------------------
  260|   196k|                        *out++ = *from++;
  261|   196k|                        if (len > 1)
  ------------------
  |  Branch (261:29): [True: 87.7k, False: 108k]
  ------------------
  262|  87.7k|                            *out++ = *from++;
  263|   196k|                    }
  264|   786k|                }
  265|   843k|            }
  266|  18.7k|            else if ((op & 64) == 0) {          /* 2nd level distance code */
  ------------------
  |  Branch (266:22): [True: 18.7k, False: 0]
  ------------------
  267|  18.7k|                here = dcode + here->val + (hold & ((1U << op) - 1));
  268|  18.7k|                goto dodist;
  269|  18.7k|            }
  270|      0|            else {
  271|      0|                strm->msg = (char *)"invalid distance code";
  272|      0|                state->mode = BAD;
  273|      0|                break;
  274|      0|            }
  275|   862k|        }
  276|  65.3k|        else if ((op & 64) == 0) {              /* 2nd level length code */
  ------------------
  |  Branch (276:18): [True: 65.2k, False: 40]
  ------------------
  277|  65.2k|            here = lcode + here->val + (hold & ((1U << op) - 1));
  278|  65.2k|            goto dolen;
  279|  65.2k|        }
  280|     40|        else if (op & 32) {                     /* end-of-block */
  ------------------
  |  Branch (280:18): [True: 40, False: 0]
  ------------------
  281|     40|            Tracevv((stderr, "inflate:         end of block\n"));
  282|     40|            state->mode = TYPE;
  283|     40|            break;
  284|     40|        }
  285|      0|        else {
  286|      0|            strm->msg = (char *)"invalid literal/length code";
  287|      0|            state->mode = BAD;
  288|      0|            break;
  289|      0|        }
  290|  1.23M|    } while (in < last && out < end);
  ------------------
  |  Branch (290:14): [True: 1.16M, False: 49]
  |  Branch (290:27): [True: 1.16M, False: 3.14k]
  ------------------
  291|       |
  292|       |    /* return unused bytes (on entry, bits < 8, so in won't go too far back) */
  293|  3.23k|    len = bits >> 3;
  294|  3.23k|    in -= len;
  295|  3.23k|    bits -= len << 3;
  296|  3.23k|    hold &= (1U << bits) - 1;
  297|       |
  298|       |    /* update state and return */
  299|  3.23k|    strm->next_in = in;
  300|  3.23k|    strm->next_out = out;
  301|  3.23k|    strm->avail_in = (unsigned)(in < last ? 5 + (last - in) : 5 - (in - last));
  ------------------
  |  Branch (301:33): [True: 3.20k, False: 24]
  ------------------
  302|  3.23k|    strm->avail_out = (unsigned)(out < end ?
  ------------------
  |  Branch (302:34): [True: 89, False: 3.14k]
  ------------------
  303|  3.14k|                                 257 + (end - out) : 257 - (out - end));
  304|  3.23k|    state->hold = hold;
  305|  3.23k|    state->bits = bits;
  306|  3.23k|    return;
  307|  3.23k|}

inflateResetKeep:
  121|     26|{
  122|     26|    struct inflate_state FAR *state;
  123|       |
  124|     26|    if (inflateStateCheck(strm)) return Z_STREAM_ERROR;
  ------------------
  |  |  181|      0|#define Z_STREAM_ERROR (-2)
  ------------------
  |  Branch (124:9): [True: 0, False: 26]
  ------------------
  125|     26|    state = (struct inflate_state FAR *)strm->state;
  126|     26|    strm->total_in = strm->total_out = state->total = 0;
  127|     26|    strm->msg = Z_NULL;
  ------------------
  |  |  212|     26|#define Z_NULL  0  /* for initializing zalloc, zfree, opaque */
  ------------------
  128|     26|    if (state->wrap)        /* to support ill-conceived Java test suite */
  ------------------
  |  Branch (128:9): [True: 18, False: 8]
  ------------------
  129|     18|        strm->adler = state->wrap & 1;
  130|     26|    state->mode = HEAD;
  131|     26|    state->last = 0;
  132|     26|    state->havedict = 0;
  133|     26|    state->flags = -1;
  134|     26|    state->dmax = 32768U;
  135|     26|    state->head = Z_NULL;
  ------------------
  |  |  212|     26|#define Z_NULL  0  /* for initializing zalloc, zfree, opaque */
  ------------------
  136|     26|    state->hold = 0;
  137|     26|    state->bits = 0;
  138|     26|    state->lencode = state->distcode = state->next = state->codes;
  139|     26|    state->sane = 1;
  140|     26|    state->back = -1;
  141|     26|    Tracev((stderr, "inflate: reset\n"));
  142|     26|    return Z_OK;
  ------------------
  |  |  177|     26|#define Z_OK            0
  ------------------
  143|     26|}
inflateReset:
  147|     26|{
  148|     26|    struct inflate_state FAR *state;
  149|       |
  150|     26|    if (inflateStateCheck(strm)) return Z_STREAM_ERROR;
  ------------------
  |  |  181|      0|#define Z_STREAM_ERROR (-2)
  ------------------
  |  Branch (150:9): [True: 0, False: 26]
  ------------------
  151|     26|    state = (struct inflate_state FAR *)strm->state;
  152|     26|    state->wsize = 0;
  153|     26|    state->whave = 0;
  154|     26|    state->wnext = 0;
  155|     26|    return inflateResetKeep(strm);
  156|     26|}
inflateReset2:
  161|     26|{
  162|     26|    int wrap;
  163|     26|    struct inflate_state FAR *state;
  164|       |
  165|       |    /* get the state */
  166|     26|    if (inflateStateCheck(strm)) return Z_STREAM_ERROR;
  ------------------
  |  |  181|      0|#define Z_STREAM_ERROR (-2)
  ------------------
  |  Branch (166:9): [True: 0, False: 26]
  ------------------
  167|     26|    state = (struct inflate_state FAR *)strm->state;
  168|       |
  169|       |    /* extract wrap request from windowBits parameter */
  170|     26|    if (windowBits < 0) {
  ------------------
  |  Branch (170:9): [True: 8, False: 18]
  ------------------
  171|      8|        if (windowBits < -15)
  ------------------
  |  Branch (171:13): [True: 0, False: 8]
  ------------------
  172|      0|            return Z_STREAM_ERROR;
  ------------------
  |  |  181|      0|#define Z_STREAM_ERROR (-2)
  ------------------
  173|      8|        wrap = 0;
  174|      8|        windowBits = -windowBits;
  175|      8|    }
  176|     18|    else {
  177|     18|        wrap = (windowBits >> 4) + 5;
  178|     18|#ifdef GUNZIP
  179|     18|        if (windowBits < 48)
  ------------------
  |  Branch (179:13): [True: 18, False: 0]
  ------------------
  180|     18|            windowBits &= 15;
  181|     18|#endif
  182|     18|    }
  183|       |
  184|       |    /* set number of window bits, free window if different */
  185|     26|    if (windowBits && (windowBits < 8 || windowBits > 15))
  ------------------
  |  Branch (185:9): [True: 26, False: 0]
  |  Branch (185:24): [True: 0, False: 26]
  |  Branch (185:42): [True: 0, False: 26]
  ------------------
  186|      0|        return Z_STREAM_ERROR;
  ------------------
  |  |  181|      0|#define Z_STREAM_ERROR (-2)
  ------------------
  187|     26|    if (state->window != Z_NULL && state->wbits != (unsigned)windowBits) {
  ------------------
  |  |  212|     52|#define Z_NULL  0  /* for initializing zalloc, zfree, opaque */
  ------------------
  |  Branch (187:9): [True: 0, False: 26]
  |  Branch (187:36): [True: 0, False: 0]
  ------------------
  188|      0|        ZFREE(strm, state->window);
  ------------------
  |  |  268|      0|#define ZFREE(strm, addr)  (*((strm)->zfree))((strm)->opaque, (voidpf)(addr))
  ------------------
  189|      0|        state->window = Z_NULL;
  ------------------
  |  |  212|      0|#define Z_NULL  0  /* for initializing zalloc, zfree, opaque */
  ------------------
  190|      0|    }
  191|       |
  192|       |    /* update state and reset the rest of it */
  193|     26|    state->wrap = wrap;
  194|     26|    state->wbits = (unsigned)windowBits;
  195|     26|    return inflateReset(strm);
  196|     26|}
inflateInit2_:
  203|     26|{
  204|     26|    int ret;
  205|     26|    struct inflate_state FAR *state;
  206|       |
  207|     26|    if (version == Z_NULL || version[0] != ZLIB_VERSION[0] ||
  ------------------
  |  |  212|     52|#define Z_NULL  0  /* for initializing zalloc, zfree, opaque */
  ------------------
                  if (version == Z_NULL || version[0] != ZLIB_VERSION[0] ||
  ------------------
  |  |   40|     26|#define ZLIB_VERSION "1.2.13"
  ------------------
  |  Branch (207:9): [True: 0, False: 26]
  |  Branch (207:30): [True: 0, False: 26]
  ------------------
  208|     26|        stream_size != (int)(sizeof(z_stream)))
  ------------------
  |  Branch (208:9): [True: 0, False: 26]
  ------------------
  209|      0|        return Z_VERSION_ERROR;
  ------------------
  |  |  185|      0|#define Z_VERSION_ERROR (-6)
  ------------------
  210|     26|    if (strm == Z_NULL) return Z_STREAM_ERROR;
  ------------------
  |  |  212|     26|#define Z_NULL  0  /* for initializing zalloc, zfree, opaque */
  ------------------
                  if (strm == Z_NULL) return Z_STREAM_ERROR;
  ------------------
  |  |  181|      0|#define Z_STREAM_ERROR (-2)
  ------------------
  |  Branch (210:9): [True: 0, False: 26]
  ------------------
  211|     26|    strm->msg = Z_NULL;                 /* in case we return an error */
  ------------------
  |  |  212|     26|#define Z_NULL  0  /* for initializing zalloc, zfree, opaque */
  ------------------
  212|     26|    if (strm->zalloc == (alloc_func)0) {
  ------------------
  |  Branch (212:9): [True: 26, False: 0]
  ------------------
  213|       |#ifdef Z_SOLO
  214|       |        return Z_STREAM_ERROR;
  215|       |#else
  216|     26|        strm->zalloc = zcalloc;
  217|     26|        strm->opaque = (voidpf)0;
  218|     26|#endif
  219|     26|    }
  220|     26|    if (strm->zfree == (free_func)0)
  ------------------
  |  Branch (220:9): [True: 26, False: 0]
  ------------------
  221|       |#ifdef Z_SOLO
  222|       |        return Z_STREAM_ERROR;
  223|       |#else
  224|     26|        strm->zfree = zcfree;
  225|     26|#endif
  226|     26|    state = (struct inflate_state FAR *)
  227|     26|            ZALLOC(strm, 1, sizeof(struct inflate_state));
  ------------------
  |  |  267|     26|           (*((strm)->zalloc))((strm)->opaque, (items), (size))
  ------------------
  228|     26|    if (state == Z_NULL) return Z_MEM_ERROR;
  ------------------
  |  |  212|     26|#define Z_NULL  0  /* for initializing zalloc, zfree, opaque */
  ------------------
                  if (state == Z_NULL) return Z_MEM_ERROR;
  ------------------
  |  |  183|      0|#define Z_MEM_ERROR    (-4)
  ------------------
  |  Branch (228:9): [True: 0, False: 26]
  ------------------
  229|     26|    Tracev((stderr, "inflate: allocated\n"));
  230|     26|    strm->state = (struct internal_state FAR *)state;
  231|     26|    state->strm = strm;
  232|     26|    state->window = Z_NULL;
  ------------------
  |  |  212|     26|#define Z_NULL  0  /* for initializing zalloc, zfree, opaque */
  ------------------
  233|     26|    state->mode = HEAD;     /* to pass state test in inflateReset2() */
  234|     26|    ret = inflateReset2(strm, windowBits);
  235|     26|    if (ret != Z_OK) {
  ------------------
  |  |  177|     26|#define Z_OK            0
  ------------------
  |  Branch (235:9): [True: 0, False: 26]
  ------------------
  236|      0|        ZFREE(strm, state);
  ------------------
  |  |  268|      0|#define ZFREE(strm, addr)  (*((strm)->zfree))((strm)->opaque, (voidpf)(addr))
  ------------------
  237|      0|        strm->state = Z_NULL;
  ------------------
  |  |  212|      0|#define Z_NULL  0  /* for initializing zalloc, zfree, opaque */
  ------------------
  238|      0|    }
  239|     26|    return ret;
  240|     26|}
inflate:
  628|  3.18k|{
  629|  3.18k|    struct inflate_state FAR *state;
  630|  3.18k|    z_const unsigned char FAR *next;    /* next input */
  631|  3.18k|    unsigned char FAR *put;     /* next output */
  632|  3.18k|    unsigned have, left;        /* available input and output */
  633|  3.18k|    unsigned long hold;         /* bit buffer */
  634|  3.18k|    unsigned bits;              /* bits in bit buffer */
  635|  3.18k|    unsigned in, out;           /* save starting available input and output */
  636|  3.18k|    unsigned copy;              /* number of stored or match bytes to copy */
  637|  3.18k|    unsigned char FAR *from;    /* where to copy match bytes from */
  638|  3.18k|    code here;                  /* current decoding table entry */
  639|  3.18k|    code last;                  /* parent table entry */
  640|  3.18k|    unsigned len;               /* length to copy for repeats, bits to drop */
  641|  3.18k|    int ret;                    /* return code */
  642|  3.18k|#ifdef GUNZIP
  643|  3.18k|    unsigned char hbuf[4];      /* buffer for gzip header crc calculation */
  644|  3.18k|#endif
  645|  3.18k|    static const unsigned short order[19] = /* permutation of code lengths */
  646|  3.18k|        {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15};
  647|       |
  648|  3.18k|    if (inflateStateCheck(strm) || strm->next_out == Z_NULL ||
  ------------------
  |  |  212|  6.37k|#define Z_NULL  0  /* for initializing zalloc, zfree, opaque */
  ------------------
  |  Branch (648:9): [True: 0, False: 3.18k]
  |  Branch (648:36): [True: 0, False: 3.18k]
  ------------------
  649|  3.18k|        (strm->next_in == Z_NULL && strm->avail_in != 0))
  ------------------
  |  |  212|  6.37k|#define Z_NULL  0  /* for initializing zalloc, zfree, opaque */
  ------------------
  |  Branch (649:10): [True: 0, False: 3.18k]
  |  Branch (649:37): [True: 0, False: 0]
  ------------------
  650|      0|        return Z_STREAM_ERROR;
  ------------------
  |  |  181|      0|#define Z_STREAM_ERROR (-2)
  ------------------
  651|       |
  652|  3.18k|    state = (struct inflate_state FAR *)strm->state;
  653|  3.18k|    if (state->mode == TYPE) state->mode = TYPEDO;      /* skip check */
  ------------------
  |  Branch (653:9): [True: 0, False: 3.18k]
  ------------------
  654|  3.18k|    LOAD();
  ------------------
  |  |  480|  3.18k|    do { \
  |  |  481|  3.18k|        put = strm->next_out; \
  |  |  482|  3.18k|        left = strm->avail_out; \
  |  |  483|  3.18k|        next = strm->next_in; \
  |  |  484|  3.18k|        have = strm->avail_in; \
  |  |  485|  3.18k|        hold = state->hold; \
  |  |  486|  3.18k|        bits = state->bits; \
  |  |  487|  3.18k|    } while (0)
  |  |  ------------------
  |  |  |  Branch (487:14): [Folded, False: 3.18k]
  |  |  ------------------
  ------------------
  655|  3.18k|    in = have;
  656|  3.18k|    out = left;
  657|  3.18k|    ret = Z_OK;
  ------------------
  |  |  177|  3.18k|#define Z_OK            0
  ------------------
  658|  3.18k|    for (;;)
  659|  23.5k|        switch (state->mode) {
  660|     26|        case HEAD:
  ------------------
  |  Branch (660:9): [True: 26, False: 23.5k]
  ------------------
  661|     26|            if (state->wrap == 0) {
  ------------------
  |  Branch (661:17): [True: 8, False: 18]
  ------------------
  662|      8|                state->mode = TYPEDO;
  663|      8|                break;
  664|      8|            }
  665|     18|            NEEDBITS(16);
  ------------------
  |  |  520|     18|    do { \
  |  |  521|     54|        while (bits < (unsigned)(n)) \
  |  |  ------------------
  |  |  |  Branch (521:16): [True: 36, False: 18]
  |  |  ------------------
  |  |  522|     36|            PULLBYTE(); \
  |  |  ------------------
  |  |  |  |  510|     36|    do { \
  |  |  |  |  511|     36|        if (have == 0) goto inf_leave; \
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (511:13): [True: 0, False: 36]
  |  |  |  |  ------------------
  |  |  |  |  512|     36|        have--; \
  |  |  |  |  513|     36|        hold += (unsigned long)(*next++) << bits; \
  |  |  |  |  514|     36|        bits += 8; \
  |  |  |  |  515|     36|    } while (0)
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (515:14): [Folded, False: 36]
  |  |  |  |  ------------------
  |  |  ------------------
  |  |  523|     18|    } while (0)
  |  |  ------------------
  |  |  |  Branch (523:14): [Folded, False: 18]
  |  |  ------------------
  ------------------
  666|     18|#ifdef GUNZIP
  667|     18|            if ((state->wrap & 2) && hold == 0x8b1f) {  /* gzip header */
  ------------------
  |  Branch (667:17): [True: 18, False: 0]
  |  Branch (667:38): [True: 18, False: 0]
  ------------------
  668|     18|                if (state->wbits == 0)
  ------------------
  |  Branch (668:21): [True: 0, False: 18]
  ------------------
  669|      0|                    state->wbits = 15;
  670|     18|                state->check = crc32(0L, Z_NULL, 0);
  ------------------
  |  |  212|     18|#define Z_NULL  0  /* for initializing zalloc, zfree, opaque */
  ------------------
  671|     18|                CRC2(state->check, hold);
  ------------------
  |  |  462|     18|    do { \
  |  |  463|     18|        hbuf[0] = (unsigned char)(word); \
  |  |  464|     18|        hbuf[1] = (unsigned char)((word) >> 8); \
  |  |  465|     18|        check = crc32(check, hbuf, 2); \
  |  |  466|     18|    } while (0)
  |  |  ------------------
  |  |  |  Branch (466:14): [Folded, False: 18]
  |  |  ------------------
  ------------------
  672|     18|                INITBITS();
  ------------------
  |  |  502|     18|    do { \
  |  |  503|     18|        hold = 0; \
  |  |  504|     18|        bits = 0; \
  |  |  505|     18|    } while (0)
  |  |  ------------------
  |  |  |  Branch (505:14): [Folded, False: 18]
  |  |  ------------------
  ------------------
  673|     18|                state->mode = FLAGS;
  674|     18|                break;
  675|     18|            }
  676|      0|            if (state->head != Z_NULL)
  ------------------
  |  |  212|      0|#define Z_NULL  0  /* for initializing zalloc, zfree, opaque */
  ------------------
  |  Branch (676:17): [True: 0, False: 0]
  ------------------
  677|      0|                state->head->done = -1;
  678|      0|            if (!(state->wrap & 1) ||   /* check if zlib header allowed */
  ------------------
  |  Branch (678:17): [True: 0, False: 0]
  ------------------
  679|       |#else
  680|       |            if (
  681|       |#endif
  682|      0|                ((BITS(8) << 8) + (hold >> 8)) % 31) {
  ------------------
  |  |  527|      0|    ((unsigned)hold & ((1U << (n)) - 1))
  ------------------
  |  Branch (682:17): [True: 0, False: 0]
  ------------------
  683|      0|                strm->msg = (char *)"incorrect header check";
  684|      0|                state->mode = BAD;
  685|      0|                break;
  686|      0|            }
  687|      0|            if (BITS(4) != Z_DEFLATED) {
  ------------------
  |  |  527|      0|    ((unsigned)hold & ((1U << (n)) - 1))
  ------------------
                          if (BITS(4) != Z_DEFLATED) {
  ------------------
  |  |  209|      0|#define Z_DEFLATED   8
  ------------------
  |  Branch (687:17): [True: 0, False: 0]
  ------------------
  688|      0|                strm->msg = (char *)"unknown compression method";
  689|      0|                state->mode = BAD;
  690|      0|                break;
  691|      0|            }
  692|      0|            DROPBITS(4);
  ------------------
  |  |  531|      0|    do { \
  |  |  532|      0|        hold >>= (n); \
  |  |  533|      0|        bits -= (unsigned)(n); \
  |  |  534|      0|    } while (0)
  |  |  ------------------
  |  |  |  Branch (534:14): [Folded, False: 0]
  |  |  ------------------
  ------------------
  693|      0|            len = BITS(4) + 8;
  ------------------
  |  |  527|      0|    ((unsigned)hold & ((1U << (n)) - 1))
  ------------------
  694|      0|            if (state->wbits == 0)
  ------------------
  |  Branch (694:17): [True: 0, False: 0]
  ------------------
  695|      0|                state->wbits = len;
  696|      0|            if (len > 15 || len > state->wbits) {
  ------------------
  |  Branch (696:17): [True: 0, False: 0]
  |  Branch (696:29): [True: 0, False: 0]
  ------------------
  697|      0|                strm->msg = (char *)"invalid window size";
  698|      0|                state->mode = BAD;
  699|      0|                break;
  700|      0|            }
  701|      0|            state->dmax = 1U << len;
  702|      0|            state->flags = 0;               /* indicate zlib header */
  703|      0|            Tracev((stderr, "inflate:   zlib header ok\n"));
  704|      0|            strm->adler = state->check = adler32(0L, Z_NULL, 0);
  ------------------
  |  |  212|      0|#define Z_NULL  0  /* for initializing zalloc, zfree, opaque */
  ------------------
  705|      0|            state->mode = hold & 0x200 ? DICTID : TYPE;
  ------------------
  |  Branch (705:27): [True: 0, False: 0]
  ------------------
  706|      0|            INITBITS();
  ------------------
  |  |  502|      0|    do { \
  |  |  503|      0|        hold = 0; \
  |  |  504|      0|        bits = 0; \
  |  |  505|      0|    } while (0)
  |  |  ------------------
  |  |  |  Branch (505:14): [Folded, False: 0]
  |  |  ------------------
  ------------------
  707|      0|            break;
  708|      0|#ifdef GUNZIP
  709|     18|        case FLAGS:
  ------------------
  |  Branch (709:9): [True: 18, False: 23.5k]
  ------------------
  710|     18|            NEEDBITS(16);
  ------------------
  |  |  520|     18|    do { \
  |  |  521|     54|        while (bits < (unsigned)(n)) \
  |  |  ------------------
  |  |  |  Branch (521:16): [True: 36, False: 18]
  |  |  ------------------
  |  |  522|     36|            PULLBYTE(); \
  |  |  ------------------
  |  |  |  |  510|     36|    do { \
  |  |  |  |  511|     36|        if (have == 0) goto inf_leave; \
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (511:13): [True: 0, False: 36]
  |  |  |  |  ------------------
  |  |  |  |  512|     36|        have--; \
  |  |  |  |  513|     36|        hold += (unsigned long)(*next++) << bits; \
  |  |  |  |  514|     36|        bits += 8; \
  |  |  |  |  515|     36|    } while (0)
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (515:14): [Folded, False: 36]
  |  |  |  |  ------------------
  |  |  ------------------
  |  |  523|     18|    } while (0)
  |  |  ------------------
  |  |  |  Branch (523:14): [Folded, False: 18]
  |  |  ------------------
  ------------------
  711|     18|            state->flags = (int)(hold);
  712|     18|            if ((state->flags & 0xff) != Z_DEFLATED) {
  ------------------
  |  |  209|     18|#define Z_DEFLATED   8
  ------------------
  |  Branch (712:17): [True: 0, False: 18]
  ------------------
  713|      0|                strm->msg = (char *)"unknown compression method";
  714|      0|                state->mode = BAD;
  715|      0|                break;
  716|      0|            }
  717|     18|            if (state->flags & 0xe000) {
  ------------------
  |  Branch (717:17): [True: 0, False: 18]
  ------------------
  718|      0|                strm->msg = (char *)"unknown header flags set";
  719|      0|                state->mode = BAD;
  720|      0|                break;
  721|      0|            }
  722|     18|            if (state->head != Z_NULL)
  ------------------
  |  |  212|     18|#define Z_NULL  0  /* for initializing zalloc, zfree, opaque */
  ------------------
  |  Branch (722:17): [True: 0, False: 18]
  ------------------
  723|      0|                state->head->text = (int)((hold >> 8) & 1);
  724|     18|            if ((state->flags & 0x0200) && (state->wrap & 4))
  ------------------
  |  Branch (724:17): [True: 0, False: 18]
  |  Branch (724:44): [True: 0, False: 0]
  ------------------
  725|      0|                CRC2(state->check, hold);
  ------------------
  |  |  462|      0|    do { \
  |  |  463|      0|        hbuf[0] = (unsigned char)(word); \
  |  |  464|      0|        hbuf[1] = (unsigned char)((word) >> 8); \
  |  |  465|      0|        check = crc32(check, hbuf, 2); \
  |  |  466|      0|    } while (0)
  |  |  ------------------
  |  |  |  Branch (466:14): [Folded, False: 0]
  |  |  ------------------
  ------------------
  726|     18|            INITBITS();
  ------------------
  |  |  502|     18|    do { \
  |  |  503|     18|        hold = 0; \
  |  |  504|     18|        bits = 0; \
  |  |  505|     18|    } while (0)
  |  |  ------------------
  |  |  |  Branch (505:14): [Folded, False: 18]
  |  |  ------------------
  ------------------
  727|     18|            state->mode = TIME;
  728|       |                /* fallthrough */
  729|     18|        case TIME:
  ------------------
  |  Branch (729:9): [True: 0, False: 23.5k]
  ------------------
  730|     18|            NEEDBITS(32);
  ------------------
  |  |  520|     18|    do { \
  |  |  521|     90|        while (bits < (unsigned)(n)) \
  |  |  ------------------
  |  |  |  Branch (521:16): [True: 72, False: 18]
  |  |  ------------------
  |  |  522|     72|            PULLBYTE(); \
  |  |  ------------------
  |  |  |  |  510|     72|    do { \
  |  |  |  |  511|     72|        if (have == 0) goto inf_leave; \
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (511:13): [True: 0, False: 72]
  |  |  |  |  ------------------
  |  |  |  |  512|     72|        have--; \
  |  |  |  |  513|     72|        hold += (unsigned long)(*next++) << bits; \
  |  |  |  |  514|     72|        bits += 8; \
  |  |  |  |  515|     72|    } while (0)
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (515:14): [Folded, False: 72]
  |  |  |  |  ------------------
  |  |  ------------------
  |  |  523|     18|    } while (0)
  |  |  ------------------
  |  |  |  Branch (523:14): [Folded, False: 18]
  |  |  ------------------
  ------------------
  731|     18|            if (state->head != Z_NULL)
  ------------------
  |  |  212|     18|#define Z_NULL  0  /* for initializing zalloc, zfree, opaque */
  ------------------
  |  Branch (731:17): [True: 0, False: 18]
  ------------------
  732|      0|                state->head->time = hold;
  733|     18|            if ((state->flags & 0x0200) && (state->wrap & 4))
  ------------------
  |  Branch (733:17): [True: 0, False: 18]
  |  Branch (733:44): [True: 0, False: 0]
  ------------------
  734|      0|                CRC4(state->check, hold);
  ------------------
  |  |  469|      0|    do { \
  |  |  470|      0|        hbuf[0] = (unsigned char)(word); \
  |  |  471|      0|        hbuf[1] = (unsigned char)((word) >> 8); \
  |  |  472|      0|        hbuf[2] = (unsigned char)((word) >> 16); \
  |  |  473|      0|        hbuf[3] = (unsigned char)((word) >> 24); \
  |  |  474|      0|        check = crc32(check, hbuf, 4); \
  |  |  475|      0|    } while (0)
  |  |  ------------------
  |  |  |  Branch (475:14): [Folded, False: 0]
  |  |  ------------------
  ------------------
  735|     18|            INITBITS();
  ------------------
  |  |  502|     18|    do { \
  |  |  503|     18|        hold = 0; \
  |  |  504|     18|        bits = 0; \
  |  |  505|     18|    } while (0)
  |  |  ------------------
  |  |  |  Branch (505:14): [Folded, False: 18]
  |  |  ------------------
  ------------------
  736|     18|            state->mode = OS;
  737|       |                /* fallthrough */
  738|     18|        case OS:
  ------------------
  |  Branch (738:9): [True: 0, False: 23.5k]
  ------------------
  739|     18|            NEEDBITS(16);
  ------------------
  |  |  520|     18|    do { \
  |  |  521|     54|        while (bits < (unsigned)(n)) \
  |  |  ------------------
  |  |  |  Branch (521:16): [True: 36, False: 18]
  |  |  ------------------
  |  |  522|     36|            PULLBYTE(); \
  |  |  ------------------
  |  |  |  |  510|     36|    do { \
  |  |  |  |  511|     36|        if (have == 0) goto inf_leave; \
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (511:13): [True: 0, False: 36]
  |  |  |  |  ------------------
  |  |  |  |  512|     36|        have--; \
  |  |  |  |  513|     36|        hold += (unsigned long)(*next++) << bits; \
  |  |  |  |  514|     36|        bits += 8; \
  |  |  |  |  515|     36|    } while (0)
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (515:14): [Folded, False: 36]
  |  |  |  |  ------------------
  |  |  ------------------
  |  |  523|     18|    } while (0)
  |  |  ------------------
  |  |  |  Branch (523:14): [Folded, False: 18]
  |  |  ------------------
  ------------------
  740|     18|            if (state->head != Z_NULL) {
  ------------------
  |  |  212|     18|#define Z_NULL  0  /* for initializing zalloc, zfree, opaque */
  ------------------
  |  Branch (740:17): [True: 0, False: 18]
  ------------------
  741|      0|                state->head->xflags = (int)(hold & 0xff);
  742|      0|                state->head->os = (int)(hold >> 8);
  743|      0|            }
  744|     18|            if ((state->flags & 0x0200) && (state->wrap & 4))
  ------------------
  |  Branch (744:17): [True: 0, False: 18]
  |  Branch (744:44): [True: 0, False: 0]
  ------------------
  745|      0|                CRC2(state->check, hold);
  ------------------
  |  |  462|      0|    do { \
  |  |  463|      0|        hbuf[0] = (unsigned char)(word); \
  |  |  464|      0|        hbuf[1] = (unsigned char)((word) >> 8); \
  |  |  465|      0|        check = crc32(check, hbuf, 2); \
  |  |  466|      0|    } while (0)
  |  |  ------------------
  |  |  |  Branch (466:14): [Folded, False: 0]
  |  |  ------------------
  ------------------
  746|     18|            INITBITS();
  ------------------
  |  |  502|     18|    do { \
  |  |  503|     18|        hold = 0; \
  |  |  504|     18|        bits = 0; \
  |  |  505|     18|    } while (0)
  |  |  ------------------
  |  |  |  Branch (505:14): [Folded, False: 18]
  |  |  ------------------
  ------------------
  747|     18|            state->mode = EXLEN;
  748|       |                /* fallthrough */
  749|     18|        case EXLEN:
  ------------------
  |  Branch (749:9): [True: 0, False: 23.5k]
  ------------------
  750|     18|            if (state->flags & 0x0400) {
  ------------------
  |  Branch (750:17): [True: 0, False: 18]
  ------------------
  751|      0|                NEEDBITS(16);
  ------------------
  |  |  520|      0|    do { \
  |  |  521|      0|        while (bits < (unsigned)(n)) \
  |  |  ------------------
  |  |  |  Branch (521:16): [True: 0, False: 0]
  |  |  ------------------
  |  |  522|      0|            PULLBYTE(); \
  |  |  ------------------
  |  |  |  |  510|      0|    do { \
  |  |  |  |  511|      0|        if (have == 0) goto inf_leave; \
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (511:13): [True: 0, False: 0]
  |  |  |  |  ------------------
  |  |  |  |  512|      0|        have--; \
  |  |  |  |  513|      0|        hold += (unsigned long)(*next++) << bits; \
  |  |  |  |  514|      0|        bits += 8; \
  |  |  |  |  515|      0|    } while (0)
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (515:14): [Folded, False: 0]
  |  |  |  |  ------------------
  |  |  ------------------
  |  |  523|      0|    } while (0)
  |  |  ------------------
  |  |  |  Branch (523:14): [Folded, False: 0]
  |  |  ------------------
  ------------------
  752|      0|                state->length = (unsigned)(hold);
  753|      0|                if (state->head != Z_NULL)
  ------------------
  |  |  212|      0|#define Z_NULL  0  /* for initializing zalloc, zfree, opaque */
  ------------------
  |  Branch (753:21): [True: 0, False: 0]
  ------------------
  754|      0|                    state->head->extra_len = (unsigned)hold;
  755|      0|                if ((state->flags & 0x0200) && (state->wrap & 4))
  ------------------
  |  Branch (755:21): [True: 0, False: 0]
  |  Branch (755:48): [True: 0, False: 0]
  ------------------
  756|      0|                    CRC2(state->check, hold);
  ------------------
  |  |  462|      0|    do { \
  |  |  463|      0|        hbuf[0] = (unsigned char)(word); \
  |  |  464|      0|        hbuf[1] = (unsigned char)((word) >> 8); \
  |  |  465|      0|        check = crc32(check, hbuf, 2); \
  |  |  466|      0|    } while (0)
  |  |  ------------------
  |  |  |  Branch (466:14): [Folded, False: 0]
  |  |  ------------------
  ------------------
  757|      0|                INITBITS();
  ------------------
  |  |  502|      0|    do { \
  |  |  503|      0|        hold = 0; \
  |  |  504|      0|        bits = 0; \
  |  |  505|      0|    } while (0)
  |  |  ------------------
  |  |  |  Branch (505:14): [Folded, False: 0]
  |  |  ------------------
  ------------------
  758|      0|            }
  759|     18|            else if (state->head != Z_NULL)
  ------------------
  |  |  212|     18|#define Z_NULL  0  /* for initializing zalloc, zfree, opaque */
  ------------------
  |  Branch (759:22): [True: 0, False: 18]
  ------------------
  760|      0|                state->head->extra = Z_NULL;
  ------------------
  |  |  212|      0|#define Z_NULL  0  /* for initializing zalloc, zfree, opaque */
  ------------------
  761|     18|            state->mode = EXTRA;
  762|       |                /* fallthrough */
  763|     18|        case EXTRA:
  ------------------
  |  Branch (763:9): [True: 0, False: 23.5k]
  ------------------
  764|     18|            if (state->flags & 0x0400) {
  ------------------
  |  Branch (764:17): [True: 0, False: 18]
  ------------------
  765|      0|                copy = state->length;
  766|      0|                if (copy > have) copy = have;
  ------------------
  |  Branch (766:21): [True: 0, False: 0]
  ------------------
  767|      0|                if (copy) {
  ------------------
  |  Branch (767:21): [True: 0, False: 0]
  ------------------
  768|      0|                    if (state->head != Z_NULL &&
  ------------------
  |  |  212|      0|#define Z_NULL  0  /* for initializing zalloc, zfree, opaque */
  ------------------
  |  Branch (768:25): [True: 0, False: 0]
  ------------------
  769|      0|                        state->head->extra != Z_NULL &&
  ------------------
  |  |  212|      0|#define Z_NULL  0  /* for initializing zalloc, zfree, opaque */
  ------------------
  |  Branch (769:25): [True: 0, False: 0]
  ------------------
  770|      0|                        (len = state->head->extra_len - state->length) <
  ------------------
  |  Branch (770:25): [True: 0, False: 0]
  ------------------
  771|      0|                            state->head->extra_max) {
  772|      0|                        zmemcpy(state->head->extra + len, next,
  ------------------
  |  |  230|      0|#    define zmemcpy memcpy
  ------------------
  773|      0|                                len + copy > state->head->extra_max ?
  ------------------
  |  Branch (773:33): [True: 0, False: 0]
  ------------------
  774|      0|                                state->head->extra_max - len : copy);
  775|      0|                    }
  776|      0|                    if ((state->flags & 0x0200) && (state->wrap & 4))
  ------------------
  |  Branch (776:25): [True: 0, False: 0]
  |  Branch (776:52): [True: 0, False: 0]
  ------------------
  777|      0|                        state->check = crc32(state->check, next, copy);
  778|      0|                    have -= copy;
  779|      0|                    next += copy;
  780|      0|                    state->length -= copy;
  781|      0|                }
  782|      0|                if (state->length) goto inf_leave;
  ------------------
  |  Branch (782:21): [True: 0, False: 0]
  ------------------
  783|      0|            }
  784|     18|            state->length = 0;
  785|     18|            state->mode = NAME;
  786|       |                /* fallthrough */
  787|     18|        case NAME:
  ------------------
  |  Branch (787:9): [True: 0, False: 23.5k]
  ------------------
  788|     18|            if (state->flags & 0x0800) {
  ------------------
  |  Branch (788:17): [True: 0, False: 18]
  ------------------
  789|      0|                if (have == 0) goto inf_leave;
  ------------------
  |  Branch (789:21): [True: 0, False: 0]
  ------------------
  790|      0|                copy = 0;
  791|      0|                do {
  792|      0|                    len = (unsigned)(next[copy++]);
  793|      0|                    if (state->head != Z_NULL &&
  ------------------
  |  |  212|      0|#define Z_NULL  0  /* for initializing zalloc, zfree, opaque */
  ------------------
  |  Branch (793:25): [True: 0, False: 0]
  ------------------
  794|      0|                            state->head->name != Z_NULL &&
  ------------------
  |  |  212|      0|#define Z_NULL  0  /* for initializing zalloc, zfree, opaque */
  ------------------
  |  Branch (794:29): [True: 0, False: 0]
  ------------------
  795|      0|                            state->length < state->head->name_max)
  ------------------
  |  Branch (795:29): [True: 0, False: 0]
  ------------------
  796|      0|                        state->head->name[state->length++] = (Bytef)len;
  797|      0|                } while (len && copy < have);
  ------------------
  |  Branch (797:26): [True: 0, False: 0]
  |  Branch (797:33): [True: 0, False: 0]
  ------------------
  798|      0|                if ((state->flags & 0x0200) && (state->wrap & 4))
  ------------------
  |  Branch (798:21): [True: 0, False: 0]
  |  Branch (798:48): [True: 0, False: 0]
  ------------------
  799|      0|                    state->check = crc32(state->check, next, copy);
  800|      0|                have -= copy;
  801|      0|                next += copy;
  802|      0|                if (len) goto inf_leave;
  ------------------
  |  Branch (802:21): [True: 0, False: 0]
  ------------------
  803|      0|            }
  804|     18|            else if (state->head != Z_NULL)
  ------------------
  |  |  212|     18|#define Z_NULL  0  /* for initializing zalloc, zfree, opaque */
  ------------------
  |  Branch (804:22): [True: 0, False: 18]
  ------------------
  805|      0|                state->head->name = Z_NULL;
  ------------------
  |  |  212|      0|#define Z_NULL  0  /* for initializing zalloc, zfree, opaque */
  ------------------
  806|     18|            state->length = 0;
  807|     18|            state->mode = COMMENT;
  808|       |                /* fallthrough */
  809|     18|        case COMMENT:
  ------------------
  |  Branch (809:9): [True: 0, False: 23.5k]
  ------------------
  810|     18|            if (state->flags & 0x1000) {
  ------------------
  |  Branch (810:17): [True: 0, False: 18]
  ------------------
  811|      0|                if (have == 0) goto inf_leave;
  ------------------
  |  Branch (811:21): [True: 0, False: 0]
  ------------------
  812|      0|                copy = 0;
  813|      0|                do {
  814|      0|                    len = (unsigned)(next[copy++]);
  815|      0|                    if (state->head != Z_NULL &&
  ------------------
  |  |  212|      0|#define Z_NULL  0  /* for initializing zalloc, zfree, opaque */
  ------------------
  |  Branch (815:25): [True: 0, False: 0]
  ------------------
  816|      0|                            state->head->comment != Z_NULL &&
  ------------------
  |  |  212|      0|#define Z_NULL  0  /* for initializing zalloc, zfree, opaque */
  ------------------
  |  Branch (816:29): [True: 0, False: 0]
  ------------------
  817|      0|                            state->length < state->head->comm_max)
  ------------------
  |  Branch (817:29): [True: 0, False: 0]
  ------------------
  818|      0|                        state->head->comment[state->length++] = (Bytef)len;
  819|      0|                } while (len && copy < have);
  ------------------
  |  Branch (819:26): [True: 0, False: 0]
  |  Branch (819:33): [True: 0, False: 0]
  ------------------
  820|      0|                if ((state->flags & 0x0200) && (state->wrap & 4))
  ------------------
  |  Branch (820:21): [True: 0, False: 0]
  |  Branch (820:48): [True: 0, False: 0]
  ------------------
  821|      0|                    state->check = crc32(state->check, next, copy);
  822|      0|                have -= copy;
  823|      0|                next += copy;
  824|      0|                if (len) goto inf_leave;
  ------------------
  |  Branch (824:21): [True: 0, False: 0]
  ------------------
  825|      0|            }
  826|     18|            else if (state->head != Z_NULL)
  ------------------
  |  |  212|     18|#define Z_NULL  0  /* for initializing zalloc, zfree, opaque */
  ------------------
  |  Branch (826:22): [True: 0, False: 18]
  ------------------
  827|      0|                state->head->comment = Z_NULL;
  ------------------
  |  |  212|      0|#define Z_NULL  0  /* for initializing zalloc, zfree, opaque */
  ------------------
  828|     18|            state->mode = HCRC;
  829|       |                /* fallthrough */
  830|     18|        case HCRC:
  ------------------
  |  Branch (830:9): [True: 0, False: 23.5k]
  ------------------
  831|     18|            if (state->flags & 0x0200) {
  ------------------
  |  Branch (831:17): [True: 0, False: 18]
  ------------------
  832|      0|                NEEDBITS(16);
  ------------------
  |  |  520|      0|    do { \
  |  |  521|      0|        while (bits < (unsigned)(n)) \
  |  |  ------------------
  |  |  |  Branch (521:16): [True: 0, False: 0]
  |  |  ------------------
  |  |  522|      0|            PULLBYTE(); \
  |  |  ------------------
  |  |  |  |  510|      0|    do { \
  |  |  |  |  511|      0|        if (have == 0) goto inf_leave; \
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (511:13): [True: 0, False: 0]
  |  |  |  |  ------------------
  |  |  |  |  512|      0|        have--; \
  |  |  |  |  513|      0|        hold += (unsigned long)(*next++) << bits; \
  |  |  |  |  514|      0|        bits += 8; \
  |  |  |  |  515|      0|    } while (0)
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (515:14): [Folded, False: 0]
  |  |  |  |  ------------------
  |  |  ------------------
  |  |  523|      0|    } while (0)
  |  |  ------------------
  |  |  |  Branch (523:14): [Folded, False: 0]
  |  |  ------------------
  ------------------
  833|      0|                if ((state->wrap & 4) && hold != (state->check & 0xffff)) {
  ------------------
  |  Branch (833:21): [True: 0, False: 0]
  |  Branch (833:42): [True: 0, False: 0]
  ------------------
  834|      0|                    strm->msg = (char *)"header crc mismatch";
  835|      0|                    state->mode = BAD;
  836|      0|                    break;
  837|      0|                }
  838|      0|                INITBITS();
  ------------------
  |  |  502|      0|    do { \
  |  |  503|      0|        hold = 0; \
  |  |  504|      0|        bits = 0; \
  |  |  505|      0|    } while (0)
  |  |  ------------------
  |  |  |  Branch (505:14): [Folded, False: 0]
  |  |  ------------------
  ------------------
  839|      0|            }
  840|     18|            if (state->head != Z_NULL) {
  ------------------
  |  |  212|     18|#define Z_NULL  0  /* for initializing zalloc, zfree, opaque */
  ------------------
  |  Branch (840:17): [True: 0, False: 18]
  ------------------
  841|      0|                state->head->hcrc = (int)((state->flags >> 9) & 1);
  842|      0|                state->head->done = 1;
  843|      0|            }
  844|     18|            strm->adler = state->check = crc32(0L, Z_NULL, 0);
  ------------------
  |  |  212|     18|#define Z_NULL  0  /* for initializing zalloc, zfree, opaque */
  ------------------
  845|     18|            state->mode = TYPE;
  846|     18|            break;
  847|      0|#endif
  848|      0|        case DICTID:
  ------------------
  |  Branch (848:9): [True: 0, False: 23.5k]
  ------------------
  849|      0|            NEEDBITS(32);
  ------------------
  |  |  520|      0|    do { \
  |  |  521|      0|        while (bits < (unsigned)(n)) \
  |  |  ------------------
  |  |  |  Branch (521:16): [True: 0, False: 0]
  |  |  ------------------
  |  |  522|      0|            PULLBYTE(); \
  |  |  ------------------
  |  |  |  |  510|      0|    do { \
  |  |  |  |  511|      0|        if (have == 0) goto inf_leave; \
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (511:13): [True: 0, False: 0]
  |  |  |  |  ------------------
  |  |  |  |  512|      0|        have--; \
  |  |  |  |  513|      0|        hold += (unsigned long)(*next++) << bits; \
  |  |  |  |  514|      0|        bits += 8; \
  |  |  |  |  515|      0|    } while (0)
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (515:14): [Folded, False: 0]
  |  |  |  |  ------------------
  |  |  ------------------
  |  |  523|      0|    } while (0)
  |  |  ------------------
  |  |  |  Branch (523:14): [Folded, False: 0]
  |  |  ------------------
  ------------------
  850|      0|            strm->adler = state->check = ZSWAP32(hold);
  ------------------
  |  |  272|      0|#define ZSWAP32(q) ((((q) >> 24) & 0xff) + (((q) >> 8) & 0xff00) + \
  |  |  273|      0|                    (((q) & 0xff00) << 8) + (((q) & 0xff) << 24))
  ------------------
  851|      0|            INITBITS();
  ------------------
  |  |  502|      0|    do { \
  |  |  503|      0|        hold = 0; \
  |  |  504|      0|        bits = 0; \
  |  |  505|      0|    } while (0)
  |  |  ------------------
  |  |  |  Branch (505:14): [Folded, False: 0]
  |  |  ------------------
  ------------------
  852|      0|            state->mode = DICT;
  853|       |                /* fallthrough */
  854|      0|        case DICT:
  ------------------
  |  Branch (854:9): [True: 0, False: 23.5k]
  ------------------
  855|      0|            if (state->havedict == 0) {
  ------------------
  |  Branch (855:17): [True: 0, False: 0]
  ------------------
  856|      0|                RESTORE();
  ------------------
  |  |  491|      0|    do { \
  |  |  492|      0|        strm->next_out = put; \
  |  |  493|      0|        strm->avail_out = left; \
  |  |  494|      0|        strm->next_in = next; \
  |  |  495|      0|        strm->avail_in = have; \
  |  |  496|      0|        state->hold = hold; \
  |  |  497|      0|        state->bits = bits; \
  |  |  498|      0|    } while (0)
  |  |  ------------------
  |  |  |  Branch (498:14): [Folded, False: 0]
  |  |  ------------------
  ------------------
  857|      0|                return Z_NEED_DICT;
  ------------------
  |  |  179|      0|#define Z_NEED_DICT     2
  ------------------
  858|      0|            }
  859|      0|            strm->adler = state->check = adler32(0L, Z_NULL, 0);
  ------------------
  |  |  212|      0|#define Z_NULL  0  /* for initializing zalloc, zfree, opaque */
  ------------------
  860|      0|            state->mode = TYPE;
  861|       |                /* fallthrough */
  862|     66|        case TYPE:
  ------------------
  |  Branch (862:9): [True: 66, False: 23.5k]
  ------------------
  863|     66|            if (flush == Z_BLOCK || flush == Z_TREES) goto inf_leave;
  ------------------
  |  |  173|    132|#define Z_BLOCK         5
  ------------------
                          if (flush == Z_BLOCK || flush == Z_TREES) goto inf_leave;
  ------------------
  |  |  174|     66|#define Z_TREES         6
  ------------------
  |  Branch (863:17): [True: 0, False: 66]
  |  Branch (863:37): [True: 0, False: 66]
  ------------------
  864|       |                /* fallthrough */
  865|     74|        case TYPEDO:
  ------------------
  |  Branch (865:9): [True: 8, False: 23.5k]
  ------------------
  866|     74|            if (state->last) {
  ------------------
  |  Branch (866:17): [True: 16, False: 58]
  ------------------
  867|     16|                BYTEBITS();
  ------------------
  |  |  538|     16|    do { \
  |  |  539|     16|        hold >>= bits & 7; \
  |  |  540|     16|        bits -= bits & 7; \
  |  |  541|     16|    } while (0)
  |  |  ------------------
  |  |  |  Branch (541:14): [Folded, False: 16]
  |  |  ------------------
  ------------------
  868|     16|                state->mode = CHECK;
  869|     16|                break;
  870|     16|            }
  871|     58|            NEEDBITS(3);
  ------------------
  |  |  520|     58|    do { \
  |  |  521|     95|        while (bits < (unsigned)(n)) \
  |  |  ------------------
  |  |  |  Branch (521:16): [True: 37, False: 58]
  |  |  ------------------
  |  |  522|     58|            PULLBYTE(); \
  |  |  ------------------
  |  |  |  |  510|     37|    do { \
  |  |  |  |  511|     37|        if (have == 0) goto inf_leave; \
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (511:13): [True: 0, False: 37]
  |  |  |  |  ------------------
  |  |  |  |  512|     37|        have--; \
  |  |  |  |  513|     37|        hold += (unsigned long)(*next++) << bits; \
  |  |  |  |  514|     37|        bits += 8; \
  |  |  |  |  515|     37|    } while (0)
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (515:14): [Folded, False: 37]
  |  |  |  |  ------------------
  |  |  ------------------
  |  |  523|     58|    } while (0)
  |  |  ------------------
  |  |  |  Branch (523:14): [Folded, False: 58]
  |  |  ------------------
  ------------------
  872|     58|            state->last = BITS(1);
  ------------------
  |  |  527|     58|    ((unsigned)hold & ((1U << (n)) - 1))
  ------------------
  873|     58|            DROPBITS(1);
  ------------------
  |  |  531|     58|    do { \
  |  |  532|     58|        hold >>= (n); \
  |  |  533|     58|        bits -= (unsigned)(n); \
  |  |  534|     58|    } while (0)
  |  |  ------------------
  |  |  |  Branch (534:14): [Folded, False: 58]
  |  |  ------------------
  ------------------
  874|     58|            switch (BITS(2)) {
  ------------------
  |  |  527|     58|    ((unsigned)hold & ((1U << (n)) - 1))
  |  |  ------------------
  |  |  |  Branch (527:5): [True: 58, False: 0]
  |  |  ------------------
  ------------------
  875|      0|            case 0:                             /* stored block */
  ------------------
  |  Branch (875:13): [True: 0, False: 58]
  ------------------
  876|      0|                Tracev((stderr, "inflate:     stored block%s\n",
  877|      0|                        state->last ? " (last)" : ""));
  878|      0|                state->mode = STORED;
  879|      0|                break;
  880|      4|            case 1:                             /* fixed block */
  ------------------
  |  Branch (880:13): [True: 4, False: 54]
  ------------------
  881|      4|                fixedtables(state);
  882|      4|                Tracev((stderr, "inflate:     fixed codes block%s\n",
  883|      4|                        state->last ? " (last)" : ""));
  884|      4|                state->mode = LEN_;             /* decode codes */
  885|      4|                if (flush == Z_TREES) {
  ------------------
  |  |  174|      4|#define Z_TREES         6
  ------------------
  |  Branch (885:21): [True: 0, False: 4]
  ------------------
  886|      0|                    DROPBITS(2);
  ------------------
  |  |  531|      0|    do { \
  |  |  532|      0|        hold >>= (n); \
  |  |  533|      0|        bits -= (unsigned)(n); \
  |  |  534|      0|    } while (0)
  |  |  ------------------
  |  |  |  Branch (534:14): [Folded, False: 0]
  |  |  ------------------
  ------------------
  887|      0|                    goto inf_leave;
  888|      0|                }
  889|      4|                break;
  890|     54|            case 2:                             /* dynamic block */
  ------------------
  |  Branch (890:13): [True: 54, False: 4]
  ------------------
  891|     54|                Tracev((stderr, "inflate:     dynamic codes block%s\n",
  892|     54|                        state->last ? " (last)" : ""));
  893|     54|                state->mode = TABLE;
  894|     54|                break;
  895|      0|            case 3:
  ------------------
  |  Branch (895:13): [True: 0, False: 58]
  ------------------
  896|      0|                strm->msg = (char *)"invalid block type";
  897|      0|                state->mode = BAD;
  898|     58|            }
  899|     58|            DROPBITS(2);
  ------------------
  |  |  531|     58|    do { \
  |  |  532|     58|        hold >>= (n); \
  |  |  533|     58|        bits -= (unsigned)(n); \
  |  |  534|     58|    } while (0)
  |  |  ------------------
  |  |  |  Branch (534:14): [Folded, False: 58]
  |  |  ------------------
  ------------------
  900|     58|            break;
  901|      0|        case STORED:
  ------------------
  |  Branch (901:9): [True: 0, False: 23.5k]
  ------------------
  902|      0|            BYTEBITS();                         /* go to byte boundary */
  ------------------
  |  |  538|      0|    do { \
  |  |  539|      0|        hold >>= bits & 7; \
  |  |  540|      0|        bits -= bits & 7; \
  |  |  541|      0|    } while (0)
  |  |  ------------------
  |  |  |  Branch (541:14): [Folded, False: 0]
  |  |  ------------------
  ------------------
  903|      0|            NEEDBITS(32);
  ------------------
  |  |  520|      0|    do { \
  |  |  521|      0|        while (bits < (unsigned)(n)) \
  |  |  ------------------
  |  |  |  Branch (521:16): [True: 0, False: 0]
  |  |  ------------------
  |  |  522|      0|            PULLBYTE(); \
  |  |  ------------------
  |  |  |  |  510|      0|    do { \
  |  |  |  |  511|      0|        if (have == 0) goto inf_leave; \
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (511:13): [True: 0, False: 0]
  |  |  |  |  ------------------
  |  |  |  |  512|      0|        have--; \
  |  |  |  |  513|      0|        hold += (unsigned long)(*next++) << bits; \
  |  |  |  |  514|      0|        bits += 8; \
  |  |  |  |  515|      0|    } while (0)
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (515:14): [Folded, False: 0]
  |  |  |  |  ------------------
  |  |  ------------------
  |  |  523|      0|    } while (0)
  |  |  ------------------
  |  |  |  Branch (523:14): [Folded, False: 0]
  |  |  ------------------
  ------------------
  904|      0|            if ((hold & 0xffff) != ((hold >> 16) ^ 0xffff)) {
  ------------------
  |  Branch (904:17): [True: 0, False: 0]
  ------------------
  905|      0|                strm->msg = (char *)"invalid stored block lengths";
  906|      0|                state->mode = BAD;
  907|      0|                break;
  908|      0|            }
  909|      0|            state->length = (unsigned)hold & 0xffff;
  910|      0|            Tracev((stderr, "inflate:       stored length %u\n",
  911|      0|                    state->length));
  912|      0|            INITBITS();
  ------------------
  |  |  502|      0|    do { \
  |  |  503|      0|        hold = 0; \
  |  |  504|      0|        bits = 0; \
  |  |  505|      0|    } while (0)
  |  |  ------------------
  |  |  |  Branch (505:14): [Folded, False: 0]
  |  |  ------------------
  ------------------
  913|      0|            state->mode = COPY_;
  914|      0|            if (flush == Z_TREES) goto inf_leave;
  ------------------
  |  |  174|      0|#define Z_TREES         6
  ------------------
  |  Branch (914:17): [True: 0, False: 0]
  ------------------
  915|       |                /* fallthrough */
  916|      0|        case COPY_:
  ------------------
  |  Branch (916:9): [True: 0, False: 23.5k]
  ------------------
  917|      0|            state->mode = COPY;
  918|       |                /* fallthrough */
  919|      0|        case COPY:
  ------------------
  |  Branch (919:9): [True: 0, False: 23.5k]
  ------------------
  920|      0|            copy = state->length;
  921|      0|            if (copy) {
  ------------------
  |  Branch (921:17): [True: 0, False: 0]
  ------------------
  922|      0|                if (copy > have) copy = have;
  ------------------
  |  Branch (922:21): [True: 0, False: 0]
  ------------------
  923|      0|                if (copy > left) copy = left;
  ------------------
  |  Branch (923:21): [True: 0, False: 0]
  ------------------
  924|      0|                if (copy == 0) goto inf_leave;
  ------------------
  |  Branch (924:21): [True: 0, False: 0]
  ------------------
  925|      0|                zmemcpy(put, next, copy);
  ------------------
  |  |  230|      0|#    define zmemcpy memcpy
  ------------------
  926|      0|                have -= copy;
  927|      0|                next += copy;
  928|      0|                left -= copy;
  929|      0|                put += copy;
  930|      0|                state->length -= copy;
  931|      0|                break;
  932|      0|            }
  933|      0|            Tracev((stderr, "inflate:       stored end\n"));
  934|      0|            state->mode = TYPE;
  935|      0|            break;
  936|     54|        case TABLE:
  ------------------
  |  Branch (936:9): [True: 54, False: 23.5k]
  ------------------
  937|     54|            NEEDBITS(14);
  ------------------
  |  |  520|     54|    do { \
  |  |  521|    154|        while (bits < (unsigned)(n)) \
  |  |  ------------------
  |  |  |  Branch (521:16): [True: 100, False: 54]
  |  |  ------------------
  |  |  522|    100|            PULLBYTE(); \
  |  |  ------------------
  |  |  |  |  510|    100|    do { \
  |  |  |  |  511|    100|        if (have == 0) goto inf_leave; \
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (511:13): [True: 0, False: 100]
  |  |  |  |  ------------------
  |  |  |  |  512|    100|        have--; \
  |  |  |  |  513|    100|        hold += (unsigned long)(*next++) << bits; \
  |  |  |  |  514|    100|        bits += 8; \
  |  |  |  |  515|    100|    } while (0)
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (515:14): [Folded, False: 100]
  |  |  |  |  ------------------
  |  |  ------------------
  |  |  523|     54|    } while (0)
  |  |  ------------------
  |  |  |  Branch (523:14): [Folded, False: 54]
  |  |  ------------------
  ------------------
  938|     54|            state->nlen = BITS(5) + 257;
  ------------------
  |  |  527|     54|    ((unsigned)hold & ((1U << (n)) - 1))
  ------------------
  939|     54|            DROPBITS(5);
  ------------------
  |  |  531|     54|    do { \
  |  |  532|     54|        hold >>= (n); \
  |  |  533|     54|        bits -= (unsigned)(n); \
  |  |  534|     54|    } while (0)
  |  |  ------------------
  |  |  |  Branch (534:14): [Folded, False: 54]
  |  |  ------------------
  ------------------
  940|     54|            state->ndist = BITS(5) + 1;
  ------------------
  |  |  527|     54|    ((unsigned)hold & ((1U << (n)) - 1))
  ------------------
  941|     54|            DROPBITS(5);
  ------------------
  |  |  531|     54|    do { \
  |  |  532|     54|        hold >>= (n); \
  |  |  533|     54|        bits -= (unsigned)(n); \
  |  |  534|     54|    } while (0)
  |  |  ------------------
  |  |  |  Branch (534:14): [Folded, False: 54]
  |  |  ------------------
  ------------------
  942|     54|            state->ncode = BITS(4) + 4;
  ------------------
  |  |  527|     54|    ((unsigned)hold & ((1U << (n)) - 1))
  ------------------
  943|     54|            DROPBITS(4);
  ------------------
  |  |  531|     54|    do { \
  |  |  532|     54|        hold >>= (n); \
  |  |  533|     54|        bits -= (unsigned)(n); \
  |  |  534|     54|    } while (0)
  |  |  ------------------
  |  |  |  Branch (534:14): [Folded, False: 54]
  |  |  ------------------
  ------------------
  944|     54|#ifndef PKZIP_BUG_WORKAROUND
  945|     54|            if (state->nlen > 286 || state->ndist > 30) {
  ------------------
  |  Branch (945:17): [True: 0, False: 54]
  |  Branch (945:38): [True: 0, False: 54]
  ------------------
  946|      0|                strm->msg = (char *)"too many length or distance symbols";
  947|      0|                state->mode = BAD;
  948|      0|                break;
  949|      0|            }
  950|     54|#endif
  951|     54|            Tracev((stderr, "inflate:       table sizes ok\n"));
  952|     54|            state->have = 0;
  953|     54|            state->mode = LENLENS;
  954|       |                /* fallthrough */
  955|     54|        case LENLENS:
  ------------------
  |  Branch (955:9): [True: 0, False: 23.5k]
  ------------------
  956|    916|            while (state->have < state->ncode) {
  ------------------
  |  Branch (956:20): [True: 862, False: 54]
  ------------------
  957|    862|                NEEDBITS(3);
  ------------------
  |  |  520|    862|    do { \
  |  |  521|  1.17k|        while (bits < (unsigned)(n)) \
  |  |  ------------------
  |  |  |  Branch (521:16): [True: 312, False: 862]
  |  |  ------------------
  |  |  522|    862|            PULLBYTE(); \
  |  |  ------------------
  |  |  |  |  510|    312|    do { \
  |  |  |  |  511|    312|        if (have == 0) goto inf_leave; \
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (511:13): [True: 0, False: 312]
  |  |  |  |  ------------------
  |  |  |  |  512|    312|        have--; \
  |  |  |  |  513|    312|        hold += (unsigned long)(*next++) << bits; \
  |  |  |  |  514|    312|        bits += 8; \
  |  |  |  |  515|    312|    } while (0)
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (515:14): [Folded, False: 312]
  |  |  |  |  ------------------
  |  |  ------------------
  |  |  523|    862|    } while (0)
  |  |  ------------------
  |  |  |  Branch (523:14): [Folded, False: 862]
  |  |  ------------------
  ------------------
  958|    862|                state->lens[order[state->have++]] = (unsigned short)BITS(3);
  ------------------
  |  |  527|    862|    ((unsigned)hold & ((1U << (n)) - 1))
  ------------------
  959|    862|                DROPBITS(3);
  ------------------
  |  |  531|    862|    do { \
  |  |  532|    862|        hold >>= (n); \
  |  |  533|    862|        bits -= (unsigned)(n); \
  |  |  534|    862|    } while (0)
  |  |  ------------------
  |  |  |  Branch (534:14): [Folded, False: 862]
  |  |  ------------------
  ------------------
  960|    862|            }
  961|    218|            while (state->have < 19)
  ------------------
  |  Branch (961:20): [True: 164, False: 54]
  ------------------
  962|    164|                state->lens[order[state->have++]] = 0;
  963|     54|            state->next = state->codes;
  964|     54|            state->lencode = (const code FAR *)(state->next);
  965|     54|            state->lenbits = 7;
  966|     54|            ret = inflate_table(CODES, state->lens, 19, &(state->next),
  967|     54|                                &(state->lenbits), state->work);
  968|     54|            if (ret) {
  ------------------
  |  Branch (968:17): [True: 0, False: 54]
  ------------------
  969|      0|                strm->msg = (char *)"invalid code lengths set";
  970|      0|                state->mode = BAD;
  971|      0|                break;
  972|      0|            }
  973|     54|            Tracev((stderr, "inflate:       code lengths ok\n"));
  974|     54|            state->have = 0;
  975|     54|            state->mode = CODELENS;
  976|       |                /* fallthrough */
  977|     54|        case CODELENS:
  ------------------
  |  Branch (977:9): [True: 0, False: 23.5k]
  ------------------
  978|  10.1k|            while (state->have < state->nlen + state->ndist) {
  ------------------
  |  Branch (978:20): [True: 10.0k, False: 54]
  ------------------
  979|  13.8k|                for (;;) {
  980|  13.8k|                    here = state->lencode[BITS(state->lenbits)];
  ------------------
  |  |  527|  13.8k|    ((unsigned)hold & ((1U << (n)) - 1))
  ------------------
  981|  13.8k|                    if ((unsigned)(here.bits) <= bits) break;
  ------------------
  |  Branch (981:25): [True: 10.0k, False: 3.78k]
  ------------------
  982|  3.78k|                    PULLBYTE();
  ------------------
  |  |  510|  3.78k|    do { \
  |  |  511|  3.78k|        if (have == 0) goto inf_leave; \
  |  |  ------------------
  |  |  |  Branch (511:13): [True: 0, False: 3.78k]
  |  |  ------------------
  |  |  512|  3.78k|        have--; \
  |  |  513|  3.78k|        hold += (unsigned long)(*next++) << bits; \
  |  |  514|  3.78k|        bits += 8; \
  |  |  515|  3.78k|    } while (0)
  |  |  ------------------
  |  |  |  Branch (515:14): [Folded, False: 3.78k]
  |  |  ------------------
  ------------------
  983|  3.78k|                }
  984|  10.0k|                if (here.val < 16) {
  ------------------
  |  Branch (984:21): [True: 9.11k, False: 974]
  ------------------
  985|  9.11k|                    DROPBITS(here.bits);
  ------------------
  |  |  531|  9.11k|    do { \
  |  |  532|  9.11k|        hold >>= (n); \
  |  |  533|  9.11k|        bits -= (unsigned)(n); \
  |  |  534|  9.11k|    } while (0)
  |  |  ------------------
  |  |  |  Branch (534:14): [Folded, False: 9.11k]
  |  |  ------------------
  ------------------
  986|  9.11k|                    state->lens[state->have++] = here.val;
  987|  9.11k|                }
  988|    974|                else {
  989|    974|                    if (here.val == 16) {
  ------------------
  |  Branch (989:25): [True: 818, False: 156]
  ------------------
  990|    818|                        NEEDBITS(here.bits + 2);
  ------------------
  |  |  520|    818|    do { \
  |  |  521|  1.03k|        while (bits < (unsigned)(n)) \
  |  |  ------------------
  |  |  |  Branch (521:16): [True: 215, False: 818]
  |  |  ------------------
  |  |  522|    818|            PULLBYTE(); \
  |  |  ------------------
  |  |  |  |  510|    215|    do { \
  |  |  |  |  511|    215|        if (have == 0) goto inf_leave; \
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (511:13): [True: 0, False: 215]
  |  |  |  |  ------------------
  |  |  |  |  512|    215|        have--; \
  |  |  |  |  513|    215|        hold += (unsigned long)(*next++) << bits; \
  |  |  |  |  514|    215|        bits += 8; \
  |  |  |  |  515|    215|    } while (0)
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (515:14): [Folded, False: 215]
  |  |  |  |  ------------------
  |  |  ------------------
  |  |  523|    818|    } while (0)
  |  |  ------------------
  |  |  |  Branch (523:14): [Folded, False: 818]
  |  |  ------------------
  ------------------
  991|    818|                        DROPBITS(here.bits);
  ------------------
  |  |  531|    818|    do { \
  |  |  532|    818|        hold >>= (n); \
  |  |  533|    818|        bits -= (unsigned)(n); \
  |  |  534|    818|    } while (0)
  |  |  ------------------
  |  |  |  Branch (534:14): [Folded, False: 818]
  |  |  ------------------
  ------------------
  992|    818|                        if (state->have == 0) {
  ------------------
  |  Branch (992:29): [True: 0, False: 818]
  ------------------
  993|      0|                            strm->msg = (char *)"invalid bit length repeat";
  994|      0|                            state->mode = BAD;
  995|      0|                            break;
  996|      0|                        }
  997|    818|                        len = state->lens[state->have - 1];
  998|    818|                        copy = 3 + BITS(2);
  ------------------
  |  |  527|    818|    ((unsigned)hold & ((1U << (n)) - 1))
  ------------------
  999|    818|                        DROPBITS(2);
  ------------------
  |  |  531|    818|    do { \
  |  |  532|    818|        hold >>= (n); \
  |  |  533|    818|        bits -= (unsigned)(n); \
  |  |  534|    818|    } while (0)
  |  |  ------------------
  |  |  |  Branch (534:14): [Folded, False: 818]
  |  |  ------------------
  ------------------
 1000|    818|                    }
 1001|    156|                    else if (here.val == 17) {
  ------------------
  |  Branch (1001:30): [True: 80, False: 76]
  ------------------
 1002|     80|                        NEEDBITS(here.bits + 3);
  ------------------
  |  |  520|     80|    do { \
  |  |  521|    105|        while (bits < (unsigned)(n)) \
  |  |  ------------------
  |  |  |  Branch (521:16): [True: 25, False: 80]
  |  |  ------------------
  |  |  522|     80|            PULLBYTE(); \
  |  |  ------------------
  |  |  |  |  510|     25|    do { \
  |  |  |  |  511|     25|        if (have == 0) goto inf_leave; \
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (511:13): [True: 0, False: 25]
  |  |  |  |  ------------------
  |  |  |  |  512|     25|        have--; \
  |  |  |  |  513|     25|        hold += (unsigned long)(*next++) << bits; \
  |  |  |  |  514|     25|        bits += 8; \
  |  |  |  |  515|     25|    } while (0)
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (515:14): [Folded, False: 25]
  |  |  |  |  ------------------
  |  |  ------------------
  |  |  523|     80|    } while (0)
  |  |  ------------------
  |  |  |  Branch (523:14): [Folded, False: 80]
  |  |  ------------------
  ------------------
 1003|     80|                        DROPBITS(here.bits);
  ------------------
  |  |  531|     80|    do { \
  |  |  532|     80|        hold >>= (n); \
  |  |  533|     80|        bits -= (unsigned)(n); \
  |  |  534|     80|    } while (0)
  |  |  ------------------
  |  |  |  Branch (534:14): [Folded, False: 80]
  |  |  ------------------
  ------------------
 1004|     80|                        len = 0;
 1005|     80|                        copy = 3 + BITS(3);
  ------------------
  |  |  527|     80|    ((unsigned)hold & ((1U << (n)) - 1))
  ------------------
 1006|     80|                        DROPBITS(3);
  ------------------
  |  |  531|     80|    do { \
  |  |  532|     80|        hold >>= (n); \
  |  |  533|     80|        bits -= (unsigned)(n); \
  |  |  534|     80|    } while (0)
  |  |  ------------------
  |  |  |  Branch (534:14): [Folded, False: 80]
  |  |  ------------------
  ------------------
 1007|     80|                    }
 1008|     76|                    else {
 1009|     76|                        NEEDBITS(here.bits + 7);
  ------------------
  |  |  520|     76|    do { \
  |  |  521|    142|        while (bits < (unsigned)(n)) \
  |  |  ------------------
  |  |  |  Branch (521:16): [True: 66, False: 76]
  |  |  ------------------
  |  |  522|     76|            PULLBYTE(); \
  |  |  ------------------
  |  |  |  |  510|     66|    do { \
  |  |  |  |  511|     66|        if (have == 0) goto inf_leave; \
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (511:13): [True: 0, False: 66]
  |  |  |  |  ------------------
  |  |  |  |  512|     66|        have--; \
  |  |  |  |  513|     66|        hold += (unsigned long)(*next++) << bits; \
  |  |  |  |  514|     66|        bits += 8; \
  |  |  |  |  515|     66|    } while (0)
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (515:14): [Folded, False: 66]
  |  |  |  |  ------------------
  |  |  ------------------
  |  |  523|     76|    } while (0)
  |  |  ------------------
  |  |  |  Branch (523:14): [Folded, False: 76]
  |  |  ------------------
  ------------------
 1010|     76|                        DROPBITS(here.bits);
  ------------------
  |  |  531|     76|    do { \
  |  |  532|     76|        hold >>= (n); \
  |  |  533|     76|        bits -= (unsigned)(n); \
  |  |  534|     76|    } while (0)
  |  |  ------------------
  |  |  |  Branch (534:14): [Folded, False: 76]
  |  |  ------------------
  ------------------
 1011|     76|                        len = 0;
 1012|     76|                        copy = 11 + BITS(7);
  ------------------
  |  |  527|     76|    ((unsigned)hold & ((1U << (n)) - 1))
  ------------------
 1013|     76|                        DROPBITS(7);
  ------------------
  |  |  531|     76|    do { \
  |  |  532|     76|        hold >>= (n); \
  |  |  533|     76|        bits -= (unsigned)(n); \
  |  |  534|     76|    } while (0)
  |  |  ------------------
  |  |  |  Branch (534:14): [Folded, False: 76]
  |  |  ------------------
  ------------------
 1014|     76|                    }
 1015|    974|                    if (state->have + copy > state->nlen + state->ndist) {
  ------------------
  |  Branch (1015:25): [True: 0, False: 974]
  ------------------
 1016|      0|                        strm->msg = (char *)"invalid bit length repeat";
 1017|      0|                        state->mode = BAD;
 1018|      0|                        break;
 1019|      0|                    }
 1020|  8.63k|                    while (copy--)
  ------------------
  |  Branch (1020:28): [True: 7.65k, False: 974]
  ------------------
 1021|  7.65k|                        state->lens[state->have++] = (unsigned short)len;
 1022|    974|                }
 1023|  10.0k|            }
 1024|       |
 1025|       |            /* handle error breaks in while */
 1026|     54|            if (state->mode == BAD) break;
  ------------------
  |  Branch (1026:17): [True: 0, False: 54]
  ------------------
 1027|       |
 1028|       |            /* check for end-of-block code (better have one) */
 1029|     54|            if (state->lens[256] == 0) {
  ------------------
  |  Branch (1029:17): [True: 0, False: 54]
  ------------------
 1030|      0|                strm->msg = (char *)"invalid code -- missing end-of-block";
 1031|      0|                state->mode = BAD;
 1032|      0|                break;
 1033|      0|            }
 1034|       |
 1035|       |            /* build code tables -- note: do not change the lenbits or distbits
 1036|       |               values here (9 and 6) without reading the comments in inftrees.h
 1037|       |               concerning the ENOUGH constants, which depend on those values */
 1038|     54|            state->next = state->codes;
 1039|     54|            state->lencode = (const code FAR *)(state->next);
 1040|     54|            state->lenbits = 9;
 1041|     54|            ret = inflate_table(LENS, state->lens, state->nlen, &(state->next),
 1042|     54|                                &(state->lenbits), state->work);
 1043|     54|            if (ret) {
  ------------------
  |  Branch (1043:17): [True: 0, False: 54]
  ------------------
 1044|      0|                strm->msg = (char *)"invalid literal/lengths set";
 1045|      0|                state->mode = BAD;
 1046|      0|                break;
 1047|      0|            }
 1048|     54|            state->distcode = (const code FAR *)(state->next);
 1049|     54|            state->distbits = 6;
 1050|     54|            ret = inflate_table(DISTS, state->lens + state->nlen, state->ndist,
 1051|     54|                            &(state->next), &(state->distbits), state->work);
 1052|     54|            if (ret) {
  ------------------
  |  Branch (1052:17): [True: 0, False: 54]
  ------------------
 1053|      0|                strm->msg = (char *)"invalid distances set";
 1054|      0|                state->mode = BAD;
 1055|      0|                break;
 1056|      0|            }
 1057|     54|            Tracev((stderr, "inflate:       codes ok\n"));
 1058|     54|            state->mode = LEN_;
 1059|     54|            if (flush == Z_TREES) goto inf_leave;
  ------------------
  |  |  174|     54|#define Z_TREES         6
  ------------------
  |  Branch (1059:17): [True: 0, False: 54]
  ------------------
 1060|       |                /* fallthrough */
 1061|     58|        case LEN_:
  ------------------
  |  Branch (1061:9): [True: 4, False: 23.5k]
  ------------------
 1062|     58|            state->mode = LEN;
 1063|       |                /* fallthrough */
 1064|  12.0k|        case LEN:
  ------------------
  |  Branch (1064:9): [True: 11.9k, False: 11.6k]
  ------------------
 1065|  12.0k|            if (have >= 6 && left >= 258) {
  ------------------
  |  Branch (1065:17): [True: 11.9k, False: 145]
  |  Branch (1065:30): [True: 3.23k, False: 8.67k]
  ------------------
 1066|  3.23k|                RESTORE();
  ------------------
  |  |  491|  3.23k|    do { \
  |  |  492|  3.23k|        strm->next_out = put; \
  |  |  493|  3.23k|        strm->avail_out = left; \
  |  |  494|  3.23k|        strm->next_in = next; \
  |  |  495|  3.23k|        strm->avail_in = have; \
  |  |  496|  3.23k|        state->hold = hold; \
  |  |  497|  3.23k|        state->bits = bits; \
  |  |  498|  3.23k|    } while (0)
  |  |  ------------------
  |  |  |  Branch (498:14): [Folded, False: 3.23k]
  |  |  ------------------
  ------------------
 1067|  3.23k|                inflate_fast(strm, out);
 1068|  3.23k|                LOAD();
  ------------------
  |  |  480|  3.23k|    do { \
  |  |  481|  3.23k|        put = strm->next_out; \
  |  |  482|  3.23k|        left = strm->avail_out; \
  |  |  483|  3.23k|        next = strm->next_in; \
  |  |  484|  3.23k|        have = strm->avail_in; \
  |  |  485|  3.23k|        hold = state->hold; \
  |  |  486|  3.23k|        bits = state->bits; \
  |  |  487|  3.23k|    } while (0)
  |  |  ------------------
  |  |  |  Branch (487:14): [Folded, False: 3.23k]
  |  |  ------------------
  ------------------
 1069|  3.23k|                if (state->mode == TYPE)
  ------------------
  |  Branch (1069:21): [True: 40, False: 3.19k]
  ------------------
 1070|     40|                    state->back = -1;
 1071|  3.23k|                break;
 1072|  3.23k|            }
 1073|  8.81k|            state->back = 0;
 1074|  12.9k|            for (;;) {
 1075|  12.9k|                here = state->lencode[BITS(state->lenbits)];
  ------------------
  |  |  527|  12.9k|    ((unsigned)hold & ((1U << (n)) - 1))
  ------------------
 1076|  12.9k|                if ((unsigned)(here.bits) <= bits) break;
  ------------------
  |  Branch (1076:21): [True: 8.80k, False: 4.14k]
  ------------------
 1077|  4.14k|                PULLBYTE();
  ------------------
  |  |  510|  4.14k|    do { \
  |  |  511|  4.14k|        if (have == 0) goto inf_leave; \
  |  |  ------------------
  |  |  |  Branch (511:13): [True: 11, False: 4.12k]
  |  |  ------------------
  |  |  512|  4.14k|        have--; \
  |  |  513|  4.12k|        hold += (unsigned long)(*next++) << bits; \
  |  |  514|  4.12k|        bits += 8; \
  |  |  515|  4.12k|    } while (0)
  |  |  ------------------
  |  |  |  Branch (515:14): [Folded, False: 4.12k]
  |  |  ------------------
  ------------------
 1078|  4.14k|            }
 1079|  8.80k|            if (here.op && (here.op & 0xf0) == 0) {
  ------------------
  |  Branch (1079:17): [True: 6.84k, False: 1.96k]
  |  Branch (1079:28): [True: 483, False: 6.35k]
  ------------------
 1080|    483|                last = here;
 1081|    571|                for (;;) {
 1082|    571|                    here = state->lencode[last.val +
 1083|    571|                            (BITS(last.bits + last.op) >> last.bits)];
  ------------------
  |  |  527|    571|    ((unsigned)hold & ((1U << (n)) - 1))
  ------------------
 1084|    571|                    if ((unsigned)(last.bits + here.bits) <= bits) break;
  ------------------
  |  Branch (1084:25): [True: 483, False: 88]
  ------------------
 1085|     88|                    PULLBYTE();
  ------------------
  |  |  510|     88|    do { \
  |  |  511|     88|        if (have == 0) goto inf_leave; \
  |  |  ------------------
  |  |  |  Branch (511:13): [True: 0, False: 88]
  |  |  ------------------
  |  |  512|     88|        have--; \
  |  |  513|     88|        hold += (unsigned long)(*next++) << bits; \
  |  |  514|     88|        bits += 8; \
  |  |  515|     88|    } while (0)
  |  |  ------------------
  |  |  |  Branch (515:14): [Folded, False: 88]
  |  |  ------------------
  ------------------
 1086|     88|                }
 1087|    483|                DROPBITS(last.bits);
  ------------------
  |  |  531|    483|    do { \
  |  |  532|    483|        hold >>= (n); \
  |  |  533|    483|        bits -= (unsigned)(n); \
  |  |  534|    483|    } while (0)
  |  |  ------------------
  |  |  |  Branch (534:14): [Folded, False: 483]
  |  |  ------------------
  ------------------
 1088|    483|                state->back += last.bits;
 1089|    483|            }
 1090|  8.80k|            DROPBITS(here.bits);
  ------------------
  |  |  531|  8.80k|    do { \
  |  |  532|  8.80k|        hold >>= (n); \
  |  |  533|  8.80k|        bits -= (unsigned)(n); \
  |  |  534|  8.80k|    } while (0)
  |  |  ------------------
  |  |  |  Branch (534:14): [Folded, False: 8.80k]
  |  |  ------------------
  ------------------
 1091|  8.80k|            state->back += here.bits;
 1092|  8.80k|            state->length = (unsigned)here.val;
 1093|  8.80k|            if ((int)(here.op) == 0) {
  ------------------
  |  Branch (1093:17): [True: 2.32k, False: 6.47k]
  ------------------
 1094|  2.32k|                Tracevv((stderr, here.val >= 0x20 && here.val < 0x7f ?
 1095|  2.32k|                        "inflate:         literal '%c'\n" :
 1096|  2.32k|                        "inflate:         literal 0x%02x\n", here.val));
 1097|  2.32k|                state->mode = LIT;
 1098|  2.32k|                break;
 1099|  2.32k|            }
 1100|  6.47k|            if (here.op & 32) {
  ------------------
  |  Branch (1100:17): [True: 8, False: 6.46k]
  ------------------
 1101|      8|                Tracevv((stderr, "inflate:         end of block\n"));
 1102|      8|                state->back = -1;
 1103|      8|                state->mode = TYPE;
 1104|      8|                break;
 1105|      8|            }
 1106|  6.46k|            if (here.op & 64) {
  ------------------
  |  Branch (1106:17): [True: 0, False: 6.46k]
  ------------------
 1107|      0|                strm->msg = (char *)"invalid literal/length code";
 1108|      0|                state->mode = BAD;
 1109|      0|                break;
 1110|      0|            }
 1111|  6.46k|            state->extra = (unsigned)(here.op) & 15;
 1112|  6.46k|            state->mode = LENEXT;
 1113|       |                /* fallthrough */
 1114|  6.46k|        case LENEXT:
  ------------------
  |  Branch (1114:9): [True: 0, False: 23.5k]
  ------------------
 1115|  6.46k|            if (state->extra) {
  ------------------
  |  Branch (1115:17): [True: 1.72k, False: 4.74k]
  ------------------
 1116|  1.72k|                NEEDBITS(state->extra);
  ------------------
  |  |  520|  1.72k|    do { \
  |  |  521|  2.08k|        while (bits < (unsigned)(n)) \
  |  |  ------------------
  |  |  |  Branch (521:16): [True: 359, False: 1.72k]
  |  |  ------------------
  |  |  522|  1.72k|            PULLBYTE(); \
  |  |  ------------------
  |  |  |  |  510|    359|    do { \
  |  |  |  |  511|    359|        if (have == 0) goto inf_leave; \
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (511:13): [True: 0, False: 359]
  |  |  |  |  ------------------
  |  |  |  |  512|    359|        have--; \
  |  |  |  |  513|    359|        hold += (unsigned long)(*next++) << bits; \
  |  |  |  |  514|    359|        bits += 8; \
  |  |  |  |  515|    359|    } while (0)
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (515:14): [Folded, False: 359]
  |  |  |  |  ------------------
  |  |  ------------------
  |  |  523|  1.72k|    } while (0)
  |  |  ------------------
  |  |  |  Branch (523:14): [Folded, False: 1.72k]
  |  |  ------------------
  ------------------
 1117|  1.72k|                state->length += BITS(state->extra);
  ------------------
  |  |  527|  1.72k|    ((unsigned)hold & ((1U << (n)) - 1))
  ------------------
 1118|  1.72k|                DROPBITS(state->extra);
  ------------------
  |  |  531|  1.72k|    do { \
  |  |  532|  1.72k|        hold >>= (n); \
  |  |  533|  1.72k|        bits -= (unsigned)(n); \
  |  |  534|  1.72k|    } while (0)
  |  |  ------------------
  |  |  |  Branch (534:14): [Folded, False: 1.72k]
  |  |  ------------------
  ------------------
 1119|  1.72k|                state->back += state->extra;
 1120|  1.72k|            }
 1121|  6.46k|            Tracevv((stderr, "inflate:         length %u\n", state->length));
 1122|  6.46k|            state->was = state->length;
 1123|  6.46k|            state->mode = DIST;
 1124|       |                /* fallthrough */
 1125|  6.47k|        case DIST:
  ------------------
  |  Branch (1125:9): [True: 3, False: 23.5k]
  ------------------
 1126|  8.76k|            for (;;) {
 1127|  8.76k|                here = state->distcode[BITS(state->distbits)];
  ------------------
  |  |  527|  8.76k|    ((unsigned)hold & ((1U << (n)) - 1))
  ------------------
 1128|  8.76k|                if ((unsigned)(here.bits) <= bits) break;
  ------------------
  |  Branch (1128:21): [True: 6.46k, False: 2.30k]
  ------------------
 1129|  2.30k|                PULLBYTE();
  ------------------
  |  |  510|  2.30k|    do { \
  |  |  511|  2.30k|        if (have == 0) goto inf_leave; \
  |  |  ------------------
  |  |  |  Branch (511:13): [True: 6, False: 2.29k]
  |  |  ------------------
  |  |  512|  2.30k|        have--; \
  |  |  513|  2.29k|        hold += (unsigned long)(*next++) << bits; \
  |  |  514|  2.29k|        bits += 8; \
  |  |  515|  2.29k|    } while (0)
  |  |  ------------------
  |  |  |  Branch (515:14): [Folded, False: 2.29k]
  |  |  ------------------
  ------------------
 1130|  2.30k|            }
 1131|  6.46k|            if ((here.op & 0xf0) == 0) {
  ------------------
  |  Branch (1131:17): [True: 146, False: 6.31k]
  ------------------
 1132|    146|                last = here;
 1133|    214|                for (;;) {
 1134|    214|                    here = state->distcode[last.val +
 1135|    214|                            (BITS(last.bits + last.op) >> last.bits)];
  ------------------
  |  |  527|    214|    ((unsigned)hold & ((1U << (n)) - 1))
  ------------------
 1136|    214|                    if ((unsigned)(last.bits + here.bits) <= bits) break;
  ------------------
  |  Branch (1136:25): [True: 146, False: 68]
  ------------------
 1137|     68|                    PULLBYTE();
  ------------------
  |  |  510|     68|    do { \
  |  |  511|     68|        if (have == 0) goto inf_leave; \
  |  |  ------------------
  |  |  |  Branch (511:13): [True: 0, False: 68]
  |  |  ------------------
  |  |  512|     68|        have--; \
  |  |  513|     68|        hold += (unsigned long)(*next++) << bits; \
  |  |  514|     68|        bits += 8; \
  |  |  515|     68|    } while (0)
  |  |  ------------------
  |  |  |  Branch (515:14): [Folded, False: 68]
  |  |  ------------------
  ------------------
 1138|     68|                }
 1139|    146|                DROPBITS(last.bits);
  ------------------
  |  |  531|    146|    do { \
  |  |  532|    146|        hold >>= (n); \
  |  |  533|    146|        bits -= (unsigned)(n); \
  |  |  534|    146|    } while (0)
  |  |  ------------------
  |  |  |  Branch (534:14): [Folded, False: 146]
  |  |  ------------------
  ------------------
 1140|    146|                state->back += last.bits;
 1141|    146|            }
 1142|  6.46k|            DROPBITS(here.bits);
  ------------------
  |  |  531|  6.46k|    do { \
  |  |  532|  6.46k|        hold >>= (n); \
  |  |  533|  6.46k|        bits -= (unsigned)(n); \
  |  |  534|  6.46k|    } while (0)
  |  |  ------------------
  |  |  |  Branch (534:14): [Folded, False: 6.46k]
  |  |  ------------------
  ------------------
 1143|  6.46k|            state->back += here.bits;
 1144|  6.46k|            if (here.op & 64) {
  ------------------
  |  Branch (1144:17): [True: 0, False: 6.46k]
  ------------------
 1145|      0|                strm->msg = (char *)"invalid distance code";
 1146|      0|                state->mode = BAD;
 1147|      0|                break;
 1148|      0|            }
 1149|  6.46k|            state->offset = (unsigned)here.val;
 1150|  6.46k|            state->extra = (unsigned)(here.op) & 15;
 1151|  6.46k|            state->mode = DISTEXT;
 1152|       |                /* fallthrough */
 1153|  6.47k|        case DISTEXT:
  ------------------
  |  Branch (1153:9): [True: 12, False: 23.5k]
  ------------------
 1154|  6.47k|            if (state->extra) {
  ------------------
  |  Branch (1154:17): [True: 3.37k, False: 3.10k]
  ------------------
 1155|  3.37k|                NEEDBITS(state->extra);
  ------------------
  |  |  520|  3.37k|    do { \
  |  |  521|  6.68k|        while (bits < (unsigned)(n)) \
  |  |  ------------------
  |  |  |  Branch (521:16): [True: 3.32k, False: 3.35k]
  |  |  ------------------
  |  |  522|  3.37k|            PULLBYTE(); \
  |  |  ------------------
  |  |  |  |  510|  3.32k|    do { \
  |  |  |  |  511|  3.32k|        if (have == 0) goto inf_leave; \
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (511:13): [True: 17, False: 3.31k]
  |  |  |  |  ------------------
  |  |  |  |  512|  3.32k|        have--; \
  |  |  |  |  513|  3.31k|        hold += (unsigned long)(*next++) << bits; \
  |  |  |  |  514|  3.31k|        bits += 8; \
  |  |  |  |  515|  3.31k|    } while (0)
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (515:14): [Folded, False: 3.31k]
  |  |  |  |  ------------------
  |  |  ------------------
  |  |  523|  3.37k|    } while (0)
  |  |  ------------------
  |  |  |  Branch (523:14): [Folded, False: 3.35k]
  |  |  ------------------
  ------------------
 1156|  3.35k|                state->offset += BITS(state->extra);
  ------------------
  |  |  527|  3.35k|    ((unsigned)hold & ((1U << (n)) - 1))
  ------------------
 1157|  3.35k|                DROPBITS(state->extra);
  ------------------
  |  |  531|  3.35k|    do { \
  |  |  532|  3.35k|        hold >>= (n); \
  |  |  533|  3.35k|        bits -= (unsigned)(n); \
  |  |  534|  3.35k|    } while (0)
  |  |  ------------------
  |  |  |  Branch (534:14): [Folded, False: 3.35k]
  |  |  ------------------
  ------------------
 1158|  3.35k|                state->back += state->extra;
 1159|  3.35k|            }
 1160|       |#ifdef INFLATE_STRICT
 1161|       |            if (state->offset > state->dmax) {
 1162|       |                strm->msg = (char *)"invalid distance too far back";
 1163|       |                state->mode = BAD;
 1164|       |                break;
 1165|       |            }
 1166|       |#endif
 1167|  6.46k|            Tracevv((stderr, "inflate:         distance %u\n", state->offset));
 1168|  6.46k|            state->mode = MATCH;
 1169|       |                /* fallthrough */
 1170|  15.5k|        case MATCH:
  ------------------
  |  Branch (1170:9): [True: 9.06k, False: 14.5k]
  ------------------
 1171|  15.5k|            if (left == 0) goto inf_leave;
  ------------------
  |  Branch (1171:17): [True: 3.13k, False: 12.3k]
  ------------------
 1172|  12.3k|            copy = out - left;
 1173|  12.3k|            if (state->offset > copy) {         /* copy from window */
  ------------------
  |  Branch (1173:17): [True: 3.22k, False: 9.17k]
  ------------------
 1174|  3.22k|                copy = state->offset - copy;
 1175|  3.22k|                if (copy > state->whave) {
  ------------------
  |  Branch (1175:21): [True: 0, False: 3.22k]
  ------------------
 1176|      0|                    if (state->sane) {
  ------------------
  |  Branch (1176:25): [True: 0, False: 0]
  ------------------
 1177|      0|                        strm->msg = (char *)"invalid distance too far back";
 1178|      0|                        state->mode = BAD;
 1179|      0|                        break;
 1180|      0|                    }
 1181|       |#ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR
 1182|       |                    Trace((stderr, "inflate.c too far\n"));
 1183|       |                    copy -= state->whave;
 1184|       |                    if (copy > state->length) copy = state->length;
 1185|       |                    if (copy > left) copy = left;
 1186|       |                    left -= copy;
 1187|       |                    state->length -= copy;
 1188|       |                    do {
 1189|       |                        *put++ = 0;
 1190|       |                    } while (--copy);
 1191|       |                    if (state->length == 0) state->mode = LEN;
 1192|       |                    break;
 1193|       |#endif
 1194|      0|                }
 1195|  3.22k|                if (copy > state->wnext) {
  ------------------
  |  Branch (1195:21): [True: 3.21k, False: 8]
  ------------------
 1196|  3.21k|                    copy -= state->wnext;
 1197|  3.21k|                    from = state->window + (state->wsize - copy);
 1198|  3.21k|                }
 1199|      8|                else
 1200|      8|                    from = state->window + (state->wnext - copy);
 1201|  3.22k|                if (copy > state->length) copy = state->length;
  ------------------
  |  Branch (1201:21): [True: 389, False: 2.83k]
  ------------------
 1202|  3.22k|            }
 1203|  9.17k|            else {                              /* copy from output */
 1204|  9.17k|                from = put - state->offset;
 1205|  9.17k|                copy = state->length;
 1206|  9.17k|            }
 1207|  12.3k|            if (copy > left) copy = left;
  ------------------
  |  Branch (1207:17): [True: 3.11k, False: 9.28k]
  ------------------
 1208|  12.3k|            left -= copy;
 1209|  12.3k|            state->length -= copy;
 1210|   822k|            do {
 1211|   822k|                *put++ = *from++;
 1212|   822k|            } while (--copy);
  ------------------
  |  Branch (1212:22): [True: 809k, False: 12.3k]
  ------------------
 1213|  12.3k|            if (state->length == 0) state->mode = LEN;
  ------------------
  |  Branch (1213:17): [True: 6.46k, False: 5.93k]
  ------------------
 1214|  12.3k|            break;
 1215|  2.33k|        case LIT:
  ------------------
  |  Branch (1215:9): [True: 2.33k, False: 21.2k]
  ------------------
 1216|  2.33k|            if (left == 0) goto inf_leave;
  ------------------
  |  Branch (1216:17): [True: 8, False: 2.32k]
  ------------------
 1217|  2.32k|            *put++ = (unsigned char)(state->length);
 1218|  2.32k|            left--;
 1219|  2.32k|            state->mode = LEN;
 1220|  2.32k|            break;
 1221|     16|        case CHECK:
  ------------------
  |  Branch (1221:9): [True: 16, False: 23.5k]
  ------------------
 1222|     16|            if (state->wrap) {
  ------------------
  |  Branch (1222:17): [True: 8, False: 8]
  ------------------
 1223|      8|                NEEDBITS(32);
  ------------------
  |  |  520|      8|    do { \
  |  |  521|     40|        while (bits < (unsigned)(n)) \
  |  |  ------------------
  |  |  |  Branch (521:16): [True: 32, False: 8]
  |  |  ------------------
  |  |  522|     32|            PULLBYTE(); \
  |  |  ------------------
  |  |  |  |  510|     32|    do { \
  |  |  |  |  511|     32|        if (have == 0) goto inf_leave; \
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (511:13): [True: 0, False: 32]
  |  |  |  |  ------------------
  |  |  |  |  512|     32|        have--; \
  |  |  |  |  513|     32|        hold += (unsigned long)(*next++) << bits; \
  |  |  |  |  514|     32|        bits += 8; \
  |  |  |  |  515|     32|    } while (0)
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (515:14): [Folded, False: 32]
  |  |  |  |  ------------------
  |  |  ------------------
  |  |  523|      8|    } while (0)
  |  |  ------------------
  |  |  |  Branch (523:14): [Folded, False: 8]
  |  |  ------------------
  ------------------
 1224|      8|                out -= left;
 1225|      8|                strm->total_out += out;
 1226|      8|                state->total += out;
 1227|      8|                if ((state->wrap & 4) && out)
  ------------------
  |  Branch (1227:21): [True: 8, False: 0]
  |  Branch (1227:42): [True: 8, False: 0]
  ------------------
 1228|      8|                    strm->adler = state->check =
 1229|      8|                        UPDATE_CHECK(state->check, put - out, out);
  ------------------
  |  |  454|      8|    (state->flags ? crc32(check, buf, len) : adler32(check, buf, len))
  |  |  ------------------
  |  |  |  Branch (454:6): [True: 8, False: 0]
  |  |  ------------------
  ------------------
 1230|      8|                out = left;
 1231|      8|                if ((state->wrap & 4) && (
  ------------------
  |  Branch (1231:21): [True: 8, False: 0]
  |  Branch (1231:42): [True: 0, False: 8]
  ------------------
 1232|      8|#ifdef GUNZIP
 1233|      8|                     state->flags ? hold :
  ------------------
  |  Branch (1233:22): [True: 8, False: 0]
  ------------------
 1234|      8|#endif
 1235|      8|                     ZSWAP32(hold)) != state->check) {
  ------------------
  |  |  272|      0|#define ZSWAP32(q) ((((q) >> 24) & 0xff) + (((q) >> 8) & 0xff00) + \
  |  |  273|      0|                    (((q) & 0xff00) << 8) + (((q) & 0xff) << 24))
  ------------------
 1236|      0|                    strm->msg = (char *)"incorrect data check";
 1237|      0|                    state->mode = BAD;
 1238|      0|                    break;
 1239|      0|                }
 1240|      8|                INITBITS();
  ------------------
  |  |  502|      8|    do { \
  |  |  503|      8|        hold = 0; \
  |  |  504|      8|        bits = 0; \
  |  |  505|      8|    } while (0)
  |  |  ------------------
  |  |  |  Branch (505:14): [Folded, False: 8]
  |  |  ------------------
  ------------------
 1241|      8|                Tracev((stderr, "inflate:   check matches trailer\n"));
 1242|      8|            }
 1243|     16|#ifdef GUNZIP
 1244|     16|            state->mode = LENGTH;
 1245|       |                /* fallthrough */
 1246|     16|        case LENGTH:
  ------------------
  |  Branch (1246:9): [True: 0, False: 23.5k]
  ------------------
 1247|     16|            if (state->wrap && state->flags) {
  ------------------
  |  Branch (1247:17): [True: 8, False: 8]
  |  Branch (1247:32): [True: 8, False: 0]
  ------------------
 1248|      8|                NEEDBITS(32);
  ------------------
  |  |  520|      8|    do { \
  |  |  521|     40|        while (bits < (unsigned)(n)) \
  |  |  ------------------
  |  |  |  Branch (521:16): [True: 32, False: 8]
  |  |  ------------------
  |  |  522|     32|            PULLBYTE(); \
  |  |  ------------------
  |  |  |  |  510|     32|    do { \
  |  |  |  |  511|     32|        if (have == 0) goto inf_leave; \
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (511:13): [True: 0, False: 32]
  |  |  |  |  ------------------
  |  |  |  |  512|     32|        have--; \
  |  |  |  |  513|     32|        hold += (unsigned long)(*next++) << bits; \
  |  |  |  |  514|     32|        bits += 8; \
  |  |  |  |  515|     32|    } while (0)
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (515:14): [Folded, False: 32]
  |  |  |  |  ------------------
  |  |  ------------------
  |  |  523|      8|    } while (0)
  |  |  ------------------
  |  |  |  Branch (523:14): [Folded, False: 8]
  |  |  ------------------
  ------------------
 1249|      8|                if ((state->wrap & 4) && hold != (state->total & 0xffffffff)) {
  ------------------
  |  Branch (1249:21): [True: 8, False: 0]
  |  Branch (1249:42): [True: 0, False: 8]
  ------------------
 1250|      0|                    strm->msg = (char *)"incorrect length check";
 1251|      0|                    state->mode = BAD;
 1252|      0|                    break;
 1253|      0|                }
 1254|      8|                INITBITS();
  ------------------
  |  |  502|      8|    do { \
  |  |  503|      8|        hold = 0; \
  |  |  504|      8|        bits = 0; \
  |  |  505|      8|    } while (0)
  |  |  ------------------
  |  |  |  Branch (505:14): [Folded, False: 8]
  |  |  ------------------
  ------------------
 1255|      8|                Tracev((stderr, "inflate:   length matches trailer\n"));
 1256|      8|            }
 1257|     16|#endif
 1258|     16|            state->mode = DONE;
 1259|       |                /* fallthrough */
 1260|     16|        case DONE:
  ------------------
  |  Branch (1260:9): [True: 0, False: 23.5k]
  ------------------
 1261|     16|            ret = Z_STREAM_END;
  ------------------
  |  |  178|     16|#define Z_STREAM_END    1
  ------------------
 1262|     16|            goto inf_leave;
 1263|      0|        case BAD:
  ------------------
  |  Branch (1263:9): [True: 0, False: 23.5k]
  ------------------
 1264|      0|            ret = Z_DATA_ERROR;
  ------------------
  |  |  182|      0|#define Z_DATA_ERROR   (-3)
  ------------------
 1265|      0|            goto inf_leave;
 1266|      0|        case MEM:
  ------------------
  |  Branch (1266:9): [True: 0, False: 23.5k]
  ------------------
 1267|      0|            return Z_MEM_ERROR;
  ------------------
  |  |  183|      0|#define Z_MEM_ERROR    (-4)
  ------------------
 1268|      0|        case SYNC:
  ------------------
  |  Branch (1268:9): [True: 0, False: 23.5k]
  ------------------
 1269|       |                /* fallthrough */
 1270|      0|        default:
  ------------------
  |  Branch (1270:9): [True: 0, False: 23.5k]
  ------------------
 1271|      0|            return Z_STREAM_ERROR;
  ------------------
  |  |  181|      0|#define Z_STREAM_ERROR (-2)
  ------------------
 1272|  23.5k|        }
 1273|       |
 1274|       |    /*
 1275|       |       Return from inflate(), updating the total counts and the check value.
 1276|       |       If there was no progress during the inflate() call, return a buffer
 1277|       |       error.  Call updatewindow() to create and/or update the window state.
 1278|       |       Note: a memory error from inflate() is non-recoverable.
 1279|       |     */
 1280|  3.18k|  inf_leave:
 1281|  3.18k|    RESTORE();
  ------------------
  |  |  491|  3.18k|    do { \
  |  |  492|  3.18k|        strm->next_out = put; \
  |  |  493|  3.18k|        strm->avail_out = left; \
  |  |  494|  3.18k|        strm->next_in = next; \
  |  |  495|  3.18k|        strm->avail_in = have; \
  |  |  496|  3.18k|        state->hold = hold; \
  |  |  497|  3.18k|        state->bits = bits; \
  |  |  498|  3.18k|    } while (0)
  |  |  ------------------
  |  |  |  Branch (498:14): [Folded, False: 3.18k]
  |  |  ------------------
  ------------------
 1282|  3.18k|    if (state->wsize || (out != strm->avail_out && state->mode < BAD &&
  ------------------
  |  Branch (1282:9): [True: 3.16k, False: 26]
  |  Branch (1282:26): [True: 26, False: 0]
  |  Branch (1282:52): [True: 26, False: 0]
  ------------------
 1283|     26|            (state->mode < CHECK || flush != Z_FINISH)))
  ------------------
  |  |  172|      4|#define Z_FINISH        4
  ------------------
  |  Branch (1283:14): [True: 22, False: 4]
  |  Branch (1283:37): [True: 4, False: 0]
  ------------------
 1284|  3.18k|        if (updatewindow(strm, strm->next_out, out - strm->avail_out)) {
  ------------------
  |  Branch (1284:13): [True: 0, False: 3.18k]
  ------------------
 1285|      0|            state->mode = MEM;
 1286|      0|            return Z_MEM_ERROR;
  ------------------
  |  |  183|      0|#define Z_MEM_ERROR    (-4)
  ------------------
 1287|      0|        }
 1288|  3.18k|    in -= strm->avail_in;
 1289|  3.18k|    out -= strm->avail_out;
 1290|  3.18k|    strm->total_in += in;
 1291|  3.18k|    strm->total_out += out;
 1292|  3.18k|    state->total += out;
 1293|  3.18k|    if ((state->wrap & 4) && out)
  ------------------
  |  Branch (1293:9): [True: 3.15k, False: 30]
  |  Branch (1293:30): [True: 3.14k, False: 18]
  ------------------
 1294|  3.14k|        strm->adler = state->check =
 1295|  3.14k|            UPDATE_CHECK(state->check, strm->next_out - out, out);
  ------------------
  |  |  454|  3.14k|    (state->flags ? crc32(check, buf, len) : adler32(check, buf, len))
  |  |  ------------------
  |  |  |  Branch (454:6): [True: 3.14k, False: 0]
  |  |  ------------------
  ------------------
 1296|  3.18k|    strm->data_type = (int)state->bits + (state->last ? 64 : 0) +
  ------------------
  |  Branch (1296:43): [True: 3.05k, False: 134]
  ------------------
 1297|  3.18k|                      (state->mode == TYPE ? 128 : 0) +
  ------------------
  |  Branch (1297:24): [True: 0, False: 3.18k]
  ------------------
 1298|  3.18k|                      (state->mode == LEN_ || state->mode == COPY_ ? 256 : 0);
  ------------------
  |  Branch (1298:24): [True: 0, False: 3.18k]
  |  Branch (1298:47): [True: 0, False: 3.18k]
  ------------------
 1299|  3.18k|    if (((in == 0 && out == 0) || flush == Z_FINISH) && ret == Z_OK)
  ------------------
  |  |  172|  3.17k|#define Z_FINISH        4
  ------------------
                  if (((in == 0 && out == 0) || flush == Z_FINISH) && ret == Z_OK)
  ------------------
  |  |  177|     10|#define Z_OK            0
  ------------------
  |  Branch (1299:11): [True: 10, False: 3.17k]
  |  Branch (1299:22): [True: 10, False: 0]
  |  Branch (1299:35): [True: 0, False: 3.17k]
  |  Branch (1299:57): [True: 10, False: 0]
  ------------------
 1300|     10|        ret = Z_BUF_ERROR;
  ------------------
  |  |  184|     10|#define Z_BUF_ERROR    (-5)
  ------------------
 1301|  3.18k|    return ret;
 1302|  3.18k|}
inflateEnd:
 1306|     26|{
 1307|     26|    struct inflate_state FAR *state;
 1308|     26|    if (inflateStateCheck(strm))
  ------------------
  |  Branch (1308:9): [True: 0, False: 26]
  ------------------
 1309|      0|        return Z_STREAM_ERROR;
  ------------------
  |  |  181|      0|#define Z_STREAM_ERROR (-2)
  ------------------
 1310|     26|    state = (struct inflate_state FAR *)strm->state;
 1311|     26|    if (state->window != Z_NULL) ZFREE(strm, state->window);
  ------------------
  |  |  212|     26|#define Z_NULL  0  /* for initializing zalloc, zfree, opaque */
  ------------------
                  if (state->window != Z_NULL) ZFREE(strm, state->window);
  ------------------
  |  |  268|     26|#define ZFREE(strm, addr)  (*((strm)->zfree))((strm)->opaque, (voidpf)(addr))
  ------------------
  |  Branch (1311:9): [True: 26, False: 0]
  ------------------
 1312|     26|    ZFREE(strm, strm->state);
  ------------------
  |  |  268|     26|#define ZFREE(strm, addr)  (*((strm)->zfree))((strm)->opaque, (voidpf)(addr))
  ------------------
 1313|     26|    strm->state = Z_NULL;
  ------------------
  |  |  212|     26|#define Z_NULL  0  /* for initializing zalloc, zfree, opaque */
  ------------------
 1314|     26|    Tracev((stderr, "inflate: end\n"));
 1315|     26|    return Z_OK;
  ------------------
  |  |  177|     26|#define Z_OK            0
  ------------------
 1316|     26|}
inflate.c:inflateStateCheck:
  107|  3.29k|{
  108|  3.29k|    struct inflate_state FAR *state;
  109|  3.29k|    if (strm == Z_NULL ||
  ------------------
  |  |  212|  6.58k|#define Z_NULL  0  /* for initializing zalloc, zfree, opaque */
  ------------------
  |  Branch (109:9): [True: 0, False: 3.29k]
  ------------------
  110|  3.29k|        strm->zalloc == (alloc_func)0 || strm->zfree == (free_func)0)
  ------------------
  |  Branch (110:9): [True: 0, False: 3.29k]
  |  Branch (110:42): [True: 0, False: 3.29k]
  ------------------
  111|      0|        return 1;
  112|  3.29k|    state = (struct inflate_state FAR *)strm->state;
  113|  3.29k|    if (state == Z_NULL || state->strm != strm ||
  ------------------
  |  |  212|  6.58k|#define Z_NULL  0  /* for initializing zalloc, zfree, opaque */
  ------------------
  |  Branch (113:9): [True: 0, False: 3.29k]
  |  Branch (113:28): [True: 0, False: 3.29k]
  ------------------
  114|  3.29k|        state->mode < HEAD || state->mode > SYNC)
  ------------------
  |  Branch (114:9): [True: 0, False: 3.29k]
  |  Branch (114:31): [True: 0, False: 3.29k]
  ------------------
  115|      0|        return 1;
  116|  3.29k|    return 0;
  117|  3.29k|}
inflate.c:fixedtables:
  283|      4|{
  284|       |#ifdef BUILDFIXED
  285|       |    static int virgin = 1;
  286|       |    static code *lenfix, *distfix;
  287|       |    static code fixed[544];
  288|       |
  289|       |    /* build fixed huffman tables if first call (may not be thread safe) */
  290|       |    if (virgin) {
  291|       |        unsigned sym, bits;
  292|       |        static code *next;
  293|       |
  294|       |        /* literal/length table */
  295|       |        sym = 0;
  296|       |        while (sym < 144) state->lens[sym++] = 8;
  297|       |        while (sym < 256) state->lens[sym++] = 9;
  298|       |        while (sym < 280) state->lens[sym++] = 7;
  299|       |        while (sym < 288) state->lens[sym++] = 8;
  300|       |        next = fixed;
  301|       |        lenfix = next;
  302|       |        bits = 9;
  303|       |        inflate_table(LENS, state->lens, 288, &(next), &(bits), state->work);
  304|       |
  305|       |        /* distance table */
  306|       |        sym = 0;
  307|       |        while (sym < 32) state->lens[sym++] = 5;
  308|       |        distfix = next;
  309|       |        bits = 5;
  310|       |        inflate_table(DISTS, state->lens, 32, &(next), &(bits), state->work);
  311|       |
  312|       |        /* do this just once */
  313|       |        virgin = 0;
  314|       |    }
  315|       |#else /* !BUILDFIXED */
  316|      4|#   include "inffixed.h"
  ------------------
  |  |    1|       |    /* inffixed.h -- table for decoding fixed codes
  |  |    2|       |     * Generated automatically by makefixed().
  |  |    3|       |     */
  |  |    4|       |
  |  |    5|       |    /* WARNING: this file should *not* be used by applications.
  |  |    6|       |       It is part of the implementation of this library and is
  |  |    7|       |       subject to change. Applications should only use zlib.h.
  |  |    8|       |     */
  |  |    9|       |
  |  |   10|      4|    static const code lenfix[512] = {
  |  |   11|      4|        {96,7,0},{0,8,80},{0,8,16},{20,8,115},{18,7,31},{0,8,112},{0,8,48},
  |  |   12|      4|        {0,9,192},{16,7,10},{0,8,96},{0,8,32},{0,9,160},{0,8,0},{0,8,128},
  |  |   13|      4|        {0,8,64},{0,9,224},{16,7,6},{0,8,88},{0,8,24},{0,9,144},{19,7,59},
  |  |   14|      4|        {0,8,120},{0,8,56},{0,9,208},{17,7,17},{0,8,104},{0,8,40},{0,9,176},
  |  |   15|      4|        {0,8,8},{0,8,136},{0,8,72},{0,9,240},{16,7,4},{0,8,84},{0,8,20},
  |  |   16|      4|        {21,8,227},{19,7,43},{0,8,116},{0,8,52},{0,9,200},{17,7,13},{0,8,100},
  |  |   17|      4|        {0,8,36},{0,9,168},{0,8,4},{0,8,132},{0,8,68},{0,9,232},{16,7,8},
  |  |   18|      4|        {0,8,92},{0,8,28},{0,9,152},{20,7,83},{0,8,124},{0,8,60},{0,9,216},
  |  |   19|      4|        {18,7,23},{0,8,108},{0,8,44},{0,9,184},{0,8,12},{0,8,140},{0,8,76},
  |  |   20|      4|        {0,9,248},{16,7,3},{0,8,82},{0,8,18},{21,8,163},{19,7,35},{0,8,114},
  |  |   21|      4|        {0,8,50},{0,9,196},{17,7,11},{0,8,98},{0,8,34},{0,9,164},{0,8,2},
  |  |   22|      4|        {0,8,130},{0,8,66},{0,9,228},{16,7,7},{0,8,90},{0,8,26},{0,9,148},
  |  |   23|      4|        {20,7,67},{0,8,122},{0,8,58},{0,9,212},{18,7,19},{0,8,106},{0,8,42},
  |  |   24|      4|        {0,9,180},{0,8,10},{0,8,138},{0,8,74},{0,9,244},{16,7,5},{0,8,86},
  |  |   25|      4|        {0,8,22},{64,8,0},{19,7,51},{0,8,118},{0,8,54},{0,9,204},{17,7,15},
  |  |   26|      4|        {0,8,102},{0,8,38},{0,9,172},{0,8,6},{0,8,134},{0,8,70},{0,9,236},
  |  |   27|      4|        {16,7,9},{0,8,94},{0,8,30},{0,9,156},{20,7,99},{0,8,126},{0,8,62},
  |  |   28|      4|        {0,9,220},{18,7,27},{0,8,110},{0,8,46},{0,9,188},{0,8,14},{0,8,142},
  |  |   29|      4|        {0,8,78},{0,9,252},{96,7,0},{0,8,81},{0,8,17},{21,8,131},{18,7,31},
  |  |   30|      4|        {0,8,113},{0,8,49},{0,9,194},{16,7,10},{0,8,97},{0,8,33},{0,9,162},
  |  |   31|      4|        {0,8,1},{0,8,129},{0,8,65},{0,9,226},{16,7,6},{0,8,89},{0,8,25},
  |  |   32|      4|        {0,9,146},{19,7,59},{0,8,121},{0,8,57},{0,9,210},{17,7,17},{0,8,105},
  |  |   33|      4|        {0,8,41},{0,9,178},{0,8,9},{0,8,137},{0,8,73},{0,9,242},{16,7,4},
  |  |   34|      4|        {0,8,85},{0,8,21},{16,8,258},{19,7,43},{0,8,117},{0,8,53},{0,9,202},
  |  |   35|      4|        {17,7,13},{0,8,101},{0,8,37},{0,9,170},{0,8,5},{0,8,133},{0,8,69},
  |  |   36|      4|        {0,9,234},{16,7,8},{0,8,93},{0,8,29},{0,9,154},{20,7,83},{0,8,125},
  |  |   37|      4|        {0,8,61},{0,9,218},{18,7,23},{0,8,109},{0,8,45},{0,9,186},{0,8,13},
  |  |   38|      4|        {0,8,141},{0,8,77},{0,9,250},{16,7,3},{0,8,83},{0,8,19},{21,8,195},
  |  |   39|      4|        {19,7,35},{0,8,115},{0,8,51},{0,9,198},{17,7,11},{0,8,99},{0,8,35},
  |  |   40|      4|        {0,9,166},{0,8,3},{0,8,131},{0,8,67},{0,9,230},{16,7,7},{0,8,91},
  |  |   41|      4|        {0,8,27},{0,9,150},{20,7,67},{0,8,123},{0,8,59},{0,9,214},{18,7,19},
  |  |   42|      4|        {0,8,107},{0,8,43},{0,9,182},{0,8,11},{0,8,139},{0,8,75},{0,9,246},
  |  |   43|      4|        {16,7,5},{0,8,87},{0,8,23},{64,8,0},{19,7,51},{0,8,119},{0,8,55},
  |  |   44|      4|        {0,9,206},{17,7,15},{0,8,103},{0,8,39},{0,9,174},{0,8,7},{0,8,135},
  |  |   45|      4|        {0,8,71},{0,9,238},{16,7,9},{0,8,95},{0,8,31},{0,9,158},{20,7,99},
  |  |   46|      4|        {0,8,127},{0,8,63},{0,9,222},{18,7,27},{0,8,111},{0,8,47},{0,9,190},
  |  |   47|      4|        {0,8,15},{0,8,143},{0,8,79},{0,9,254},{96,7,0},{0,8,80},{0,8,16},
  |  |   48|      4|        {20,8,115},{18,7,31},{0,8,112},{0,8,48},{0,9,193},{16,7,10},{0,8,96},
  |  |   49|      4|        {0,8,32},{0,9,161},{0,8,0},{0,8,128},{0,8,64},{0,9,225},{16,7,6},
  |  |   50|      4|        {0,8,88},{0,8,24},{0,9,145},{19,7,59},{0,8,120},{0,8,56},{0,9,209},
  |  |   51|      4|        {17,7,17},{0,8,104},{0,8,40},{0,9,177},{0,8,8},{0,8,136},{0,8,72},
  |  |   52|      4|        {0,9,241},{16,7,4},{0,8,84},{0,8,20},{21,8,227},{19,7,43},{0,8,116},
  |  |   53|      4|        {0,8,52},{0,9,201},{17,7,13},{0,8,100},{0,8,36},{0,9,169},{0,8,4},
  |  |   54|      4|        {0,8,132},{0,8,68},{0,9,233},{16,7,8},{0,8,92},{0,8,28},{0,9,153},
  |  |   55|      4|        {20,7,83},{0,8,124},{0,8,60},{0,9,217},{18,7,23},{0,8,108},{0,8,44},
  |  |   56|      4|        {0,9,185},{0,8,12},{0,8,140},{0,8,76},{0,9,249},{16,7,3},{0,8,82},
  |  |   57|      4|        {0,8,18},{21,8,163},{19,7,35},{0,8,114},{0,8,50},{0,9,197},{17,7,11},
  |  |   58|      4|        {0,8,98},{0,8,34},{0,9,165},{0,8,2},{0,8,130},{0,8,66},{0,9,229},
  |  |   59|      4|        {16,7,7},{0,8,90},{0,8,26},{0,9,149},{20,7,67},{0,8,122},{0,8,58},
  |  |   60|      4|        {0,9,213},{18,7,19},{0,8,106},{0,8,42},{0,9,181},{0,8,10},{0,8,138},
  |  |   61|      4|        {0,8,74},{0,9,245},{16,7,5},{0,8,86},{0,8,22},{64,8,0},{19,7,51},
  |  |   62|      4|        {0,8,118},{0,8,54},{0,9,205},{17,7,15},{0,8,102},{0,8,38},{0,9,173},
  |  |   63|      4|        {0,8,6},{0,8,134},{0,8,70},{0,9,237},{16,7,9},{0,8,94},{0,8,30},
  |  |   64|      4|        {0,9,157},{20,7,99},{0,8,126},{0,8,62},{0,9,221},{18,7,27},{0,8,110},
  |  |   65|      4|        {0,8,46},{0,9,189},{0,8,14},{0,8,142},{0,8,78},{0,9,253},{96,7,0},
  |  |   66|      4|        {0,8,81},{0,8,17},{21,8,131},{18,7,31},{0,8,113},{0,8,49},{0,9,195},
  |  |   67|      4|        {16,7,10},{0,8,97},{0,8,33},{0,9,163},{0,8,1},{0,8,129},{0,8,65},
  |  |   68|      4|        {0,9,227},{16,7,6},{0,8,89},{0,8,25},{0,9,147},{19,7,59},{0,8,121},
  |  |   69|      4|        {0,8,57},{0,9,211},{17,7,17},{0,8,105},{0,8,41},{0,9,179},{0,8,9},
  |  |   70|      4|        {0,8,137},{0,8,73},{0,9,243},{16,7,4},{0,8,85},{0,8,21},{16,8,258},
  |  |   71|      4|        {19,7,43},{0,8,117},{0,8,53},{0,9,203},{17,7,13},{0,8,101},{0,8,37},
  |  |   72|      4|        {0,9,171},{0,8,5},{0,8,133},{0,8,69},{0,9,235},{16,7,8},{0,8,93},
  |  |   73|      4|        {0,8,29},{0,9,155},{20,7,83},{0,8,125},{0,8,61},{0,9,219},{18,7,23},
  |  |   74|      4|        {0,8,109},{0,8,45},{0,9,187},{0,8,13},{0,8,141},{0,8,77},{0,9,251},
  |  |   75|      4|        {16,7,3},{0,8,83},{0,8,19},{21,8,195},{19,7,35},{0,8,115},{0,8,51},
  |  |   76|      4|        {0,9,199},{17,7,11},{0,8,99},{0,8,35},{0,9,167},{0,8,3},{0,8,131},
  |  |   77|      4|        {0,8,67},{0,9,231},{16,7,7},{0,8,91},{0,8,27},{0,9,151},{20,7,67},
  |  |   78|      4|        {0,8,123},{0,8,59},{0,9,215},{18,7,19},{0,8,107},{0,8,43},{0,9,183},
  |  |   79|      4|        {0,8,11},{0,8,139},{0,8,75},{0,9,247},{16,7,5},{0,8,87},{0,8,23},
  |  |   80|      4|        {64,8,0},{19,7,51},{0,8,119},{0,8,55},{0,9,207},{17,7,15},{0,8,103},
  |  |   81|      4|        {0,8,39},{0,9,175},{0,8,7},{0,8,135},{0,8,71},{0,9,239},{16,7,9},
  |  |   82|      4|        {0,8,95},{0,8,31},{0,9,159},{20,7,99},{0,8,127},{0,8,63},{0,9,223},
  |  |   83|      4|        {18,7,27},{0,8,111},{0,8,47},{0,9,191},{0,8,15},{0,8,143},{0,8,79},
  |  |   84|      4|        {0,9,255}
  |  |   85|      4|    };
  |  |   86|       |
  |  |   87|      4|    static const code distfix[32] = {
  |  |   88|      4|        {16,5,1},{23,5,257},{19,5,17},{27,5,4097},{17,5,5},{25,5,1025},
  |  |   89|      4|        {21,5,65},{29,5,16385},{16,5,3},{24,5,513},{20,5,33},{28,5,8193},
  |  |   90|      4|        {18,5,9},{26,5,2049},{22,5,129},{64,5,0},{16,5,2},{23,5,385},
  |  |   91|      4|        {19,5,25},{27,5,6145},{17,5,7},{25,5,1537},{21,5,97},{29,5,24577},
  |  |   92|      4|        {16,5,4},{24,5,769},{20,5,49},{28,5,12289},{18,5,13},{26,5,3073},
  |  |   93|      4|        {22,5,193},{64,5,0}
  |  |   94|      4|    };
  ------------------
  317|      4|#endif /* BUILDFIXED */
  318|      4|    state->lencode = lenfix;
  319|      4|    state->lenbits = 9;
  320|      4|    state->distcode = distfix;
  321|      4|    state->distbits = 5;
  322|      4|}
inflate.c:updatewindow:
  403|  3.18k|{
  404|  3.18k|    struct inflate_state FAR *state;
  405|  3.18k|    unsigned dist;
  406|       |
  407|  3.18k|    state = (struct inflate_state FAR *)strm->state;
  408|       |
  409|       |    /* if it hasn't been done already, allocate space for the window */
  410|  3.18k|    if (state->window == Z_NULL) {
  ------------------
  |  |  212|  3.18k|#define Z_NULL  0  /* for initializing zalloc, zfree, opaque */
  ------------------
  |  Branch (410:9): [True: 26, False: 3.16k]
  ------------------
  411|     26|        state->window = (unsigned char FAR *)
  412|     26|                        ZALLOC(strm, 1U << state->wbits,
  ------------------
  |  |  267|     26|           (*((strm)->zalloc))((strm)->opaque, (items), (size))
  ------------------
  413|     26|                               sizeof(unsigned char));
  414|     26|        if (state->window == Z_NULL) return 1;
  ------------------
  |  |  212|     26|#define Z_NULL  0  /* for initializing zalloc, zfree, opaque */
  ------------------
  |  Branch (414:13): [True: 0, False: 26]
  ------------------
  415|     26|    }
  416|       |
  417|       |    /* if window not in use yet, initialize */
  418|  3.18k|    if (state->wsize == 0) {
  ------------------
  |  Branch (418:9): [True: 26, False: 3.16k]
  ------------------
  419|     26|        state->wsize = 1U << state->wbits;
  420|     26|        state->wnext = 0;
  421|     26|        state->whave = 0;
  422|     26|    }
  423|       |
  424|       |    /* copy state->wsize or less output bytes into the circular window */
  425|  3.18k|    if (copy >= state->wsize) {
  ------------------
  |  Branch (425:9): [True: 3.13k, False: 50]
  ------------------
  426|  3.13k|        zmemcpy(state->window, end - state->wsize, state->wsize);
  ------------------
  |  |  230|  3.13k|#    define zmemcpy memcpy
  ------------------
  427|  3.13k|        state->wnext = 0;
  428|  3.13k|        state->whave = state->wsize;
  429|  3.13k|    }
  430|     50|    else {
  431|     50|        dist = state->wsize - state->wnext;
  432|     50|        if (dist > copy) dist = copy;
  ------------------
  |  Branch (432:13): [True: 44, False: 6]
  ------------------
  433|     50|        zmemcpy(state->window + state->wnext, end - copy, dist);
  ------------------
  |  |  230|     50|#    define zmemcpy memcpy
  ------------------
  434|     50|        copy -= dist;
  435|     50|        if (copy) {
  ------------------
  |  Branch (435:13): [True: 6, False: 44]
  ------------------
  436|      6|            zmemcpy(state->window, end - copy, copy);
  ------------------
  |  |  230|      6|#    define zmemcpy memcpy
  ------------------
  437|      6|            state->wnext = copy;
  438|      6|            state->whave = state->wsize;
  439|      6|        }
  440|     44|        else {
  441|     44|            state->wnext += dist;
  442|     44|            if (state->wnext == state->wsize) state->wnext = 0;
  ------------------
  |  Branch (442:17): [True: 0, False: 44]
  ------------------
  443|     44|            if (state->whave < state->wsize) state->whave += dist;
  ------------------
  |  Branch (443:17): [True: 6, False: 38]
  ------------------
  444|     44|        }
  445|     50|    }
  446|  3.18k|    return 0;
  447|  3.18k|}

inflate_table:
   39|    162|{
   40|    162|    unsigned len;               /* a code's length in bits */
   41|    162|    unsigned sym;               /* index of code symbols */
   42|    162|    unsigned min, max;          /* minimum and maximum code lengths */
   43|    162|    unsigned root;              /* number of index bits for root table */
   44|    162|    unsigned curr;              /* number of index bits for current table */
   45|    162|    unsigned drop;              /* code bits to drop for sub-table */
   46|    162|    int left;                   /* number of prefix codes available */
   47|    162|    unsigned used;              /* code entries in table used */
   48|    162|    unsigned huff;              /* Huffman code */
   49|    162|    unsigned incr;              /* for incrementing code, index */
   50|    162|    unsigned fill;              /* index for replicating entries */
   51|    162|    unsigned low;               /* low bits for current root entry */
   52|    162|    unsigned mask;              /* mask for low root bits */
   53|    162|    code here;                  /* table entry for duplication */
   54|    162|    code FAR *next;             /* next available space in table */
   55|    162|    const unsigned short FAR *base;     /* base value table to use */
   56|    162|    const unsigned short FAR *extra;    /* extra bits table to use */
   57|    162|    unsigned match;             /* use base and extra for symbol >= match */
   58|    162|    unsigned short count[MAXBITS+1];    /* number of codes of each length */
   59|    162|    unsigned short offs[MAXBITS+1];     /* offsets in table for each length */
   60|    162|    static const unsigned short lbase[31] = { /* Length codes 257..285 base */
   61|    162|        3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31,
   62|    162|        35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0};
   63|    162|    static const unsigned short lext[31] = { /* Length codes 257..285 extra */
   64|    162|        16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 18, 18, 18, 18,
   65|    162|        19, 19, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 16, 194, 65};
   66|    162|    static const unsigned short dbase[32] = { /* Distance codes 0..29 base */
   67|    162|        1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193,
   68|    162|        257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145,
   69|    162|        8193, 12289, 16385, 24577, 0, 0};
   70|    162|    static const unsigned short dext[32] = { /* Distance codes 0..29 extra */
   71|    162|        16, 16, 16, 16, 17, 17, 18, 18, 19, 19, 20, 20, 21, 21, 22, 22,
   72|    162|        23, 23, 24, 24, 25, 25, 26, 26, 27, 27,
   73|    162|        28, 28, 29, 29, 64, 64};
   74|       |
   75|       |    /*
   76|       |       Process a set of code lengths to create a canonical Huffman code.  The
   77|       |       code lengths are lens[0..codes-1].  Each length corresponds to the
   78|       |       symbols 0..codes-1.  The Huffman code is generated by first sorting the
   79|       |       symbols by length from short to long, and retaining the symbol order
   80|       |       for codes with equal lengths.  Then the code starts with all zero bits
   81|       |       for the first code of the shortest length, and the codes are integer
   82|       |       increments for the same length, and zeros are appended as the length
   83|       |       increases.  For the deflate format, these bits are stored backwards
   84|       |       from their more natural integer increment ordering, and so when the
   85|       |       decoding tables are built in the large loop below, the integer codes
   86|       |       are incremented backwards.
   87|       |
   88|       |       This routine assumes, but does not check, that all of the entries in
   89|       |       lens[] are in the range 0..MAXBITS.  The caller must assure this.
   90|       |       1..MAXBITS is interpreted as that code length.  zero means that that
   91|       |       symbol does not occur in this code.
   92|       |
   93|       |       The codes are sorted by computing a count of codes for each length,
   94|       |       creating from that a table of starting indices for each length in the
   95|       |       sorted table, and then entering the symbols in order in the sorted
   96|       |       table.  The sorted table is work[], with that space being provided by
   97|       |       the caller.
   98|       |
   99|       |       The length counts are used for other purposes as well, i.e. finding
  100|       |       the minimum and maximum length codes, determining if there are any
  101|       |       codes at all, checking for a valid set of lengths, and looking ahead
  102|       |       at length counts to determine sub-table sizes when building the
  103|       |       decoding tables.
  104|       |     */
  105|       |
  106|       |    /* accumulate lengths for codes (assumes lens[] all in 0..MAXBITS) */
  107|  2.75k|    for (len = 0; len <= MAXBITS; len++)
  ------------------
  |  |    9|  2.75k|#define MAXBITS 15
  ------------------
  |  Branch (107:19): [True: 2.59k, False: 162]
  ------------------
  108|  2.59k|        count[len] = 0;
  109|  17.9k|    for (sym = 0; sym < codes; sym++)
  ------------------
  |  Branch (109:19): [True: 17.8k, False: 162]
  ------------------
  110|  17.8k|        count[lens[sym]]++;
  111|       |
  112|       |    /* bound code lengths, force root to be within code lengths */
  113|    162|    root = *bits;
  114|  1.07k|    for (max = MAXBITS; max >= 1; max--)
  ------------------
  |  |    9|    162|#define MAXBITS 15
  ------------------
  |  Branch (114:25): [True: 1.07k, False: 0]
  ------------------
  115|  1.07k|        if (count[max] != 0) break;
  ------------------
  |  Branch (115:13): [True: 162, False: 908]
  ------------------
  116|    162|    if (root > max) root = max;
  ------------------
  |  Branch (116:9): [True: 24, False: 138]
  ------------------
  117|    162|    if (max == 0) {                     /* no symbols to code at all */
  ------------------
  |  Branch (117:9): [True: 0, False: 162]
  ------------------
  118|      0|        here.op = (unsigned char)64;    /* invalid code marker */
  119|      0|        here.bits = (unsigned char)1;
  120|      0|        here.val = (unsigned short)0;
  121|      0|        *(*table)++ = here;             /* make a table to force an error */
  122|      0|        *(*table)++ = here;
  123|      0|        *bits = 1;
  124|      0|        return 0;     /* no symbols, but wait for decoding to report error */
  125|      0|    }
  126|    414|    for (min = 1; min < max; min++)
  ------------------
  |  Branch (126:19): [True: 414, False: 0]
  ------------------
  127|    414|        if (count[min] != 0) break;
  ------------------
  |  Branch (127:13): [True: 162, False: 252]
  ------------------
  128|    162|    if (root < min) root = min;
  ------------------
  |  Branch (128:9): [True: 0, False: 162]
  ------------------
  129|       |
  130|       |    /* check for an over-subscribed or incomplete set of lengths */
  131|    162|    left = 1;
  132|  2.59k|    for (len = 1; len <= MAXBITS; len++) {
  ------------------
  |  |    9|  2.59k|#define MAXBITS 15
  ------------------
  |  Branch (132:19): [True: 2.43k, False: 162]
  ------------------
  133|  2.43k|        left <<= 1;
  134|  2.43k|        left -= count[len];
  135|  2.43k|        if (left < 0) return -1;        /* over-subscribed */
  ------------------
  |  Branch (135:13): [True: 0, False: 2.43k]
  ------------------
  136|  2.43k|    }
  137|    162|    if (left > 0 && (type == CODES || max != 1))
  ------------------
  |  Branch (137:9): [True: 0, False: 162]
  |  Branch (137:22): [True: 0, False: 0]
  |  Branch (137:39): [True: 0, False: 0]
  ------------------
  138|      0|        return -1;                      /* incomplete set */
  139|       |
  140|       |    /* generate offsets into symbol table for each length for sorting */
  141|    162|    offs[1] = 0;
  142|  2.43k|    for (len = 1; len < MAXBITS; len++)
  ------------------
  |  |    9|  2.43k|#define MAXBITS 15
  ------------------
  |  Branch (142:19): [True: 2.26k, False: 162]
  ------------------
  143|  2.26k|        offs[len + 1] = offs[len] + count[len];
  144|       |
  145|       |    /* sort symbols by length, by symbol order within each length */
  146|  17.9k|    for (sym = 0; sym < codes; sym++)
  ------------------
  |  Branch (146:19): [True: 17.8k, False: 162]
  ------------------
  147|  17.8k|        if (lens[sym] != 0) work[offs[lens[sym]]++] = (unsigned short)sym;
  ------------------
  |  Branch (147:13): [True: 13.3k, False: 4.46k]
  ------------------
  148|       |
  149|       |    /*
  150|       |       Create and fill in decoding tables.  In this loop, the table being
  151|       |       filled is at next and has curr index bits.  The code being used is huff
  152|       |       with length len.  That code is converted to an index by dropping drop
  153|       |       bits off of the bottom.  For codes where len is less than drop + curr,
  154|       |       those top drop + curr - len bits are incremented through all values to
  155|       |       fill the table with replicated entries.
  156|       |
  157|       |       root is the number of index bits for the root table.  When len exceeds
  158|       |       root, sub-tables are created pointed to by the root entry with an index
  159|       |       of the low root bits of huff.  This is saved in low to check for when a
  160|       |       new sub-table should be started.  drop is zero when the root table is
  161|       |       being filled, and drop is root when sub-tables are being filled.
  162|       |
  163|       |       When a new sub-table is needed, it is necessary to look ahead in the
  164|       |       code lengths to determine what size sub-table is needed.  The length
  165|       |       counts are used for this, and so count[] is decremented as codes are
  166|       |       entered in the tables.
  167|       |
  168|       |       used keeps track of how many table entries have been allocated from the
  169|       |       provided *table space.  It is checked for LENS and DIST tables against
  170|       |       the constants ENOUGH_LENS and ENOUGH_DISTS to guard against changes in
  171|       |       the initial root table size constants.  See the comments in inftrees.h
  172|       |       for more information.
  173|       |
  174|       |       sym increments through all symbols, and the loop terminates when
  175|       |       all codes of length max, i.e. all codes, have been processed.  This
  176|       |       routine permits incomplete codes, so another loop after this one fills
  177|       |       in the rest of the decoding tables with invalid code markers.
  178|       |     */
  179|       |
  180|       |    /* set up for code type */
  181|    162|    switch (type) {
  182|     54|    case CODES:
  ------------------
  |  Branch (182:5): [True: 54, False: 108]
  ------------------
  183|     54|        base = extra = work;    /* dummy value--not used */
  184|     54|        match = 20;
  185|     54|        break;
  186|     54|    case LENS:
  ------------------
  |  Branch (186:5): [True: 54, False: 108]
  ------------------
  187|     54|        base = lbase;
  188|     54|        extra = lext;
  189|     54|        match = 257;
  190|     54|        break;
  191|     54|    default:    /* DISTS */
  ------------------
  |  Branch (191:5): [True: 54, False: 108]
  ------------------
  192|     54|        base = dbase;
  193|     54|        extra = dext;
  194|     54|        match = 0;
  195|    162|    }
  196|       |
  197|       |    /* initialize state for loop */
  198|    162|    huff = 0;                   /* starting code */
  199|    162|    sym = 0;                    /* starting code symbol */
  200|    162|    len = min;                  /* starting code length */
  201|    162|    next = *table;              /* current table to fill in */
  202|    162|    curr = root;                /* current table index bits */
  203|    162|    drop = 0;                   /* current bits to drop from code for index */
  204|    162|    low = (unsigned)(-1);       /* trigger new sub-table when len > root */
  205|    162|    used = 1U << root;          /* use root table entries */
  206|    162|    mask = used - 1;            /* mask for comparing low */
  207|       |
  208|       |    /* check available table space */
  209|    162|    if ((type == LENS && used > ENOUGH_LENS) ||
  ------------------
  |  |   49|     54|#define ENOUGH_LENS 852
  ------------------
  |  Branch (209:10): [True: 54, False: 108]
  |  Branch (209:26): [True: 0, False: 54]
  ------------------
  210|    162|        (type == DISTS && used > ENOUGH_DISTS))
  ------------------
  |  |   50|     54|#define ENOUGH_DISTS 592
  ------------------
  |  Branch (210:10): [True: 54, False: 108]
  |  Branch (210:27): [True: 0, False: 54]
  ------------------
  211|      0|        return 1;
  212|       |
  213|       |    /* process all codes and make table entries */
  214|  13.3k|    for (;;) {
  215|       |        /* create table entry */
  216|  13.3k|        here.bits = (unsigned char)(len - drop);
  217|  13.3k|        if (work[sym] + 1U < match) {
  ------------------
  |  Branch (217:13): [True: 10.6k, False: 2.72k]
  ------------------
  218|  10.6k|            here.op = (unsigned char)0;
  219|  10.6k|            here.val = work[sym];
  220|  10.6k|        }
  221|  2.72k|        else if (work[sym] >= match) {
  ------------------
  |  Branch (221:18): [True: 2.66k, False: 54]
  ------------------
  222|  2.66k|            here.op = (unsigned char)(extra[work[sym] - match]);
  223|  2.66k|            here.val = base[work[sym] - match];
  224|  2.66k|        }
  225|     54|        else {
  226|     54|            here.op = (unsigned char)(32 + 64);         /* end of block */
  227|     54|            here.val = 0;
  228|     54|        }
  229|       |
  230|       |        /* replicate for those indices with low len bits equal to huff */
  231|  13.3k|        incr = 1U << (len - drop);
  232|  13.3k|        fill = 1U << curr;
  233|  13.3k|        min = fill;                 /* save offset to next table */
  234|  40.2k|        do {
  235|  40.2k|            fill -= incr;
  236|  40.2k|            next[(huff >> drop) + fill] = here;
  237|  40.2k|        } while (fill != 0);
  ------------------
  |  Branch (237:18): [True: 26.8k, False: 13.3k]
  ------------------
  238|       |
  239|       |        /* backwards increment the len-bit code huff */
  240|  13.3k|        incr = 1U << (len - 1);
  241|  26.5k|        while (huff & incr)
  ------------------
  |  Branch (241:16): [True: 13.1k, False: 13.3k]
  ------------------
  242|  13.1k|            incr >>= 1;
  243|  13.3k|        if (incr != 0) {
  ------------------
  |  Branch (243:13): [True: 13.1k, False: 162]
  ------------------
  244|  13.1k|            huff &= incr - 1;
  245|  13.1k|            huff += incr;
  246|  13.1k|        }
  247|    162|        else
  248|    162|            huff = 0;
  249|       |
  250|       |        /* go to next symbol, update count, len */
  251|  13.3k|        sym++;
  252|  13.3k|        if (--(count[len]) == 0) {
  ------------------
  |  Branch (252:13): [True: 1.19k, False: 12.1k]
  ------------------
  253|  1.19k|            if (len == max) break;
  ------------------
  |  Branch (253:17): [True: 162, False: 1.03k]
  ------------------
  254|  1.03k|            len = lens[work[sym]];
  255|  1.03k|        }
  256|       |
  257|       |        /* create new sub-table if needed */
  258|  13.1k|        if (len > root && (huff & mask) != low) {
  ------------------
  |  Branch (258:13): [True: 5.00k, False: 8.16k]
  |  Branch (258:27): [True: 1.85k, False: 3.15k]
  ------------------
  259|       |            /* if first time, transition to sub-tables */
  260|  1.85k|            if (drop == 0)
  ------------------
  |  Branch (260:17): [True: 102, False: 1.75k]
  ------------------
  261|    102|                drop = root;
  262|       |
  263|       |            /* increment past last table */
  264|  1.85k|            next += min;            /* here min is 1 << curr */
  265|       |
  266|       |            /* determine length of next table */
  267|  1.85k|            curr = len - drop;
  268|  1.85k|            left = (int)(1 << curr);
  269|  2.06k|            while (curr + drop < max) {
  ------------------
  |  Branch (269:20): [True: 1.96k, False: 106]
  ------------------
  270|  1.96k|                left -= count[curr + drop];
  271|  1.96k|                if (left <= 0) break;
  ------------------
  |  Branch (271:21): [True: 1.74k, False: 213]
  ------------------
  272|    213|                curr++;
  273|    213|                left <<= 1;
  274|    213|            }
  275|       |
  276|       |            /* check for enough space */
  277|  1.85k|            used += 1U << curr;
  278|  1.85k|            if ((type == LENS && used > ENOUGH_LENS) ||
  ------------------
  |  |   49|  1.77k|#define ENOUGH_LENS 852
  ------------------
  |  Branch (278:18): [True: 1.77k, False: 82]
  |  Branch (278:34): [True: 0, False: 1.77k]
  ------------------
  279|  1.85k|                (type == DISTS && used > ENOUGH_DISTS))
  ------------------
  |  |   50|     82|#define ENOUGH_DISTS 592
  ------------------
  |  Branch (279:18): [True: 82, False: 1.77k]
  |  Branch (279:35): [True: 0, False: 82]
  ------------------
  280|      0|                return 1;
  281|       |
  282|       |            /* point entry in root table to sub-table */
  283|  1.85k|            low = huff & mask;
  284|  1.85k|            (*table)[low].op = (unsigned char)curr;
  285|  1.85k|            (*table)[low].bits = (unsigned char)root;
  286|  1.85k|            (*table)[low].val = (unsigned short)(next - *table);
  287|  1.85k|        }
  288|  13.1k|    }
  289|       |
  290|       |    /* fill in remaining table entry if code is incomplete (guaranteed to have
  291|       |       at most one remaining entry, since if the code is incomplete, the
  292|       |       maximum code length that was allowed to get this far is one bit) */
  293|    162|    if (huff != 0) {
  ------------------
  |  Branch (293:9): [True: 0, False: 162]
  ------------------
  294|      0|        here.op = (unsigned char)64;            /* invalid code marker */
  295|      0|        here.bits = (unsigned char)(len - drop);
  296|      0|        here.val = (unsigned short)0;
  297|      0|        next[huff] = here;
  298|      0|    }
  299|       |
  300|       |    /* set return parameters */
  301|    162|    *table += used;
  302|    162|    *bits = root;
  303|    162|    return 0;
  304|    162|}

zcalloc:
  310|     52|{
  311|     52|    (void)opaque;
  312|     52|    return sizeof(uInt) > 2 ? (voidpf)malloc(items * size) :
  ------------------
  |  Branch (312:12): [True: 52, Folded]
  ------------------
  313|     52|                              (voidpf)calloc(items, size);
  314|     52|}
zcfree:
  319|     52|{
  320|     52|    (void)opaque;
  321|     52|    free(ptr);
  322|     52|}

LLVMFuzzerTestOneInput:
   49|    469|extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t dataSize) {
   50|       |    // Limit input size to 1MB to prevent OOMs and timeouts
   51|    469|    if (dataSize > 1024 * 1024) {
  ------------------
  |  Branch (51:9): [True: 0, False: 469]
  ------------------
   52|      0|        return 0;
   53|      0|    }
   54|       |
   55|       |#ifdef _DEBUG
   56|       |    aiLogStream stream = aiGetPredefinedLogStream(aiDefaultLogStream_STDOUT, nullptr);
   57|       |    aiAttachLogStream(&stream);
   58|       |#endif
   59|       |
   60|    469|    Importer importer;
   61|    469|    unsigned int flags = aiProcessPreset_TargetRealtime_Quality | aiProcess_ValidateDataStructure;
   62|    469|    const aiScene *sc = importer.ReadFileFromMemory(data, dataSize, flags, nullptr);
   63|       |
   64|    469|    if (sc == nullptr) {
  ------------------
  |  Branch (64:9): [True: 261, False: 208]
  ------------------
   65|    261|        return 0;
   66|    261|    }
   67|       |
   68|    208|    Exporter exporter;
   69|    208|    exporter.ExportToBlob(sc, "fbx");
   70|       |
   71|       |#ifdef _DEBUG
   72|       |    aiDetachLogStream(&stream);
   73|       |#endif
   74|       |
   75|    208|    return 0;
   76|    469|}

_ZN6Assimp10TXmlParserIN4pugi8xml_nodeEEC2Ev:
  256|  1.30k|        mDoc(nullptr),
  257|  1.30k|        mData() {
  258|       |    // empty
  259|  1.30k|}
_ZN6Assimp27find_node_by_name_predicateC2ERKNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEE:
   66|      4|    explicit find_node_by_name_predicate(const std::string &name) : mName(name) {
   67|       |        // empty
   68|      4|    }
_ZNK6Assimp27find_node_by_name_predicateclEN4pugi8xml_nodeE:
   72|      8|    bool operator()(pugi::xml_node node) const {
   73|      8|        return node.name() == mName;
   74|      8|    }
_ZN6Assimp15XmlNodeIteratorC2ERN4pugi8xml_nodeENS0_13IterationModeE:
  547|  3.96k|            mParent(parent),
  548|  3.96k|            mNodes(),
  549|  3.96k|            mIndex(0) {
  550|  3.96k|        if (mode == PreOrderMode) {
  ------------------
  |  Branch (550:13): [True: 3.96k, False: 0]
  ------------------
  551|  3.96k|            collectChildrenPreOrder(parent);
  552|  3.96k|        } else {
  553|      0|            collectChildrenPostOrder(parent);
  554|      0|        }
  555|  3.96k|    }
_ZN6Assimp15XmlNodeIterator23collectChildrenPreOrderERN4pugi8xml_nodeE:
  562|  69.2k|    void collectChildrenPreOrder(XmlNode &node) {
  563|  69.2k|        if (node != mParent && node.type() == pugi::node_element) {
  ------------------
  |  Branch (563:13): [True: 65.2k, False: 3.96k]
  |  Branch (563:32): [True: 39.1k, False: 26.0k]
  ------------------
  564|  39.1k|            mNodes.push_back(node);
  565|  39.1k|        }
  566|  69.2k|        for (XmlNode currentNode : node.children()) {
  ------------------
  |  Branch (566:34): [True: 65.2k, False: 69.2k]
  ------------------
  567|  65.2k|            collectChildrenPreOrder(currentNode);
  568|  65.2k|        }
  569|  69.2k|    }
_ZN6Assimp15XmlNodeIterator7getNextERN4pugi8xml_nodeE:
  585|  36.1k|    bool getNext(XmlNode &next) {
  586|  36.1k|        if (mIndex == mNodes.size()) {
  ------------------
  |  Branch (586:13): [True: 3.94k, False: 32.2k]
  ------------------
  587|  3.94k|            return false;
  588|  3.94k|        }
  589|       |
  590|  32.2k|        next = mNodes[mIndex];
  591|  32.2k|        ++mIndex;
  592|       |
  593|  32.2k|        return true;
  594|  36.1k|    }
_ZN6Assimp10TXmlParserIN4pugi8xml_nodeEE5clearEv:
  267|  1.30k|inline void TXmlParser<TNodeType>::clear() {
  268|  1.30k|    if (mData.empty()) {
  ------------------
  |  Branch (268:9): [True: 1.24k, False: 60]
  ------------------
  269|  1.24k|        if (mDoc) {
  ------------------
  |  Branch (269:13): [True: 0, False: 1.24k]
  ------------------
  270|      0|            delete mDoc;
  271|      0|        }
  272|  1.24k|        mDoc = nullptr;
  273|  1.24k|        return;
  274|  1.24k|    }
  275|       |
  276|     60|    mData.clear();
  277|     60|    delete mDoc;
  278|     60|    mDoc = nullptr;
  279|     60|}
_ZN6Assimp10TXmlParserIN4pugi8xml_nodeEED2Ev:
  262|  1.30k|inline TXmlParser<TNodeType>::~TXmlParser() {
  263|  1.30k|    clear();
  264|  1.30k|}
_ZN6Assimp10TXmlParserIN4pugi8xml_nodeEE8findNodeERKNSt3__112basic_stringIcNS4_11char_traitsIcEENS4_9allocatorIcEEEE:
  282|      4|inline TNodeType *TXmlParser<TNodeType>::findNode(const std::string &name) {
  283|      4|    if (name.empty()) {
  ------------------
  |  Branch (283:9): [True: 0, False: 4]
  ------------------
  284|      0|        return nullptr;
  285|      0|    }
  286|       |
  287|      4|    if (nullptr == mDoc) {
  ------------------
  |  Branch (287:9): [True: 0, False: 4]
  ------------------
  288|      0|        return nullptr;
  289|      0|    }
  290|       |
  291|      4|    find_node_by_name_predicate predicate(name);
  292|      4|    mCurrent = mDoc->find_node(std::move(predicate));
  293|      4|    if (mCurrent.empty()) {
  ------------------
  |  Branch (293:9): [True: 0, False: 4]
  ------------------
  294|      0|        return nullptr;
  295|      0|    }
  296|       |
  297|      4|    return &mCurrent;
  298|      4|}
_ZN6Assimp10TXmlParserIN4pugi8xml_nodeEE5parseEPNS_8IOStreamE:
  306|     60|bool TXmlParser<TNodeType>::parse(IOStream *stream) {
  307|     60|    if (hasRoot()) {
  ------------------
  |  Branch (307:9): [True: 0, False: 60]
  ------------------
  308|      0|        clear();
  309|      0|    }
  310|       |
  311|     60|    if (nullptr == stream) {
  ------------------
  |  Branch (311:9): [True: 0, False: 60]
  ------------------
  312|      0|        ASSIMP_LOG_DEBUG("Stream is nullptr.");
  313|      0|        return false;
  314|      0|    }
  315|       |
  316|     60|    const size_t len = stream->FileSize();
  317|     60|    mData.resize(len + 1);
  318|     60|    memset(&mData[0], '\0', len + 1);
  319|     60|    stream->Read(&mData[0], 1, len);
  320|       |
  321|     60|    mDoc = new pugi::xml_document();
  322|       |    // load_string assumes native encoding (aka always utf-8 per build options)
  323|       |    //pugi::xml_parse_result parse_result = mDoc->load_string(&mData[0], pugi::parse_full);
  324|     60|    pugi::xml_parse_result parse_result = mDoc->load_buffer(&mData[0], mData.size(), pugi::parse_full);
  325|     60|    if (parse_result.status == pugi::status_ok) {
  ------------------
  |  Branch (325:9): [True: 48, False: 12]
  ------------------
  326|     48|        return true;
  327|     48|    }
  328|       |
  329|     60|    ASSIMP_LOG_DEBUG("Error while parse xml.", std::string(parse_result.description()), " @ ", parse_result.offset);
  330|       |
  331|     12|    return false;
  332|     60|}
_ZNK6Assimp10TXmlParserIN4pugi8xml_nodeEE7hasRootEv:
  351|     60|bool TXmlParser<TNodeType>::hasRoot() const {
  352|     60|    return nullptr != mDoc;
  353|     60|}
_ZN6Assimp10TXmlParserIN4pugi8xml_nodeEE14getValueAsRealERS2_Rf:
  489|    169|inline bool TXmlParser<TNodeType>::getValueAsReal(XmlNode& node, ai_real& v) {
  490|    169|    if (node.empty()) {
  ------------------
  |  Branch (490:9): [True: 0, False: 169]
  ------------------
  491|      0|        return false;
  492|      0|    }
  493|       |
  494|    169|    v = node.text().as_float();
  495|       |
  496|    169|    return true;
  497|    169|}
_ZN6Assimp10TXmlParserIN4pugi8xml_nodeEE16getValueAsStringERS2_RNSt3__112basic_stringIcNS5_11char_traitsIcEENS5_9allocatorIcEEEE:
  476|  11.1k|inline bool TXmlParser<TNodeType>::getValueAsString(XmlNode &node, std::string &text) {
  477|  11.1k|    text = std::string();
  478|  11.1k|    if (node.empty()) {
  ------------------
  |  Branch (478:9): [True: 0, False: 11.1k]
  ------------------
  479|      0|        return false;
  480|      0|    }
  481|       |
  482|  11.1k|    text = node.text().as_string();
  483|  11.1k|    text = ai_trim(text);
  484|       |
  485|  11.1k|    return true;
  486|  11.1k|}
_ZN6Assimp15XmlNodeIteratorD2Ev:
  558|  3.96k|    ~XmlNodeIterator() = default;
_ZN6Assimp10TXmlParserIN4pugi8xml_nodeEE18getStdStrAttributeERS2_PKcRNSt3__112basic_stringIcNS7_11char_traitsIcEENS7_9allocatorIcEEEE:
  452|  16.6k|inline bool TXmlParser<TNodeType>::getStdStrAttribute(XmlNode &xmlNode, const char *name, std::string &val) {
  453|  16.6k|    pugi::xml_attribute attr = xmlNode.attribute(name);
  454|  16.6k|    if (attr.empty()) {
  ------------------
  |  Branch (454:9): [True: 408, False: 16.2k]
  ------------------
  455|    408|        return false;
  456|    408|    }
  457|       |
  458|  16.2k|    val = attr.as_string();
  459|       |
  460|  16.2k|    return true;
  461|  16.6k|}
_ZN6Assimp10TXmlParserIN4pugi8xml_nodeEE12hasAttributeERS2_PKc:
  386|  13.3k|inline bool TXmlParser<TNodeType>::hasAttribute(XmlNode &xmlNode, const char *name) {
  387|  13.3k|    pugi::xml_attribute attr = xmlNode.attribute(name);
  388|  13.3k|    return !attr.empty();
  389|  13.3k|}
_ZN6Assimp10TXmlParserIN4pugi8xml_nodeEE15getIntAttributeERS2_PKcRi:
  403|  1.68k|inline bool TXmlParser<TNodeType>::getIntAttribute(XmlNode &xmlNode, const char *name, int &val) {
  404|  1.68k|    pugi::xml_attribute attr = xmlNode.attribute(name);
  405|  1.68k|    if (attr.empty()) {
  ------------------
  |  Branch (405:9): [True: 0, False: 1.68k]
  ------------------
  406|      0|        return false;
  407|      0|    }
  408|       |
  409|  1.68k|    val = attr.as_int();
  410|  1.68k|    return true;
  411|  1.68k|}
_ZN6Assimp10TXmlParserIN4pugi8xml_nodeEE11getRootNodeEv:
  370|     48|TNodeType TXmlParser<TNodeType>::getRootNode() {
  371|     48|    static pugi::xml_node none;
  372|     48|    if (nullptr == mDoc) {
  ------------------
  |  Branch (372:9): [True: 0, False: 48]
  ------------------
  373|      0|        return none;
  374|      0|    }
  375|       |
  376|     48|    return mDoc->root();
  377|     48|}
_ZN6Assimp10TXmlParserIN4pugi8xml_nodeEE14getValueAsBoolERS2_Rb:
  523|     18|inline bool TXmlParser<TNodeType>::getValueAsBool(XmlNode &node, bool &v) {
  524|     18|    if (node.empty()) {
  ------------------
  |  Branch (524:9): [True: 0, False: 18]
  ------------------
  525|      0|        return false;
  526|      0|    }
  527|       |
  528|     18|    v = node.text().as_bool();
  529|       |
  530|     18|    return true;
  531|     18|}
_ZN6Assimp10TXmlParserIN4pugi8xml_nodeEE16getUIntAttributeERS2_PKcRj:
  392|  3.98k|inline bool TXmlParser<TNodeType>::getUIntAttribute(XmlNode &xmlNode, const char *name, unsigned int &val) {
  393|  3.98k|    pugi::xml_attribute attr = xmlNode.attribute(name);
  394|  3.98k|    if (attr.empty()) {
  ------------------
  |  Branch (394:9): [True: 137, False: 3.84k]
  ------------------
  395|    137|        return false;
  396|    137|    }
  397|       |
  398|  3.84k|    val = attr.as_uint();
  399|  3.84k|    return true;
  400|  3.98k|}

