Salome HOME
Copyright update 2020
[modules/smesh.git] / src / MEDWrapper / MED_Factory.cxx
index 3e354c131c4e8cdea033cc7b44c1b608773ccab5..114cb623e5ce7a7c653159414872fac42bb28df5 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright (C) 2007-2016  CEA/DEN, EDF R&D, OPEN CASCADE
+// Copyright (C) 2007-2020  CEA/DEN, EDF R&D, OPEN CASCADE
 //
 // Copyright (C) 2003-2007  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
 #include "MED_Utilities.hxx"
 #include "MED_Wrapper.hxx"
 
+#include <Basics_Utils.hxx>
+
 #include <stdio.h>
 #include <errno.h>
 #include <sstream>
+#include <fstream>
 
 #include <med.h>
 extern "C"
@@ -41,6 +44,29 @@ extern "C"
 #include <windows.h>
 #endif
 
+// -------------------------------------------------------------------------------------------------------------------
+// --- MED file compatibility: write using a lower major version implies append on an empty file of the target version
+//
+// *******************************************************************************************************************
+// ==> This file must be modified when MED version changes:
+// MED_MAJOR_NUM and MED_MINOR_NUM are defined in an external include from MED prerequisite: med.h
+// When MED_MAJOR_NUM or MED_MINOR_NUM changes, MED_MAJOR_EXPECTED and MED_MINOR_EXPECTED must be set accordingly
+// and MED_VERSIONS_APPEND_COMPATIBLE must be updated: The lower compatible versions may change with a new MED version
+// If the major version of MED change (for instance 4 --> 5) and if MED allows to append meshes in MED-4.x format,
+// Empty file content for MED-4.x should be provided (EMPTY_FILE_4x) and method CreateEmptyMEDFile should be updated.
+// *******************************************************************************************************************
+
+#define MED_MAJOR_EXPECTED 4
+#define MED_MINOR_EXPECTED 1
+#if MED_MAJOR_NUM != MED_MAJOR_EXPECTED
+  #error "MED major version does not correspond to the expected version, fix the minor and major compatibility values in CheckCompatibility method (MED_VERSIONS_APPEND_COMPATIBLE) and set the correct expected version (MED_MAJOR_EXPECTED, MED_MINOR_EXPECTED)"
+#endif
+#if MED_MINOR_NUM != MED_MINOR_EXPECTED
+  #error "MED minor version does not correspond to the expected version, fix the minor and major compatibility values in CheckCompatibility method (MED_VERSIONS_APPEND_COMPATIBLE) and set the correct expected version above (MED_MAJOR_EXPECTED, MED_MINOR_EXPECTED)"
+#endif
+#define MED_VERSIONS_APPEND_COMPATIBLE {41, 40, 32, 33} // --- 10*major + minor (the 3rd digit, release, is not used here,
+                                                        //                       med uses always the latest available)
+                                                        // --- The first in the list should be the default: current version
 
 namespace MED
 {
@@ -48,42 +74,71 @@ namespace MED
   {
 #ifdef WIN32
 #ifdef UNICODE
-       size_t length = strlen(fileName.c_str()) + sizeof(char);
-       wchar_t* path = new wchar_t[length];
-       memset(path, '\0', length);
-       mbstowcs(path, fileName.c_str(), length);
+    int size_needed = MultiByteToWideChar(CP_UTF8, 0, fileName.c_str(), strlen(fileName.c_str()), NULL, 0);
+    wchar_t* path = new wchar_t[size_needed + 1];
+    MultiByteToWideChar(CP_UTF8, 0, fileName.c_str(), strlen(fileName.c_str()), path, size_needed);
+    path[size_needed] = '\0';
 #else
-       cosnt char* path = xmlPath.c_str();
+    cosnt char* path = xmlPath.c_str();
 #endif
-       bool res = (GetFileAttributes(path) != INVALID_FILE_ATTRIBUTES);
+    bool res = (GetFileAttributes(path) != INVALID_FILE_ATTRIBUTES);
 #ifdef UNICODE
-       delete path;
+    delete path;
 #endif
-       return res;
+    return res;
 #else
     return (access(fileName.c_str(), F_OK) == 0);
 #endif
   }
 
+  /*!
+   *  Return the list of med versions compatibles for write/append,
+   *  encoded in 10*major+minor (for instance, code for med 3.2.1 is 32)
+   */
+  std::vector<int> GetMEDVersionsAppendCompatible()
+  {
+    int mvok[] = MED_VERSIONS_APPEND_COMPATIBLE;
+    std::vector<int> MEDVersionsOK(mvok, mvok + sizeof(mvok)/sizeof(int));
+    int curVersion = MED_MAJOR_NUM * 10 + MED_MINOR_NUM;
+    if ( MEDVersionsOK[0] != curVersion )
+      MEDVersionsOK.insert( MEDVersionsOK.begin(), curVersion );
+    return MEDVersionsOK;
+  }
+
+  /*!
+   *  \brief: Check read or write(append) Compatibility of a med file
+   *  \param [in] : fileName - the file to read or to append to
+   *  \param [in] : isforAppend - when true, check if the med file version is OK to append a mesh,
+   *                              when false, check if the med file is readable.
+   */
   bool CheckCompatibility(const std::string& fileName, bool isForAppend)
   {
     bool ok = false;
+    std::vector<int> medVersionsOK = GetMEDVersionsAppendCompatible();
     // check that file is accessible
     if ( exists(fileName) ) {
       // check HDF5 && MED compatibility
       med_bool hdfok, medok;
       med_err r0 = MEDfileCompatibility(fileName.c_str(), &hdfok, &medok);
-      //MESSAGE(r0 << " " << hdfok << " " << medok);
+      MESSAGE(r0 << " " << hdfok << " " << medok);
       if ( r0==0 && hdfok && medok ) {
         med_idt aFid = MEDfileOpen(fileName.c_str(), MED_ACC_RDONLY);
         if (aFid >= 0) {
           med_int major, minor, release;
           med_err ret = MEDfileNumVersionRd(aFid, &major, &minor, &release);
-          //MESSAGE(ret << " " << major << "." << minor << "." << release);
+          MESSAGE(ret << " " << major << "." << minor << "." << release);
           if (ret >= 0) {
             bool isReadOnly = !isForAppend;
-            if ( isReadOnly  || ((major == MED_MAJOR_NUM) && (minor == MED_MINOR_NUM)))
+            if (isReadOnly)
               ok = true;
+            else {
+              int medVersion = 10*major + minor;
+              for (size_t ii=0; ii < medVersionsOK.size(); ii++)
+                if (medVersionsOK[ii] == medVersion) {
+                  ok =true;
+                  break;
+                }
+            }
           }
         }
         MEDfileClose(aFid);
@@ -128,13 +183,27 @@ namespace MED
     if (!CheckCompatibility(fileName)) {
       EXCEPTION(std::runtime_error, "Cannot open file '"<<fileName<<"'.");
     }
-    return new MED::TWrapper(fileName);
+    return new MED::TWrapper(fileName, false);
   }
 
-  PWrapper CrWrapperW(const std::string& fileName, int theMinor)
+  PWrapper CrWrapperW(const std::string& fileName, int theVersion)
   {
+    bool isCreated = false;
     if (!CheckCompatibility(fileName, true))
+    {
       remove(fileName.c_str());
-    return new MED::TWrapper(fileName, theMinor);
+      isCreated = true;
+    }
+    med_int wantedMajor = MED_MAJOR_NUM;
+    med_int wantedMinor = MED_MINOR_NUM;
+    // when non managed version of file is requested : ignore it and take the latest version
+    std::vector<int> versionsOK(GetMEDVersionsAppendCompatible());
+    bool isVersionRequestedOK(std::find(versionsOK.begin(),versionsOK.end(),theVersion)!=versionsOK.end());
+    if (isCreated && isVersionRequestedOK)
+    {
+      wantedMajor = theVersion/10;
+      wantedMinor = theVersion%10;
+    }
+    return new MED::TWrapper(fileName, true, wantedMajor, wantedMinor);
   }
 }