Browse Source

Merge pull request #1832 from assimp/3mf_basematerial_support

3mf basematerial support
Kim Kulling 7 years ago
parent
commit
58e73143fc

+ 5 - 0
code/3MFXmlTags.h

@@ -45,6 +45,10 @@ namespace Assimp {
 namespace D3MF {
 
 namespace XmlTag {
+    // Meta-data
+    static const std::string meta = "metadata";
+    static const std::string meta_name = "name";
+
     // Model-data specific tags
     static const std::string model = "model";
     static const std::string model_unit = "unit";
@@ -74,6 +78,7 @@ namespace XmlTag {
 
     // Material definitions
     static const std::string basematerials = "basematerials";
+    static const std::string basematerials_id = "id";
     static const std::string basematerials_base = "base";
     static const std::string basematerials_name = "name";
     static const std::string basematerials_displaycolor = "displaycolor";

+ 8 - 8
code/BaseImporter.cpp

@@ -115,13 +115,12 @@ void BaseImporter::SetupProperties(const Importer* /*pImp*/)
 }
 
 // ------------------------------------------------------------------------------------------------
-void BaseImporter::GetExtensionList(std::set<std::string>& extensions)
-{
+void BaseImporter::GetExtensionList(std::set<std::string>& extensions) {
     const aiImporterDesc* desc = GetInfo();
-    ai_assert(desc != NULL);
+    ai_assert(desc != nullptr);
 
     const char* ext = desc->mFileExtensions;
-    ai_assert(ext != NULL);
+    ai_assert(ext != nullptr );
 
     const char* last = ext;
     do {
@@ -145,12 +144,13 @@ void BaseImporter::GetExtensionList(std::set<std::string>& extensions)
     unsigned int        searchBytes /* = 200 */,
     bool                tokensSol /* false */)
 {
-    ai_assert( NULL != tokens );
+    ai_assert( nullptr != tokens );
     ai_assert( 0 != numTokens );
     ai_assert( 0 != searchBytes);
 
-    if (!pIOHandler)
+    if ( nullptr == pIOHandler ) {
         return false;
+    }
 
     std::unique_ptr<IOStream> pStream (pIOHandler->Open(pFile));
     if (pStream.get() ) {
@@ -179,9 +179,9 @@ void BaseImporter::GetExtensionList(std::set<std::string>& extensions)
         *cur2 = '\0';
 
         std::string token;
-        for (unsigned int i = 0; i < numTokens;++i) {
+        for (unsigned int i = 0; i < numTokens; ++i ) {
             ai_assert( nullptr != tokens[i] );
-            size_t len( strlen( tokens[ i ] ) );
+            const size_t len( strlen( tokens[ i ] ) );
             token.clear();
             const char *ptr( tokens[ i ] );
             for ( size_t tokIdx = 0; tokIdx < len; ++tokIdx ) {

+ 17 - 9
code/ConvertToLHProcess.cpp

@@ -91,12 +91,14 @@ void MakeLeftHandedProcess::Execute( aiScene* pScene)
     ProcessNode( pScene->mRootNode, aiMatrix4x4());
 
     // process the meshes accordingly
-    for( unsigned int a = 0; a < pScene->mNumMeshes; ++a)
-        ProcessMesh( pScene->mMeshes[a]);
+    for ( unsigned int a = 0; a < pScene->mNumMeshes; ++a ) {
+        ProcessMesh( pScene->mMeshes[ a ] );
+    }
 
     // process the materials accordingly
-    for( unsigned int a = 0; a < pScene->mNumMaterials; ++a)
-        ProcessMaterial( pScene->mMaterials[a]);
+    for ( unsigned int a = 0; a < pScene->mNumMaterials; ++a ) {
+        ProcessMaterial( pScene->mMaterials[ a ] );
+    }
 
     // transform all animation channels as well
     for( unsigned int a = 0; a < pScene->mNumAnimations; a++)
@@ -136,8 +138,11 @@ void MakeLeftHandedProcess::ProcessNode( aiNode* pNode, const aiMatrix4x4& pPare
 
 // ------------------------------------------------------------------------------------------------
 // Converts a single mesh to left handed coordinates.
-void MakeLeftHandedProcess::ProcessMesh( aiMesh* pMesh)
-{
+void MakeLeftHandedProcess::ProcessMesh( aiMesh* pMesh) {
+    if ( nullptr == pMesh ) {
+        DefaultLogger::get()->error( "Nullptr to mesh found." );
+        return;
+    }
     // mirror positions, normals and stuff along the Z axis
     for( size_t a = 0; a < pMesh->mNumVertices; ++a)
     {
@@ -173,8 +178,12 @@ void MakeLeftHandedProcess::ProcessMesh( aiMesh* pMesh)
 
 // ------------------------------------------------------------------------------------------------
 // Converts a single material to left handed coordinates.
-void MakeLeftHandedProcess::ProcessMaterial( aiMaterial* _mat)
-{
+void MakeLeftHandedProcess::ProcessMaterial( aiMaterial* _mat) {
+    if ( nullptr == _mat ) {
+        DefaultLogger::get()->error( "Nullptr to aiMaterial found." );
+        return;
+    }
+
     aiMaterial* mat = (aiMaterial*)_mat;
     for (unsigned int a = 0; a < mat->mNumProperties;++a)   {
         aiMaterialProperty* prop = mat->mProperties[a];
@@ -183,7 +192,6 @@ void MakeLeftHandedProcess::ProcessMaterial( aiMaterial* _mat)
         if (!::strcmp( prop->mKey.data, "$tex.mapaxis"))    {
             ai_assert( prop->mDataLength >= sizeof(aiVector3D)); /* something is wrong with the validation if we end up here */
             aiVector3D* pff = (aiVector3D*)prop->mData;
-
             pff->z *= -1.f;
         }
     }

+ 49 - 6
code/D3MFExporter.cpp

@@ -49,8 +49,9 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include <assimp/IOStream.hpp>
 #include <assimp/Exporter.hpp>
 #include <assimp/DefaultLogger.hpp>
-
+#include <assimp/StringUtils.h>
 #include <assimp/Exceptional.h>
+
 #include "3MFXmlTags.h"
 #include "D3MFOpcPackage.h"
 
@@ -126,7 +127,6 @@ bool D3MFExporter::exportArchive( const char *file ) {
     return ok;
 }
 
-
 bool D3MFExporter::exportContentTypes() {
     mContentOutput.clear();
 
@@ -153,7 +153,11 @@ bool D3MFExporter::exportRelations() {
     mRelOutput << "<Relationships xmlns=\"http://schemas.openxmlformats.org/package/2006/relationships\">";
 
     for ( size_t i = 0; i < mRelations.size(); ++i ) {
-        mRelOutput << "<Relationship Target=\"/" << mRelations[ i ]->target << "\" ";
+        if ( mRelations[ i ]->target[ 0 ] == '/' ) {
+            mRelOutput << "<Relationship Target=\"" << mRelations[ i ]->target << "\" ";
+        } else {
+            mRelOutput << "<Relationship Target=\"/" << mRelations[ i ]->target << "\" ";
+        }
         mRelOutput << "Id=\"" << mRelations[i]->id << "\" ";
         mRelOutput << "Type=\"" << mRelations[ i ]->type << "\" />";
         mRelOutput << std::endl;
@@ -177,6 +181,8 @@ bool D3MFExporter::export3DModel() {
     mModelOutput << "<" << XmlTag::resources << ">";
     mModelOutput << std::endl;
 
+    writeBaseMaterials();
+
     writeObjects();
 
 
@@ -203,6 +209,40 @@ void D3MFExporter::writeHeader() {
     mModelOutput << std::endl;
 }
 
+void D3MFExporter::writeBaseMaterials() {
+    mModelOutput << "<basematerials id=\"1\">\n";
+    for ( size_t i = 0; i < mScene->mNumMaterials; ++i ) {
+        aiMaterial *mat = mScene->mMaterials[ i ];
+        std::string strName;
+        aiString name;
+        if ( mat->Get( AI_MATKEY_NAME, name ) != aiReturn_SUCCESS ) {
+            strName = "basemat_" + to_string( i );
+        } else {
+            strName = name.C_Str();
+        }
+        std::string hexDiffuseColor;
+        aiColor4D color;
+        if ( mat->Get( AI_MATKEY_COLOR_DIFFUSE, color ) == aiReturn_SUCCESS ) {
+            hexDiffuseColor = "#";
+            std::string tmp;
+            
+            tmp = DecimalToHexa( color.r );
+            hexDiffuseColor += tmp;
+            tmp = DecimalToHexa( color.g );
+            hexDiffuseColor += tmp;
+            tmp = DecimalToHexa( color.b );
+            hexDiffuseColor += tmp;
+            tmp = DecimalToHexa( color.a );
+            hexDiffuseColor += tmp;
+        } else {
+            hexDiffuseColor = "#FFFFFFFF";
+        }
+
+        mModelOutput << "<base name=\""+strName+"\" "+" displaycolor=\""+hexDiffuseColor+"\" />\n";
+    }
+    mModelOutput << "</basematerials>\n";
+}
+
 void D3MFExporter::writeObjects() {
     if ( nullptr == mScene->mRootNode ) {
         return;
@@ -242,7 +282,9 @@ void D3MFExporter::writeMesh( aiMesh *mesh ) {
     }
     mModelOutput << "</" << XmlTag::vertices << ">" << std::endl;
 
-    writeFaces( mesh );
+    const unsigned int matIdx( mesh->mMaterialIndex );
+
+    writeFaces( mesh, matIdx );
 
     mModelOutput << "</" << XmlTag::mesh << ">" << std::endl;
 }
@@ -252,7 +294,7 @@ void D3MFExporter::writeVertex( const aiVector3D &pos ) {
     mModelOutput << std::endl;
 }
 
-void D3MFExporter::writeFaces( aiMesh *mesh ) {
+void D3MFExporter::writeFaces( aiMesh *mesh, unsigned int matIdx ) {
     if ( nullptr == mesh ) {
         return;
     }
@@ -264,7 +306,8 @@ void D3MFExporter::writeFaces( aiMesh *mesh ) {
     for ( unsigned int i = 0; i < mesh->mNumFaces; ++i ) {
         aiFace &currentFace = mesh->mFaces[ i ];
         mModelOutput << "<" << XmlTag::triangle << " v1=\"" << currentFace.mIndices[ 0 ] << "\" v2=\""
-                << currentFace.mIndices[ 1 ] << "\" v3=\"" << currentFace.mIndices[ 2 ] << "\"/>";
+                << currentFace.mIndices[ 1 ] << "\" v3=\"" << currentFace.mIndices[ 2 ]
+                << "\" pid=\"1\" p1=\""+to_string(matIdx)+"\" />";
         mModelOutput << std::endl;
     }
     mModelOutput << "</" << XmlTag::triangles << ">";

+ 2 - 1
code/D3MFExporter.h

@@ -76,10 +76,11 @@ public:
 
 protected:
     void writeHeader();
+    void writeBaseMaterials();
     void writeObjects();
     void writeMesh( aiMesh *mesh );
     void writeVertex( const aiVector3D &pos );
-    void writeFaces( aiMesh *mesh );
+    void writeFaces( aiMesh *mesh, unsigned int matIdx );
     void writeBuild();
     void exportContentTyp( const std::string &filename );
     void writeModelToArchive( const std::string &folder, const std::string &modelName );

+ 66 - 25
code/D3MFImporter.cpp

@@ -70,9 +70,14 @@ namespace D3MF {
 
 class XmlSerializer {
 public:
+    using MatArray = std::vector<aiMaterial*>;
+    using MatId2MatArray = std::map<unsigned int, std::vector<unsigned int>>;
+
     XmlSerializer(XmlReader* xmlReader)
     : mMeshes()
-    , mMaterials() 
+    , mMatArray()
+    , mActiveMatGroup( 99999999 )
+    , mMatId2MatArray()
     , xmlReader(xmlReader){
 		// empty
     }
@@ -109,10 +114,10 @@ public:
 
         std::copy( mMeshes.begin(), mMeshes.end(), scene->mMeshes);
 
-        scene->mNumMaterials = mMaterials.size();
+        scene->mNumMaterials = static_cast<unsigned int>( mMatArray.size() );
         if ( 0 != scene->mNumMaterials ) {
             scene->mMaterials = new aiMaterial*[ scene->mNumMaterials ];
-            std::copy( mMaterials.begin(), mMaterials.end(), scene->mMaterials );
+            std::copy( mMatArray.begin(), mMatArray.end(), scene->mMaterials );
         }
         scene->mRootNode->mNumChildren = static_cast<unsigned int>(children.size());
         scene->mRootNode->mChildren = new aiNode*[scene->mRootNode->mNumChildren]();
@@ -128,11 +133,11 @@ private:
 
         const char *attrib( nullptr );
         std::string name, type;
-        attrib = xmlReader->getAttributeValue( D3MF::XmlTag::name.c_str() );
+        attrib = xmlReader->getAttributeValue( D3MF::XmlTag::id.c_str() );
         if ( nullptr != attrib ) {
             name = attrib;
         }
-        attrib = xmlReader->getAttributeValue( D3MF::XmlTag::name.c_str() );
+        attrib = xmlReader->getAttributeValue( D3MF::XmlTag::type.c_str() );
         if ( nullptr != attrib ) {
             type = attrib;
         }
@@ -162,7 +167,7 @@ private:
         return node.release();
     }
 
-    aiMesh* ReadMesh() {
+    aiMesh *ReadMesh() {
         aiMesh* mesh = new aiMesh();
         while(ReadToEndElement(D3MF::XmlTag::mesh)) {
             if(xmlReader->getNodeName() == D3MF::XmlTag::vertices) {
@@ -177,7 +182,6 @@ private:
 
     void ImportVertices(aiMesh* mesh) {
         std::vector<aiVector3D> vertices;
-
         while(ReadToEndElement(D3MF::XmlTag::vertices)) {
             if(xmlReader->getNodeName() == D3MF::XmlTag::vertex) {
                 vertices.push_back(ReadVertex());
@@ -234,9 +238,27 @@ private:
     }
 
     void ReadBaseMaterials() {
+        std::vector<unsigned int> MatIdArray;
+        const char *baseMaterialId( xmlReader->getAttributeValue( D3MF::XmlTag::basematerials_id.c_str() ) );
+        if ( nullptr != baseMaterialId ) {
+            unsigned int id = std::atoi( baseMaterialId );
+            const size_t newMatIdx( mMatArray.size() );
+            if ( id != mActiveMatGroup ) {
+                mActiveMatGroup = id;
+                MatId2MatArray::const_iterator it( mMatId2MatArray.find( id ) );
+                if ( mMatId2MatArray.end() == it ) {
+                    MatIdArray.clear();
+                    mMatId2MatArray[ id ] = MatIdArray;
+                } else {
+                    MatIdArray = it->second;
+                }
+            }
+            MatIdArray.push_back( newMatIdx );
+            mMatId2MatArray[ mActiveMatGroup ] = MatIdArray;
+        }
+
         while ( ReadToEndElement( D3MF::XmlTag::basematerials ) ) {
-            mMaterials.push_back( readMaterialDef() );
-            xmlReader->read();
+            mMatArray.push_back( readMaterialDef() );
         }
     }
 
@@ -285,24 +307,37 @@ private:
         return true;
     }
 
+    void assignDiffuseColor( aiMaterial *mat ) {
+        const char *color = xmlReader->getAttributeValue( D3MF::XmlTag::basematerials_displaycolor.c_str() );
+        aiColor4D diffuse;
+        if ( parseColor( color, diffuse ) ) {
+            mat->AddProperty<aiColor4D>( &diffuse, 1, AI_MATKEY_COLOR_DIFFUSE );
+        }
+
+    }
     aiMaterial *readMaterialDef() {
         aiMaterial *mat( nullptr );
         const char *name( nullptr );
-        const char *color( nullptr );
         const std::string nodeName( xmlReader->getNodeName() );
         if ( nodeName == D3MF::XmlTag::basematerials_base ) {
             name = xmlReader->getAttributeValue( D3MF::XmlTag::basematerials_name.c_str() );
-
+            std::string stdMatName;
             aiString matName;
-            matName.Set( name );
+            std::string strId( to_string( mActiveMatGroup ) );
+            stdMatName += "id";
+            stdMatName += strId;
+            stdMatName += "_";
+            if ( nullptr != name ) {
+                stdMatName += std::string( name );
+            } else {
+                stdMatName += "basemat";
+            }
+            matName.Set( stdMatName );
+
             mat = new aiMaterial;
             mat->AddProperty( &matName, AI_MATKEY_NAME );
 
-            color = xmlReader->getAttributeValue( D3MF::XmlTag::basematerials_displaycolor.c_str() );
-            aiColor4D diffuse;
-            if ( parseColor( color, diffuse ) ) {
-                mat->AddProperty<aiColor4D>( &diffuse, 1, AI_MATKEY_COLOR_DIFFUSE );
-            }
+            assignDiffuseColor( mat );
         }
 
         return mat;
@@ -339,7 +374,9 @@ private:
 
 private:
     std::vector<aiMesh*> mMeshes;
-    std::vector<aiMaterial*> mMaterials;
+    MatArray mMatArray;
+    unsigned int mActiveMatGroup;
+    MatId2MatArray mMatId2MatArray;
     XmlReader* xmlReader;
 };
 
@@ -360,7 +397,6 @@ static const aiImporterDesc desc = {
     Extension.c_str()
 };
 
-
 D3MFImporter::D3MFImporter()
 : BaseImporter() {
     // empty
@@ -370,14 +406,19 @@ D3MFImporter::~D3MFImporter() {
     // empty
 }
 
-bool D3MFImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool checkSig) const {
-    const std::string extension = GetExtension(pFile);
+bool D3MFImporter::CanRead(const std::string &filename, IOSystem *pIOHandler, bool checkSig) const {
+    const std::string extension( GetExtension( filename ) );
     if(extension == Extension ) {
         return true;
     } else if ( !extension.length() || checkSig ) {
-        if (nullptr == pIOHandler ) {
-            return true;
+        if ( nullptr == pIOHandler ) {
+            return false;
+        }
+        if ( !D3MF::D3MFOpcPackage::isZipArchive( pIOHandler, filename ) ) {
+            return false;
         }
+        D3MF::D3MFOpcPackage opcPackage( pIOHandler, filename );
+        return opcPackage.validate();
     }
 
     return false;
@@ -391,8 +432,8 @@ const aiImporterDesc *D3MFImporter::GetInfo() const {
     return &desc;
 }
 
-void D3MFImporter::InternReadFile(const std::string &pFile, aiScene *pScene, IOSystem *pIOHandler) {
-    D3MF::D3MFOpcPackage opcPackage(pIOHandler, pFile);
+void D3MFImporter::InternReadFile( const std::string &filename, aiScene *pScene, IOSystem *pIOHandler ) {
+    D3MF::D3MFOpcPackage opcPackage(pIOHandler, filename);
 
     std::unique_ptr<CIrrXML_IOStreamReader> xmlStream(new CIrrXML_IOStreamReader(opcPackage.RootStream()));
     std::unique_ptr<D3MF::XmlReader> xmlReader(irr::io::createIrrXMLReader(xmlStream.get()));

+ 39 - 29
code/D3MFOpcPackage.cpp

@@ -247,13 +247,13 @@ private:
 // ------------------------------------------------------------------------------------------------
 //  Constructor.
 D3MFZipArchive::D3MFZipArchive(IOSystem* pIOHandler, const std::string& rFile)
-: m_ZipFileHandle(NULL)
+: m_ZipFileHandle( nullptr )
 , m_ArchiveMap() {
     if (! rFile.empty()) {                
         zlib_filefunc_def mapping = IOSystem2Unzip::get(pIOHandler);            
 
         m_ZipFileHandle = unzOpen2(rFile.c_str(), &mapping);
-        if(m_ZipFileHandle != NULL) {            
+        if(m_ZipFileHandle != nullptr ) {
             mapArchive();
         }
     }
@@ -267,32 +267,32 @@ D3MFZipArchive::~D3MFZipArchive() {
     }
     m_ArchiveMap.clear();
 
-    if(m_ZipFileHandle != NULL) {
+    if(m_ZipFileHandle != nullptr) {
         unzClose(m_ZipFileHandle);
-        m_ZipFileHandle = NULL;
+        m_ZipFileHandle = nullptr;
     }
 }
 
 // ------------------------------------------------------------------------------------------------
 //  Returns true, if the archive is already open.
 bool D3MFZipArchive::isOpen() const {
-    return (m_ZipFileHandle != NULL);
+    return (m_ZipFileHandle != nullptr );
 }
 
 // ------------------------------------------------------------------------------------------------
 //  Returns true, if the filename is part of the archive.
 bool D3MFZipArchive::Exists(const char* pFile) const {
-    ai_assert(pFile != NULL);
-
-    bool exist = false;
+    ai_assert(pFile != nullptr );
 
-    if (pFile != NULL) {
-        std::string rFile(pFile);
-        std::map<std::string, ZipFile*>::const_iterator it = m_ArchiveMap.find(rFile);
+    if ( pFile == nullptr ) {
+        return false;
+    }
 
-        if(it != m_ArchiveMap.end()) {
-            exist = true;
-        }
+    std::string rFile(pFile);
+    std::map<std::string, ZipFile*>::const_iterator it = m_ArchiveMap.find(rFile);
+    bool exist( false );
+    if(it != m_ArchiveMap.end()) {
+        exist = true;
     }
 
     return exist;
@@ -434,8 +434,8 @@ public:
 
     std::vector<OpcPackageRelationshipPtr> m_relationShips;
 };
-// ------------------------------------------------------------------------------------------------
 
+// ------------------------------------------------------------------------------------------------
 D3MFOpcPackage::D3MFOpcPackage(IOSystem* pIOHandler, const std::string& rFile)
 : mRootStream(nullptr)
 , mZipArchive() {    
@@ -460,7 +460,7 @@ D3MFOpcPackage::D3MFOpcPackage(IOSystem* pIOHandler, const std::string& rFile)
             if ( rootFile.size() > 0 && rootFile[ 0 ] == '/' ) {
                 rootFile = rootFile.substr( 1 );
                 if ( rootFile[ 0 ] == '/' ) {
-                    // deal with zipbug
+                    // deal with zip-bug
                     rootFile = rootFile.substr( 1 );
                 }
             }
@@ -470,18 +470,9 @@ D3MFOpcPackage::D3MFOpcPackage(IOSystem* pIOHandler, const std::string& rFile)
             mRootStream = mZipArchive->Open(rootFile.c_str());
             ai_assert( mRootStream != nullptr );
             if ( nullptr == mRootStream ) {
-                throw DeadlyExportError( "Cannot open rootfile in archive : " + rootFile );
+                throw DeadlyExportError( "Cannot open root-file in archive : " + rootFile );
             }
 
-        //    const size_t size = zipArchive->FileSize();
-        //    m_Data.resize( size );
-
-        //    const size_t readSize = pMapFile->Read( &m_Data[0], sizeof( char ), size );
-        //    if ( readSize != size )
-        //    {
-        //        m_Data.clear();
-        //        return false;
-        //    }
             mZipArchive->Close( fileStream );
 
         } else if( file == D3MF::XmlTag::CONTENT_TYPES_ARCHIVE) {
@@ -498,6 +489,25 @@ IOStream* D3MFOpcPackage::RootStream() const {
     return mRootStream;
 }
 
+static const std::string ModelRef = "3D/3dmodel.model";
+
+bool D3MFOpcPackage::validate() {
+    if ( nullptr == mRootStream || nullptr == mZipArchive ) {
+        return false;
+    }
+
+    return mZipArchive->Exists( ModelRef.c_str() );
+}
+
+bool D3MFOpcPackage::isZipArchive( IOSystem* pIOHandler, const std::string& rFile ) {
+    D3MF::D3MFZipArchive ar( pIOHandler, rFile );
+    if ( !ar.isOpen() ) {
+        return false;
+    }
+
+    return true;
+}
+
 std::string D3MFOpcPackage::ReadPackageRootRelationship(IOStream* stream) {
     std::unique_ptr<CIrrXML_IOStreamReader> xmlStream(new CIrrXML_IOStreamReader(stream));
     std::unique_ptr<XmlReader> xml(irr::io::createIrrXMLReader(xmlStream.get()));
@@ -508,14 +518,14 @@ std::string D3MFOpcPackage::ReadPackageRootRelationship(IOStream* stream) {
         return rel->type == XmlTag::PACKAGE_START_PART_RELATIONSHIP_TYPE;
     });
 
-    if(itr == reader.m_relationShips.end())
-        throw DeadlyImportError("Cannot find " + XmlTag::PACKAGE_START_PART_RELATIONSHIP_TYPE);
+    if ( itr == reader.m_relationShips.end() ) {
+        throw DeadlyImportError( "Cannot find " + XmlTag::PACKAGE_START_PART_RELATIONSHIP_TYPE );
+    }
 
     return (*itr)->target;
 }
 
 } // Namespace D3MF
-
 } // Namespace Assimp
 
 #endif //ASSIMP_BUILD_NO_3MF_IMPORTER

+ 7 - 5
code/D3MFOpcPackage.h

@@ -51,8 +51,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 namespace Assimp {
 namespace D3MF {
 
-typedef irr::io::IrrXMLReader XmlReader;
-typedef std::shared_ptr<XmlReader> XmlReaderPtr;
+using XmlReader = irr::io::IrrXMLReader ;
+using XmlReaderPtr = std::shared_ptr<XmlReader> ;
 
 struct OpcPackageRelationship {
     std::string id;
@@ -64,9 +64,11 @@ class D3MFZipArchive;
 
 class D3MFOpcPackage {
 public:
-    D3MFOpcPackage(IOSystem* pIOHandler, const std::string& rFile);
+    D3MFOpcPackage( IOSystem* pIOHandler, const std::string& rFile );
     ~D3MFOpcPackage();
     IOStream* RootStream() const;
+    bool validate();
+    static bool isZipArchive( IOSystem* pIOHandler, const std::string& rFile );
 
 protected:
     std::string ReadPackageRootRelationship(IOStream* stream);
@@ -76,7 +78,7 @@ private:
     std::unique_ptr<D3MFZipArchive> mZipArchive;
 };
 
-}
-}
+} // Namespace D3MF
+} // Namespace Assimp
 
 #endif // D3MFOPCPACKAGE_H

+ 8 - 12
code/IRRLoader.cpp

@@ -100,26 +100,22 @@ IRRImporter::~IRRImporter()
 
 // ------------------------------------------------------------------------------------------------
 // Returns whether the class can handle the format of the given file.
-bool IRRImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const
-{
-    /* NOTE: A simple check for the file extension is not enough
-     * here. Irrmesh and irr are easy, but xml is too generic
-     * and could be collada, too. So we need to open the file and
-     * search for typical tokens.
-     */
+bool IRRImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const {
     const std::string extension = GetExtension(pFile);
-
-    if (extension == "irr")return true;
-    else if (extension == "xml" || checkSig)
-    {
+    if ( extension == "irr" ) {
+        return true;
+    } else if (extension == "xml" || checkSig) {
         /*  If CanRead() is called in order to check whether we
          *  support a specific file extension in general pIOHandler
          *  might be NULL and it's our duty to return true here.
          */
-        if (!pIOHandler)return true;
+        if ( nullptr == pIOHandler ) {
+            return true;
+        }
         const char* tokens[] = {"irr_scene"};
         return SearchFileHeaderForToken(pIOHandler,pFile,tokens,1);
     }
+
     return false;
 }
 

+ 33 - 3
include/assimp/StringUtils.h

@@ -55,7 +55,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 ///	@return	The number of written characters if the buffer size was big enough. If an encoding error occurs, a negative number is returned.
 #if defined(_MSC_VER) && _MSC_VER < 1900
 
-	inline int c99_ai_vsnprintf(char *outBuf, size_t size, const char *format, va_list ap) {
+	inline
+    int c99_ai_vsnprintf(char *outBuf, size_t size, const char *format, va_list ap) {
 		int count(-1);
 		if (0 != size) {
 			count = _vsnprintf_s(outBuf, size, _TRUNCATE, format, ap);
@@ -67,7 +68,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 		return count;
 	}
 
-	inline int ai_snprintf(char *outBuf, size_t size, const char *format, ...) {
+	inline
+    int ai_snprintf(char *outBuf, size_t size, const char *format, ...) {
 		int count;
 		va_list ap;
 
@@ -82,14 +84,24 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #   define ai_snprintf snprintf
 #endif
 
+///	@fn		to_string
+///	@brief	The portable version of to_string ( some gcc-versions on embedded devices are not supporting this).
+///	@param	value   The value to write into the std::string.
+///	@return	The value as a std::string
 template <typename T>
 inline
 std::string to_string( T value ) {
     std::ostringstream os;
     os << value;
+
     return os.str();
 }
 
+///	@fn		ai_strtof
+///	@brief	The portable version of strtof.
+///	@param	begin   The first character of the string.
+/// @param  end     The last character
+///	@return	The float value, 0.0f in cas of an error.
 inline
 float ai_strtof( const char *begin, const char *end ) {
     if ( nullptr == begin ) {
@@ -107,5 +119,23 @@ float ai_strtof( const char *begin, const char *end ) {
     return val;
 }
 
-#endif // INCLUDED_AI_STRINGUTILS_H
+///	@fn		DecimalToHexa
+///	@brief	The portable to convert a decimal value into a hexadecimal string.
+///	@param	toConvert   Value to convert
+///	@return	The hexadecimal string, is empty in case of an error.
+template<class T>
+inline
+std::string DecimalToHexa( T toConvert ) {
+    std::string result;
+    std::stringstream ss;
+    ss << std::hex << toConvert;
+    ss >> result;
+
+    for ( size_t i = 0; i < result.size(); ++i ) {
+        result[ i ] = toupper( result[ i ] );
+    }
 
+    return result;
+}
+
+#endif // INCLUDED_AI_STRINGUTILS_H

+ 0 - 2
include/assimp/fast_atof.h

@@ -146,7 +146,6 @@ uint8_t HexOctetToDecimal(const char* in) {
     return ((uint8_t)HexDigitToDecimal(in[0])<<4)+(uint8_t)HexDigitToDecimal(in[1]);
 }
 
-
 // ------------------------------------------------------------------------------------
 // signed variant of strtoul10
 // ------------------------------------------------------------------------------------
@@ -353,7 +352,6 @@ ai_real fast_atof(const char* c) {
     return ret;
 }
 
-
 inline
 ai_real fast_atof( const char* c, const char** cout) {
     ai_real ret(0.0);

+ 3 - 1
test/CMakeLists.txt

@@ -45,7 +45,9 @@ INCLUDE_DIRECTORIES(
     ${Assimp_SOURCE_DIR}/include
     ${Assimp_SOURCE_DIR}/code
 )
-
+if (MSVC)
+  set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /D_SILENCE_TR1_NAMESPACE_DEPRECATION_WARNING")
+endif()
 # Add the temporary output directories to the library path to make sure the
 # Assimp library can be found, even if it is not installed system-wide yet.
 LINK_DIRECTORIES( ${Assimp_BINARY_DIR} ${AssetImporter_BINARY_DIR}/lib )

+ 8 - 0
test/unit/utD3MFImportExport.cpp

@@ -86,4 +86,12 @@ TEST_F( utD3MFImporterExporter, export3MFtoMemTest ) {
     EXPECT_TRUE( exporterTest() );
 }
 
+TEST_F( utD3MFImporterExporter, roundtrip3MFtoMemTest ) {
+    EXPECT_TRUE( exporterTest() );
+
+    Assimp::Importer importer;
+    const aiScene *scene = importer.ReadFile( "test.3mf", 0 );
+    EXPECT_NE( nullptr, scene );
+}
+
 #endif // ASSIMP_BUILD_NO_EXPORT