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