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