Salome HOME
Copyright update 2021
[modules/smesh.git] / src / MEDWrapper / MED_Factory.cxx
1 // Copyright (C) 2007-2021  CEA/DEN, EDF R&D, OPEN CASCADE
2 //
3 // Copyright (C) 2003-2007  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
5 //
6 // This library is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU Lesser General Public
8 // License as published by the Free Software Foundation; either
9 // version 2.1 of the License, or (at your option) any later version.
10 //
11 // This library is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 // Lesser General Public License for more details.
15 //
16 // You should have received a copy of the GNU Lesser General Public
17 // License along with this library; if not, write to the Free Software
18 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
19 //
20 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
21 //
22
23 #include "MED_Factory.hxx"
24 #include "MED_Utilities.hxx"
25 #include "MED_Wrapper.hxx"
26
27 #include <Basics_Utils.hxx>
28
29 #include <stdio.h>
30 #include <errno.h>
31 #include <sstream>
32 #include <fstream>
33
34 #include <med.h>
35 extern "C"
36 {
37 #ifndef WIN32
38   #include <unistd.h>
39 #endif
40 }
41 #include <utilities.h>
42
43 #ifdef WIN32
44 #include <windows.h>
45 #endif
46
47 // -------------------------------------------------------------------------------------------------------------------
48 // --- MED file compatibility: write using a lower major version implies append on an empty file of the target version
49 //
50 // *******************************************************************************************************************
51 // ==> This file must be modified when MED version changes:
52 // MED_MAJOR_NUM and MED_MINOR_NUM are defined in an external include from MED prerequisite: med.h
53 // When MED_MAJOR_NUM or MED_MINOR_NUM changes, MED_MAJOR_EXPECTED and MED_MINOR_EXPECTED must be set accordingly
54 // and MED_VERSIONS_APPEND_COMPATIBLE must be updated: The lower compatible versions may change with a new MED version
55 // If the major version of MED change (for instance 4 --> 5) and if MED allows to append meshes in MED-4.x format,
56 // Empty file content for MED-4.x should be provided (EMPTY_FILE_4x) and method CreateEmptyMEDFile should be updated.
57 // *******************************************************************************************************************
58
59 #define MED_MAJOR_EXPECTED 4
60 #define MED_MINOR_EXPECTED 1
61 #if MED_MAJOR_NUM != MED_MAJOR_EXPECTED
62   #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)"
63 #endif
64 #if MED_MINOR_NUM != MED_MINOR_EXPECTED
65   #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)"
66 #endif
67 #define MED_VERSIONS_APPEND_COMPATIBLE {41, 40, 32, 33} // --- 10*major + minor (the 3rd digit, release, is not used here,
68                                                         //                       med uses always the latest available)
69                                                         // --- The first in the list should be the default: current version
70
71 namespace MED
72 {
73   bool exists(const std::string& fileName)
74   {
75 #ifdef WIN32
76 #ifdef UNICODE
77     int size_needed = MultiByteToWideChar(CP_UTF8, 0, fileName.c_str(), strlen(fileName.c_str()), NULL, 0);
78     wchar_t* path = new wchar_t[size_needed + 1];
79     MultiByteToWideChar(CP_UTF8, 0, fileName.c_str(), strlen(fileName.c_str()), path, size_needed);
80     path[size_needed] = '\0';
81 #else
82     cosnt char* path = xmlPath.c_str();
83 #endif
84     bool res = (GetFileAttributes(path) != INVALID_FILE_ATTRIBUTES);
85 #ifdef UNICODE
86     delete path;
87 #endif
88     return res;
89 #else
90     return (access(fileName.c_str(), F_OK) == 0);
91 #endif
92   }
93
94   /*!
95    *  Return the list of med versions compatibles for write/append,
96    *  encoded in 10*major+minor (for instance, code for med 3.2.1 is 32)
97    */
98   std::vector<int> GetMEDVersionsAppendCompatible()
99   {
100     int mvok[] = MED_VERSIONS_APPEND_COMPATIBLE;
101     std::vector<int> MEDVersionsOK(mvok, mvok + sizeof(mvok)/sizeof(int));
102     int curVersion = MED_MAJOR_NUM * 10 + MED_MINOR_NUM;
103     if ( MEDVersionsOK[0] != curVersion )
104       MEDVersionsOK.insert( MEDVersionsOK.begin(), curVersion );
105     return MEDVersionsOK;
106   }
107
108   /*!
109    *  \brief: Check read or write(append) Compatibility of a med file
110    *  \param [in] : fileName - the file to read or to append to
111    *  \param [in] : isforAppend - when true, check if the med file version is OK to append a mesh,
112    *                              when false, check if the med file is readable.
113    */
114   bool CheckCompatibility(const std::string& fileName, bool isForAppend)
115   {
116     bool ok = false;
117     std::vector<int> medVersionsOK = GetMEDVersionsAppendCompatible();
118     // check that file is accessible
119     if ( exists(fileName) ) {
120       // check HDF5 && MED compatibility
121       med_bool hdfok, medok;
122       med_err r0 = MEDfileCompatibility(fileName.c_str(), &hdfok, &medok);
123       MESSAGE(r0 << " " << hdfok << " " << medok);
124       if ( r0==0 && hdfok && medok ) {
125         med_idt aFid = MEDfileOpen(fileName.c_str(), MED_ACC_RDONLY);
126         if (aFid >= 0) {
127           med_int major, minor, release;
128           med_err ret = MEDfileNumVersionRd(aFid, &major, &minor, &release);
129           MESSAGE(ret << " " << major << "." << minor << "." << release);
130           if (ret >= 0) {
131             bool isReadOnly = !isForAppend;
132             if (isReadOnly)
133               ok = true;
134             else {
135               int medVersion = 10*major + minor;
136               for (size_t ii=0; ii < medVersionsOK.size(); ii++)
137                 if (medVersionsOK[ii] == medVersion) {
138                   ok =true;
139                   break;
140                 }
141             }
142           }
143         }
144         MEDfileClose(aFid);
145       }
146     }
147     return ok;
148   }
149
150   bool GetMEDVersion(const std::string& fileName, int& major, int& minor, int& release)
151   {
152     bool ok = false;
153     major = minor = release = 0;
154     med_idt aFid = MEDfileOpen(fileName.c_str(), MED_ACC_RDONLY);
155     if (aFid >= 0) {
156       med_int _major, _minor, _release;
157       med_err ret = MEDfileNumVersionRd(aFid, &_major, &_minor, &_release);
158       if (ret == 0) {
159         major = _major;
160         minor = _minor;
161         release = _release;
162         ok = true;
163       }
164       MEDfileClose(aFid);
165     }
166     return ok;
167   }
168
169   std::string GetMEDVersion(const std::string& fileName)
170   {
171     std::string version;
172     int major, minor, release;
173     if (GetMEDVersion(fileName, major, minor, release)) {
174       std::ostringstream os;
175       os << major << "." << minor << "." << release;
176       version = os.str();
177     }
178     return version;
179   }
180
181   PWrapper CrWrapperR(const std::string& fileName)
182   {
183     if (!CheckCompatibility(fileName)) {
184       EXCEPTION(std::runtime_error, "Cannot open file '"<<fileName<<"'.");
185     }
186     return new MED::TWrapper(fileName, false);
187   }
188
189   PWrapper CrWrapperW(const std::string& fileName, int theVersion)
190   {
191     bool isCreated = false;
192     if (!CheckCompatibility(fileName, true))
193     {
194       remove(fileName.c_str());
195       isCreated = true;
196     }
197     med_int wantedMajor = MED_MAJOR_NUM;
198     med_int wantedMinor = MED_MINOR_NUM;
199     // when non managed version of file is requested : ignore it and take the latest version
200     std::vector<int> versionsOK(GetMEDVersionsAppendCompatible());
201     bool isVersionRequestedOK(std::find(versionsOK.begin(),versionsOK.end(),theVersion)!=versionsOK.end());
202     if (isCreated && isVersionRequestedOK)
203     {
204       wantedMajor = theVersion/10;
205       wantedMinor = theVersion%10;
206     }
207     return new MED::TWrapper(fileName, true, wantedMajor, wantedMinor);
208   }
209 }