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