1 // Copyright (C) 2007-2021 CEA/DEN, EDF R&D, OPEN CASCADE
3 // This library is free software; you can redistribute it and/or
4 // modify it under the terms of the GNU Lesser General Public
5 // License as published by the Free Software Foundation; either
6 // version 2.1 of the License, or (at your option) any later version.
8 // This library is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 // Lesser General Public License for more details.
13 // You should have received a copy of the GNU Lesser General Public
14 // License along with this library; if not, write to the Free Software
15 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
19 // File : SMESHUtils_MGLicenseKeyGen.cxx
20 // Created : Sat Jul 31 18:54:16 2021
21 // Author : Edward AGAPOV (OCC)
23 #include "SMESH_MGLicenseKeyGen.hxx"
25 #include "SMESH_Comment.hxx"
26 #include "SMESH_File.hxx"
27 #include "SMESH_TryCatch.hxx"
29 #include <Basics_DirUtils.hxx>
30 #include <Basics_Utils.hxx>
32 #include <cstdlib> // getenv, system
34 #include <boost/filesystem.hpp>
35 #include <boost/regex.hpp>
36 namespace boofs = boost::filesystem;
43 # define LibHandle HMODULE
44 # define LoadLib( name ) LoadLibrary( name )
45 # define GetProc GetProcAddress
46 # define UnLoadLib( handle ) FreeLibrary( handle );
52 # define LibHandle void*
53 # define LoadLib( name ) dlopen( name, RTLD_LAZY | RTLD_LOCAL )
54 # define GetProc dlsym
55 # define UnLoadLib( handle ) dlclose( handle );
59 // to retrieve description of exception caught by SMESH_TRY
61 #define SMESH_CAUGHT error =
63 constexpr char MESHGEMS_OLD_STYLE[] = "MESHGEMS_OLD_STYLE";
68 static LibHandle theLibraryHandle = nullptr; //!< handle of a loaded library
70 const char* theEnvVar = "SALOME_MG_KEYGEN_LIB_PATH"; /* var specifies either full file name
71 of libSalomeMeshGemsKeyGenerator or
72 URL to download the library from */
74 const char* theTmpEnvVar = "SALOME_TMP_DIR"; // directory to download the library to
76 //-----------------------------------------------------------------------------------
78 * \brief Remove library file at destruction in case if it was downloaded from server
80 //-----------------------------------------------------------------------------------
84 std::string _name; // full file name
87 LibraryFile(): _isURL( false ) {}
93 if ( theLibraryHandle )
95 UnLoadLib( theLibraryHandle );
96 theLibraryHandle = nullptr;
99 std::string tmpDir; // tmp dir that should not be removed
100 if ( const char* libPath = getenv( theTmpEnvVar ))
103 while (( !tmpDir.empty() ) &&
104 ( tmpDir.back() == '/' || tmpDir.back() == '\\' ))
108 while ( SMESH_File( _name ).remove() )
110 size_t length = _name.size();
111 _name = boofs::path( _name ).parent_path().string(); // goto parent directory
112 if ( _name.size() == length )
113 break; // no more parents
115 if ( _name == tmpDir )
116 break; // don't remove tmp dir
118 if ( !Kernel_Utils::IsEmptyDir( _name ))
126 //================================================================================
128 * \brief Retrieve description of the last error
129 * \param [out] error - return the description
130 * \return bool - true if the description found
132 //================================================================================
134 bool getLastError( std::string& error )
138 if ( const char* text = dlerror() )
147 DWORD dw = GetLastError();
149 DWORD msgLen = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
152 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
158 # if defined( UNICODE )
159 error = Kernel_Utils::encode_s((wchar_t*)cstr);
171 //================================================================================
173 * \brief Adjust file extension according to the platform
175 //================================================================================
177 bool setExtension( std::string& fileName, std::string& error )
179 if ( fileName.empty() )
181 error = "Library file name is empty";
185 std::string ext = ".dll";
186 #elif defined(__APPLE__)
187 std::string ext = ".dylib";
189 std::string ext = ".so";
192 fileName = fileName.substr( 0, fileName.find_last_of('.')) + ext;
196 //================================================================================
198 * \brief Check if library file name looks like an URL
199 * \param [in,out] libraryFile - holds file name and returns result in _isURL member field
200 * \return bool - true if the file name looks like an URL
202 //================================================================================
204 bool isURL( LibraryFile & libraryFile )
207 enum { SCHEME = 2, AUTHORITY = 4, PATH = 5 }; // sub-strings
208 boost::regex urlRegex ( R"(^(([^:\/?#]+):)?(//([^\/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?)",
209 boost::regex::extended );
210 boost::smatch matchResult;
212 libraryFile._isURL = false;
213 if ( boost::regex_match( libraryFile._name, matchResult, urlRegex ))
214 libraryFile._isURL = ( !matchResult.str( SCHEME ).empty() &&
215 !matchResult.str( AUTHORITY ).empty() &&
216 !matchResult.str( PATH ).empty() );
218 if(libraryFile._isURL)
221 enum { HOST = 2, PORT = 3, PATH = 4 }; // sub-strings
222 boost::regex urlRegex ( R"(^(([^:\/?#]+):)?([^/]+)?(/[^#]*))",
223 boost::regex::extended );
224 boost::smatch matchResult;
226 libraryFile._isURL = false;
227 if ( boost::regex_match( libraryFile._name, matchResult, urlRegex ))
228 libraryFile._isURL = ( !matchResult.str( HOST ).empty() &&
229 !matchResult.str( PORT ).empty() &&
230 !matchResult.str( PATH ).empty() );
232 return libraryFile._isURL;
235 //================================================================================
237 * \brief Download libraryFile._name URL to SALOME_TMP_DIR
238 * \param [in,out] libraryFile - holds the URL and returns name of a downloaded file
239 * \param [out] error - return error description
240 * \return bool - is a success
242 //================================================================================
244 bool downloadLib( LibraryFile& libraryFile, std::string & error )
246 // check if can write into SALOME_TMP_DIR
248 std::string tmpDir = Kernel_Utils::GetTmpDirByEnv( theTmpEnvVar );
249 if ( tmpDir.empty() ||
250 !Kernel_Utils::IsExists( tmpDir ))
252 error = "Can't download " + libraryFile._name + " as SALOME_TMP_DIR is not correctly set";
255 if ( !Kernel_Utils::IsWritable( tmpDir ))
257 error = "Can't download " + libraryFile._name + " as '" + tmpDir + "' is not writable. "
258 "Check SALOME_TMP_DIR environment variable";
264 std::string url = libraryFile._name;
268 std::string outFile = tmpDir + "MeshGemsKeyGenerator.dll";
270 // use wget (== Invoke-WebRequest) PowerShell command available since Windows 7
271 std::string psCmd = "wget -Uri " + url + " -OutFile " + outFile;
272 std::string cmd = "powershell.exe " + psCmd;
276 std::string outFile = tmpDir + "libMeshGemsKeyGenerator.so";
278 std::string cmd = "wget " + url + " -O " + outFile;
282 if ( Kernel_Utils::IsExists( outFile )) // remove existing file
284 SMESH_File lib( outFile, /*open=*/false );
292 system( cmd.c_str() ); // download
294 SMESH_File resultFile( outFile, /*open=*/false );
295 bool ok = ( resultFile.exists() && resultFile.size() > 0 );
298 libraryFile._name = outFile;
300 error = "Can't download file " + url;
305 //================================================================================
307 * \brief Load libMeshGemsKeyGenerator.so
308 * \param [out] error - return error description
309 * \param [out] libraryFile - return library file name and _isURL flag
310 * \return bool - is a success
312 //================================================================================
314 bool loadLibrary( std::string& error, LibraryFile& libraryFile )
316 if ( theLibraryHandle )
319 const char* libPath = getenv( theEnvVar );
322 error = SMESH_Comment( "Environment variable ") << theEnvVar << " is not set";
326 libraryFile._name = libPath;
327 // if ( !setExtension( libraryFile._name, error )) // is it necessary?
330 if ( isURL( libraryFile ))
332 if ( !downloadLib( libraryFile, error ))
334 // try to fix extension
335 std::string url = libraryFile._name;
336 if ( !setExtension( libraryFile._name, error ))
338 if ( url == libraryFile._name )
339 return false; // extension not changed
341 if ( !downloadLib( libraryFile, error ))
346 #if defined( WIN32 ) && defined( UNICODE )
347 std::wstring encodePath = Kernel_Utils::utf8_decode_s( libraryFile._name );
348 const wchar_t* path = encodePath.c_str();
350 const char* path = libraryFile._name.c_str();
353 theLibraryHandle = LoadLib( path );
354 if ( !theLibraryHandle )
356 if ( ! getLastError( error ))
357 error = "Can't load library '" + libraryFile._name + "'";
360 return theLibraryHandle;
363 } // anonymous namespace
366 namespace SMESHUtils_MGLicenseKeyGen // API implementation
368 //================================================================================
371 * \param [in] meshgems_cad - pointer to a MG CAD object (meshgems_cad_t)
372 * \param [out] error - return error description
373 * \return bool - is a success
375 //================================================================================
377 bool SignCAD_After( void* meshgems_cad, std::string& error )
379 LibraryFile libraryFile;
380 if ( !loadLibrary( error, libraryFile ))
384 typedef bool (*SignFun)(void* );
385 SignFun signFun = (SignFun) GetProc( theLibraryHandle, "SignCAD" );
388 if ( ! getLastError( error ))
389 error = SMESH_Comment( "Can't find symbol 'SignCAD' in '") << getenv( theEnvVar ) << "'";
395 ok = signFun( meshgems_cad );
397 SMESH_CATCH( SMESH::returnError );
399 if ( !error.empty() )
402 error = "SignCAD() failed (located in '" + libraryFile._name + "')";
407 bool SignCAD( void* meshgems_cad, std::string& error )
409 const char *meshGemsOldStyleEnvVar( getenv( MESHGEMS_OLD_STYLE ) );
410 if ( !meshGemsOldStyleEnvVar || strlen(meshGemsOldStyleEnvVar) == 0 )
411 return SignCAD_After(meshgems_cad, error);
416 //================================================================================
419 * \param [in] meshgems_mesh - pointer to a MG mesh (meshgems_mesh_t)
420 * \param [out] error - return error description
421 * \return bool - is a success
423 //================================================================================
425 bool SignMesh_After( void* meshgems_mesh, std::string& error )
427 LibraryFile libraryFile;
428 if ( !loadLibrary( error, libraryFile ))
432 typedef bool (*SignFun)(void* );
433 SignFun signFun = (SignFun) GetProc( theLibraryHandle, "SignMesh" );
436 if ( ! getLastError( error ))
437 error = SMESH_Comment( "Can't find symbol 'SignMesh' in '") << getenv( theEnvVar ) << "'";
443 ok = signFun( meshgems_mesh );
445 SMESH_CATCH( SMESH::returnError );
447 if ( !error.empty() )
450 error = "SignMesh() failed (located in '" + libraryFile._name + "')";
455 bool SignMesh( void* meshgems_mesh, std::string& error )
457 const char *meshGemsOldStyleEnvVar( getenv( MESHGEMS_OLD_STYLE ) );
458 if ( !meshGemsOldStyleEnvVar || strlen(meshGemsOldStyleEnvVar) == 0 )
459 return SignMesh_After(meshgems_mesh, error);
464 //================================================================================
466 * \brief Return a license key to pass as argument to a MG mesher executable
467 * \param [in] gmfFile - path to an input mesh file
468 * \param [in] nb* - nb of entities in the input mesh
469 * \param [out] error - return error description
470 * \return std::string - the key
472 //================================================================================
474 std::string GetKey_After(const std::string& gmfFile,
482 LibraryFile libraryFile;
483 if ( !loadLibrary( error, libraryFile ))
486 typedef std::string (*GetKeyFun)(std::string const &, int, int, int, int );
487 GetKeyFun keyFun = (GetKeyFun) GetProc( theLibraryHandle, "GetKey" );
490 if ( ! getLastError( error ))
491 error = SMESH_Comment( "Can't find symbol 'GetKey' in '") << getenv( theEnvVar ) << "'";
495 key = keyFun( gmfFile, nbVertex, nbEdge, nbFace, nbVol );
498 error = "GetKey() failed (located in '" + libraryFile._name + "')";
503 std::string GetKey(const std::string& gmfFile,
510 const char *meshGemsOldStyleEnvVar( getenv( MESHGEMS_OLD_STYLE ) );
511 if ( !meshGemsOldStyleEnvVar || strlen(meshGemsOldStyleEnvVar) == 0 )
512 return GetKey_After(gmfFile,nbVertex,nbEdge,nbFace,nbVol,error);
514 return std::string("0");
517 //================================================================================
519 * \brief Return false if libMeshGemsKeyGenerator.so is not functional
520 * \param [out] error - return error description
521 * \return bool - is a success
523 //================================================================================
525 bool CheckKeyGenLibrary( std::string& error )
527 return !GetKey("",4,0,2,0,error ).empty();
530 //================================================================================
532 * \brief Return KeyGenerator library name
534 //================================================================================
536 std::string GetLibraryName()
538 std::string libName, error;
539 if ( const char* libPath = getenv( theEnvVar ))
541 libName = Kernel_Utils::GetBaseName( libPath );
545 libName = "libSalomeMeshGemsKeyGenerator";
547 setExtension( libName, error );