Salome HOME
Run SALOME with UNICODE path.
[modules/gui.git] / src / LightApp / LightApp_Driver.cxx
1 // Copyright (C) 2007-2019  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 "LightApp_Driver.h"
24
25 #include <TCollection_AsciiString.hxx> 
26
27 #include <OSD_Path.hxx>
28 #include <OSD_File.hxx>
29 #include <OSD_Directory.hxx>
30 #include <OSD_Protection.hxx>
31 #include <OSD_FileIterator.hxx>
32
33 #include <QFileInfo>
34 #include <QDir>
35
36 #include <Qtx.h>
37
38 #ifdef WIN32
39 #include <time.h>
40 #endif
41
42 /*! Constructor.*/
43 LightApp_Driver::LightApp_Driver()
44 : myIsTemp( false )
45 {
46 }
47  
48 /*! Destructor.*/
49 LightApp_Driver::~LightApp_Driver()
50 {
51 }
52
53 /*!
54   Save in file 'theFileName' datas from this driver
55 */
56 bool LightApp_Driver::SaveDatasInFile( const char* theFileName, bool isMultiFile )
57 {
58   int aNbModules = 0;
59   std::map<std::string, ListOfFiles>::const_iterator it;
60   for (it = myMap.begin(); it != myMap.end(); ++it)
61     aNbModules++;
62
63   unsigned char** aBuffer = new unsigned char*[aNbModules]; 
64   long*           aBufferSize = new long[aNbModules];
65   char**          aModuleName = new char*[aNbModules];
66
67   if(aBuffer == NULL || aBufferSize == NULL || aModuleName == NULL)
68     return false;
69
70   int aFileBufferSize = 4;  //4 bytes for a number of the modules that will be written to the stream;
71   int i = 0;
72   for (it = myMap.begin(); it != myMap.end(); ++it) {
73     aModuleName[i] = const_cast<char*>(it->first.c_str());//(it->first);
74     aFileBufferSize += 4;                                //Add 4 bytes: a length of the module name
75     aFileBufferSize += strlen(aModuleName[i])+1;
76     std::string aName(aModuleName[i]);
77     PutFilesToStream(aName, aBuffer[i], aBufferSize[i], isMultiFile);
78     aFileBufferSize += 8;                                //Add 8 bytes: a length of the buffer
79     aFileBufferSize += aBufferSize[i];
80     i++;
81   }
82   int n = i;
83
84   unsigned char* aFileBuffer = new unsigned char[aFileBufferSize];
85   if(aFileBuffer == NULL)
86     return false;
87
88   myTmpDir = QDir::toNativeSeparators( QFileInfo( theFileName ).absolutePath() + "/" ).toUtf8().constData() ;
89
90   int aCurrentPos = 0;
91
92   //Initialize 4 bytes of the buffer by 0
93   memset(aFileBuffer, 0, 4); 
94   //Copy the number of modules that will be written to the stream
95   memcpy(aFileBuffer, &aNbModules, ((sizeof(int) > 4) ? 4 : sizeof(int)));
96   aCurrentPos += 4;
97
98   int aBufferNameSize = 0;
99   for (i = 0; i < n; i++) {
100     aBufferNameSize = strlen(aModuleName[i])+1;
101     //Initialize 4 bytes of the buffer by 0
102     memset((aFileBuffer + aCurrentPos), 0, 4); 
103     //Copy the length of the module name to the buffer
104     memcpy((aFileBuffer + aCurrentPos), &aBufferNameSize, ((sizeof(int) > 4) ? 4 : sizeof(int))); 
105     aCurrentPos += 4;
106     //Copy the module name to the buffer
107     memcpy((aFileBuffer + aCurrentPos), aModuleName[i], aBufferNameSize);
108     aCurrentPos += aBufferNameSize;
109
110     //Initialize 8 bytes of the buffer by 0
111     memset((aFileBuffer + aCurrentPos), 0, 8);
112     //Copy the length of the module buffer to the buffer
113     memcpy((aFileBuffer + aCurrentPos), (aBufferSize + i), ((sizeof(long) > 8) ? 8 : sizeof(long)));
114     aCurrentPos += 8;
115     //Copy the module buffer to the buffer
116     memcpy((aFileBuffer + aCurrentPos), aBuffer[i], aBufferSize[i]);
117     aCurrentPos += aBufferSize[i];
118   }
119
120 #ifdef WIN32
121   ofstream aFile(theFileName, ios::out | ios::binary);
122 #else
123   ofstream aFile(theFileName);
124 #endif
125   aFile.write((char*)aFileBuffer, aFileBufferSize); 
126   aFile.close();    
127
128   delete[] aBuffer;
129   delete[] aBufferSize;
130   delete[] aModuleName;
131   delete[] aFileBuffer;
132
133   return true;
134 }
135
136 /*!
137   Filling current driver from file 'theFileName'
138 */
139 bool LightApp_Driver::ReadDatasFromFile( const char* theFileName, bool isMultiFile )
140 {
141 #ifdef WIN32
142   ifstream aFile(theFileName, ios::binary);
143 #else
144   ifstream aFile(theFileName);
145 #endif  
146
147   myTmpDir = QDir::toNativeSeparators( QFileInfo( theFileName ).absolutePath() + "/" ).toUtf8().constData() ;
148
149   aFile.seekg(0, ios::end);
150   int aFileBufferSize = aFile.tellg();
151   unsigned char* aFileBuffer = new unsigned char[aFileBufferSize];
152   aFile.seekg(0, ios::beg);
153   aFile.read((char*)aFileBuffer, aFileBufferSize);
154   aFile.close();
155
156   int aNbModules = 0;
157   //Copy the number of files in the stream
158   memcpy(&aNbModules, aFileBuffer, sizeof(int));
159   long aCurrentPos = 4;
160   int aModuleNameSize;
161
162   for (int i = 0; i < aNbModules; i++) {
163     //Put a length of the module name to aModuleNameSize
164     memcpy(&aModuleNameSize, (aFileBuffer + aCurrentPos), ((sizeof(int) > 4) ? 4 : sizeof(int))); 
165     aCurrentPos += 4;
166
167     char *aModuleName = new char[aModuleNameSize];
168     //Put a module name to aModuleName
169     memcpy(aModuleName, (aFileBuffer + aCurrentPos), aModuleNameSize); 
170     aCurrentPos += aModuleNameSize;
171
172     //Put a length of the file buffer to aBufferSize
173     long aBufferSize;
174     memcpy(&aBufferSize, (aFileBuffer + aCurrentPos), ((sizeof(long) > 8) ? 8 : sizeof(long))); 
175     aCurrentPos += 8;
176     unsigned char *aBuffer = new unsigned char[aBufferSize];
177  
178     //Put a buffer for current module to aBuffer
179     memcpy(aBuffer, (aFileBuffer + aCurrentPos), aBufferSize); 
180     aCurrentPos += aBufferSize;
181
182     // Put buffer to aListOfFiles and set to myMap
183     ListOfFiles aListOfFiles = PutStreamToFiles(aBuffer, aBufferSize, isMultiFile);
184     SetListOfFiles(aModuleName, aListOfFiles);
185
186     delete[] aModuleName;
187     delete[] aBuffer;
188   }
189
190   delete[] aFileBuffer;
191   
192   return true;
193 }
194
195 /*!
196   \return temp directory for path 'theURL'
197 */
198 std::string LightApp_Driver::GetTmpDir (const char* theURL, const bool  isMultiFile)
199 {
200   std::string anURLDir = GetDirFromPath(theURL);
201   std::string aTmpDir = isMultiFile ? anURLDir : GetTmpDir();
202
203   return aTmpDir;
204 }
205
206 /*!
207   \return list of files for module with name 'theModuleName'
208 */
209 LightApp_Driver::ListOfFiles LightApp_Driver::GetListOfFiles( const char* theModuleName )
210 {
211   ListOfFiles aListOfFiles;
212
213   std::string aName(theModuleName);
214   if (myMap.count(aName))
215     aListOfFiles = myMap[aName];
216
217     return aListOfFiles;
218 }
219
220 /*!
221   Sets list of files for module with name 'theModuleName'
222 */
223 void LightApp_Driver::SetListOfFiles( const char* theModuleName, const ListOfFiles theListOfFiles )
224 {
225   std::string aName (theModuleName);
226   myMap[aName] = theListOfFiles;
227 }
228
229 /*!
230   Converts files which was created from module <theModuleName> into a byte sequence unsigned char
231 */
232 void LightApp_Driver::PutFilesToStream( const std::string& theModuleName, unsigned char*& theBuffer,
233                                         long& theBufferSize, bool theNamesOnly )
234 {
235   ListOfFiles aFiles = myMap[theModuleName];
236   // aFiles must contain temporary directory name in its first item
237   // and names of files (relatively the temporary directory) in the others
238
239   int i, aLength = aFiles.size() - 1;
240   if(aLength <= 0) {
241     theBufferSize = 0;
242     theBuffer = new unsigned char[theBufferSize];
243     return;
244   }
245   //Get a temporary directory for saved a file
246   TCollection_AsciiString aTmpDir(const_cast<char*>(aFiles[0].c_str()));
247
248   long aBufferSize = 0;
249   long aCurrentPos;
250   int aNbFiles = 0;
251   int* aFileNameSize= new int[aLength];
252   long* aFileSize= new long[aLength];
253
254   //Determine the required size of the buffer
255   TCollection_AsciiString aFileName;
256   for (i = 0; i < aLength; i++) {
257     char* aFName = const_cast<char*>(aFiles[i+1].c_str());
258     aFileName = aFName;
259     //Check if the file exists
260     if (!theNamesOnly) { // mpv 15.01.2003: if only file names must be stroed, then size of files is zero
261       TCollection_AsciiString aFullPath = aTmpDir + aFileName;   
262       OSD_Path anOSDPath(aFullPath);
263       OSD_File anOSDFile(anOSDPath);
264       if(!anOSDFile.Exists()) continue;
265 #ifdef WIN32
266       ifstream aFile(aFullPath.ToCString(), ios::binary);
267 #else
268       ifstream aFile(aFullPath.ToCString());
269 #endif
270       aFile.seekg(0, ios::end);
271       aFileSize[i] = aFile.tellg();
272       aBufferSize += aFileSize[i];              //Add a space to store the file
273     }
274     aFileNameSize[i] = strlen(aFName) + 1;
275     aBufferSize += aFileNameSize[i];          //Add a space to store the file name
276     aBufferSize += (theNamesOnly)?4:12;       //Add 4 bytes: a length of the file name,
277                                               //    8 bytes: length of the file itself
278     aNbFiles++;
279   }
280
281   aBufferSize += 4;      //4 bytes for a number of the files that will be written to the stream;
282   theBuffer = new unsigned char[aBufferSize];  
283   if(theBuffer == NULL) {
284     theBufferSize = 0;
285     theBuffer = 0;
286     return;
287   }
288   //Initialize 4 bytes of the buffer by 0
289   memset(theBuffer, 0, 4); 
290   //Copy the number of files that will be written to the stream
291   memcpy(theBuffer, &aNbFiles, ((sizeof(int) > 4) ? 4 : sizeof(int))); 
292
293   aCurrentPos = 4;
294
295   for(i = 0; i < aLength; i++) {
296     ifstream *aFile;
297     if (!theNamesOnly) { // mpv 15.01.2003: we don't open any file if theNamesOnly = true
298       TCollection_AsciiString aName(const_cast<char*>(aFiles[i+1].c_str()));
299       TCollection_AsciiString aFullPath = aTmpDir + aName;
300       OSD_Path anOSDPath(aFullPath);
301       OSD_File anOSDFile(anOSDPath);
302       if(!anOSDFile.Exists()) continue;
303 #ifdef WIN32
304       aFile = new ifstream(aFullPath.ToCString(), ios::binary);
305 #else
306       aFile = new ifstream(aFullPath.ToCString());
307 #endif
308     }
309     //Initialize 4 bytes of the buffer by 0
310     memset((theBuffer + aCurrentPos), 0, 4); 
311     //Copy the length of the file name to the buffer
312     memcpy((theBuffer + aCurrentPos), (aFileNameSize + i), ((sizeof(int) > 4) ? 4 : sizeof(int))); 
313     aCurrentPos += 4;
314
315     //Copy the file name to the buffer
316     char* aFName = const_cast<char*>(aFiles[i+1].c_str());
317     memcpy((theBuffer + aCurrentPos), aFName, aFileNameSize[i]);
318     aCurrentPos += aFileNameSize[i];
319     
320     if (!theNamesOnly) { // mpv 15.01.2003: we don't copy file content to the buffer if !theNamesOnly
321       //Initialize 8 bytes of the buffer by 0
322       memset((theBuffer + aCurrentPos), 0, 8); 
323       //Copy the length of the file to the buffer
324       memcpy((theBuffer + aCurrentPos), (aFileSize + i), ((sizeof(long) > 8) ? 8 : sizeof(long)));
325       aCurrentPos += 8;
326       
327       aFile->seekg(0, ios::beg);
328       aFile->read((char *)(theBuffer + aCurrentPos), aFileSize[i]);
329       aFile->close();
330       delete(aFile);
331       aCurrentPos += aFileSize[i];
332     }
333   }
334   delete[] aFileNameSize;
335   delete[] aFileSize;
336
337   theBufferSize = aBufferSize;
338 }
339
340 /*!
341   Converts a byte sequence <theBuffer> to files and return list of them
342 */
343 LightApp_Driver::ListOfFiles LightApp_Driver::PutStreamToFiles( const unsigned char* theBuffer,
344                                                                 const long theBufferSize, bool theNamesOnly )
345 {
346   if(theBufferSize == 0 || theBuffer == 0)
347     return   ListOfFiles();
348
349   // Create a temporary directory for the component's data files
350   std::string aDir = GetTmpDir();
351
352   // Remember that the files are in a temporary location that should be deleted
353   // when a study is closed
354   SetIsTemporary( true );
355
356   //Get a temporary directory for saving a file
357   TCollection_AsciiString aTmpDir(const_cast<char*>(aDir.c_str()));
358
359   long aFileSize, aCurrentPos = 4;
360   int i, aFileNameSize, aNbFiles = 0;
361
362   //Copy the number of files in the stream
363   memcpy(&aNbFiles, theBuffer, sizeof(int)); 
364
365   const int n = aNbFiles + 1;
366   ListOfFiles aFiles(n);
367   aFiles[0] = aDir;
368
369   for(i = 0; i < aNbFiles; i++) {
370     //Put a length of the file name to aFileNameSize
371     memcpy(&aFileNameSize, (theBuffer + aCurrentPos), ((sizeof(int) > 4) ? 4 : sizeof(int))); 
372     aCurrentPos += 4;
373
374     char *aFileName = new char[aFileNameSize];
375     //Put a file name to aFileName
376     memcpy(aFileName, (theBuffer + aCurrentPos), aFileNameSize); 
377     aCurrentPos += aFileNameSize;
378  
379     //Put a length of the file to aFileSize
380     if (!theNamesOnly) {
381       memcpy(&aFileSize, (theBuffer + aCurrentPos), ((sizeof(long) > 8) ? 8 : sizeof(long)));
382       aCurrentPos += 8;    
383       
384       TCollection_AsciiString aFullPath = aTmpDir + aFileName;
385       
386 #ifdef WIN32
387   ofstream aFile(aFullPath.ToCString(), ios::out | ios::binary);
388 #else
389   ofstream aFile(aFullPath.ToCString());
390 #endif
391
392       aFile.write((char *)(theBuffer+aCurrentPos), aFileSize); 
393       aFile.close();  
394       aCurrentPos += aFileSize;
395     }
396     std::string aStrFileName(aFileName);
397     aFiles[i+1] = aStrFileName;
398     delete[] aFileName;
399   }
400   return aFiles;
401 }
402
403 /*!
404   Remove files. First item in <theFiles> is a directory with slash at the end.
405   Other items are names of files. If <IsDirDeleted> is true,
406   then the directory is also deleted.
407 */
408 void LightApp_Driver::RemoveFiles( const ListOfFiles& theFiles, const bool IsDirDeleted)
409 {
410   int i, aLength = theFiles.size() - 1;
411   if(aLength <= 0) {
412     return;
413   }
414   //Get a temporary directory for saved a file
415   TCollection_AsciiString aDirName(const_cast<char*>(theFiles[0].c_str()));
416
417   for(i = 0; i < aLength; i++) {
418     TCollection_AsciiString aFile(aDirName);
419     aFile += const_cast<char*>(theFiles[i+1].c_str());
420     OSD_Path anOSDPath(aFile);
421     OSD_File anOSDFile(anOSDPath);
422     if(!anOSDFile.Exists()) continue;
423
424     anOSDFile.Remove();
425   }
426
427   if(IsDirDeleted) {
428     OSD_Path aPath(aDirName);
429     OSD_Directory aDir(aPath);
430     // san -- Using a special code block below is essential - it ensures that
431     // OSD_FileIterator instance is destroyed by the moment when
432     // OSD_Directory::Remove() is called.
433     // Otherwise, the directory remains locked (at least on Windows)
434     // by the iterator and cannot be removed.
435     {
436       OSD_FileIterator anIterator(aPath, '*');
437       if(!aDir.Exists() || anIterator.More())
438         return;
439     }
440     aDir.Remove();
441   }
442 }
443
444 /*!
445   Removes files which was created from module theModuleName if 
446   <IsDirDeleted> is true tmp directory is also deleted if it is empty
447 */
448 void LightApp_Driver::RemoveTemporaryFiles( const char* theModuleName, const bool IsDirDeleted )
449 {
450   std::string aModuleName(theModuleName);
451   ListOfFiles aFiles = myMap[aModuleName];
452   // aFiles must contain temporary directory name in its first item
453   // and names of files (relatively the temporary directory) in the others
454   RemoveFiles( aFiles, IsDirDeleted );
455
456 }
457
458 /*!
459   Clears map of list files
460 */ 
461 void LightApp_Driver::ClearDriverContents()
462 {
463   std::map<std::string, ListOfFiles>::iterator it;
464   for ( it = myMap.begin(); it != myMap.end(); ++it ) 
465   {
466     const char* aModuleName = const_cast<char*>(it->first.c_str());
467     // If the driver contains temporary files - 
468     // remove them along with the temporary directory
469     RemoveTemporaryFiles( aModuleName, IsTemporary() );
470   }
471   myMap.clear();  
472   // Reset the "temporary" flag
473   SetIsTemporary( false );
474 }
475
476 /*!
477   \return a temp directory to store created files like "/tmp/sub_dir/"
478 */
479 std::string LightApp_Driver::GetTmpDir()
480 {
481   if ( myTmpDir.length() != 0 )
482     return myTmpDir;
483
484   //Find a temporary directory to store a file
485   TCollection_AsciiString aTmpDir;
486
487   char *Tmp_dir = getenv("SALOME_TMP_DIR");
488   if ( !Tmp_dir )
489     Tmp_dir = getenv ( "TEMP" );
490   if ( !Tmp_dir )
491     Tmp_dir = getenv ( "TMP" );
492   if ( Tmp_dir ) 
493   {
494     aTmpDir = TCollection_AsciiString(Tmp_dir);
495 #ifdef WIN32
496     if(aTmpDir.Value(aTmpDir.Length()) != '\\') aTmpDir+='\\';
497 #else
498     if(aTmpDir.Value(aTmpDir.Length()) != '/') aTmpDir+='/';
499 #endif      
500   }
501   else 
502   {
503 #ifdef WIN32
504     aTmpDir = TCollection_AsciiString("C:\\");
505 #else
506     aTmpDir = TCollection_AsciiString("/tmp/");
507 #endif
508   }
509
510   srand((unsigned int)time(NULL));
511   int aRND = 999 + (int)(100000.0*rand()/(RAND_MAX+1.0)); //Get a random number to present a name of a sub directory
512   TCollection_AsciiString aSubDir(aRND);
513   if(aSubDir.Length() <= 1) aSubDir = TCollection_AsciiString("123409876");
514
515   aTmpDir += aSubDir; //Get RND sub directory
516
517 #ifdef WIN32
518   if(aTmpDir.Value(aTmpDir.Length()) != '\\') aTmpDir+='\\';
519 #else
520   if(aTmpDir.Value(aTmpDir.Length()) != '/') aTmpDir+='/';
521 #endif
522
523   OSD_Path aPath(aTmpDir);
524   OSD_Directory aDir(aPath);
525
526   for(aRND = 0; aDir.Exists(); aRND++) {
527     aTmpDir.Insert((aTmpDir.Length() - 1), TCollection_AsciiString(aRND));  //Build a unique directory name
528     aPath = OSD_Path(aTmpDir);
529     aDir = OSD_Directory(aPath);
530   }
531
532 #ifdef WIN32
533   // Workaround for OSD_Protection bug on Windows
534   OSD_Protection aProtection(OSD_RWXD, OSD_RWXD, OSD_RWXD, OSD_RWXD);
535 #else
536   OSD_Protection aProtection(OSD_RX, OSD_RWXD, OSD_RX, OSD_RX);
537 #endif
538   aDir.Build(aProtection);
539
540   myTmpDir = aTmpDir.ToCString();
541
542   return aTmpDir.ToCString();
543 }
544
545 /*!
546   \return the dir by the path
547 */
548 std::string LightApp_Driver::GetDirFromPath( const std::string& thePath ) {
549   if(thePath == "")
550     return "";
551   OSD_Path aPath = OSD_Path(TCollection_AsciiString(const_cast<char*>(thePath.c_str())));
552   TCollection_AsciiString aDirString(aPath.Trek());
553   aDirString.ChangeAll('|','/');
554   return aDirString.ToCString();
555 }
556