]> Creatis software - bbtk.git/blob - packages/std/src/bbstdFilesFromDirectory.cxx
#3247 BBTK Feature New Normal - FilesFromDirectory RecursiveLevel
[bbtk.git] / packages / std / src / bbstdFilesFromDirectory.cxx
1 /*
2  # ---------------------------------------------------------------------
3  #
4  # Copyright (c) CREATIS (Centre de Recherche en Acquisition et Traitement de l'Image
5  #                        pour la SantÈ)
6  # Authors : Eduardo Davila, Frederic Cervenansky, Claire Mouton
7  # Previous Authors : Laurent Guigues, Jean-Pierre Roux
8  # CreaTools website : www.creatis.insa-lyon.fr/site/fr/creatools_accueil
9  #
10  #  This software is governed by the CeCILL-B license under French law and
11  #  abiding by the rules of distribution of free software. You can  use,
12  #  modify and/ or redistribute the software under the terms of the CeCILL-B
13  #  license as circulated by CEA, CNRS and INRIA at the following URL
14  #  http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.html
15  #  or in the file LICENSE.txt.
16  #
17  #  As a counterpart to the access to the source code and  rights to copy,
18  #  modify and redistribute granted by the license, users are provided only
19  #  with a limited warranty  and the software's author,  the holder of the
20  #  economic rights,  and the successive licensors  have only  limited
21  #  liability.
22  #
23  #  The fact that you are presently reading this means that you have had
24  #  knowledge of the CeCILL-B license and that you accept its terms.
25  # ------------------------------------------------------------------------ */
26
27
28 #include "bbstdFilesFromDirectory.h"
29 #include "bbstdPackage.h"
30 #include <string>
31
32 #ifdef _MSC_VER
33    #include <windows.h>
34    #include <direct.h>
35 #else
36    #include <dirent.h>   
37    #include <sys/types.h>
38 #endif
39
40 #include <sys/stat.h>  //stat function
41
42 namespace bbstd
43 {
44
45 BBTK_ADD_BLACK_BOX_TO_PACKAGE(std,FilesFromDirectory)
46 BBTK_BLACK_BOX_IMPLEMENTATION(FilesFromDirectory,bbtk::AtomicBlackBox);
47
48 void FilesFromDirectory::Process()
49 {
50         Filenames.clear();
51         SimpleFilenames.clear();
52         DirName         = bbGetInputIn();
53         /*int nbFiles = */ Explore(DirName, bbGetInputRecursive(), bbGetInputRecursiveLevel() );
54         CleanFilenames( DirName );
55         bbSetOutputOut(Filenames);   
56         bbSetOutputOutSimple(SimpleFilenames);   
57 }
58
59 void FilesFromDirectory::bbUserSetDefaultValues()
60 {
61     bbSetInputIn(".");
62     bbSetInputRecursive(false);  
63     bbSetInputType(0);  
64     bbSetInputRecursiveLevel(999);  
65 }
66
67 void FilesFromDirectory::bbUserInitializeProcessing() 
68
69 }
70
71 void FilesFromDirectory::bbUserFinalizeProcessing() 
72 {
73 }
74   
75 /**
76  * \brief   Add a SEPARATOR to the end of the name if necessary
77  * @param   pathname file/directory name to normalize 
78  */
79 std::string FilesFromDirectory::NormalizePath(std::string const &pathname)
80 {
81 #ifdef _WIN32
82    const char FILESEPARATOR = '\\';
83 #else
84    const char FILESEPARATOR = '/';
85 #endif
86
87    std::string name = pathname;
88    int size = name.size();
89
90    if (!((name[size-1]=='/')||(name[size-1]=='\\')))
91    {
92       name += FILESEPARATOR;
93    }
94    return name;
95
96
97 /**
98  * \brief   Explores a directory with possibility of recursion
99  *          return number of files read
100  * @param  dirpath   directory to explore
101  * @param  recursive whether we want recursion or not
102  */
103
104
105
106 int FilesFromDirectory::Explore(std::string const &dirpath, bool recursive, int recursiveLevel)
107 {
108         int             numberOfFiles           = 0;
109
110 if (recursiveLevel>=0){
111
112         std::string dirName                     = NormalizePath(dirpath);
113         int             tmpNumberOfFiles;
114         std::string fileName;
115 #ifdef _MSC_VER
116         WIN32_FIND_DATA fileData;
117         //assert( dirName[dirName.size()-1] == '' );
118         HANDLE hFile = FindFirstFile((dirName+"*").c_str(), &fileData);
119
120         for(BOOL b = (hFile != INVALID_HANDLE_VALUE); b;
121        b = FindNextFile(hFile, &fileData))
122         {
123       fileName = fileData.cFileName;
124       if ( fileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY )
125       {
126          // Need to check for . and .. to avoid infinite loop
127          if ( fileName != "." && fileName != ".." && recursive )
128          {
129                         if (bbGetInputType()==1)
130                         {
131                         std::string temp = dirName+fileName;
132                         Filenames.push_back(temp);       
133                         numberOfFiles++;
134                         } // Type ALL_directories
135
136                         tmpNumberOfFiles        =       Explore(dirName+fileName, recursive,recursiveLevel-1);
137                         if ((bbGetInputType()==2)&&tmpNumberOfFiles==0)
138                         {
139                         std::string temp = dirName+fileName;
140                         Filenames.push_back(temp);       
141                         numberOfFiles++;
142                         } // Type Lsast_directories
143                         
144                         numberOfFiles           =       numberOfFiles + tmpNumberOfFiles;
145          } // if recursive
146          if ( fileName != "." && fileName != ".." && !recursive )
147                  {
148                         if ((bbGetInputType()==1) || (bbGetInputType()==2))
149                         {
150                         std::string temp = dirName+fileName;
151                         Filenames.push_back(temp);       
152                         numberOfFiles++;
153                         } // Type All_directories
154                 }// fileName && !recursive
155       } else  {
156 //      std::string temp = "\"" +dirName+fileName + "\"";
157         std::string temp = dirName+fileName;
158
159 /*
160         std::string::size_type spacePosition = temp.find_first_of(' ');
161                 if (spacePosition != std::string::npos) 
162                 {
163                         std::cout << "=========================================== File name : [" <<temp << 
164               "] contains space(s); Discarted !" << std::endl;
165                 temp.insert(spacePosition, "\\");
166                         continue;  /// \TODO : fix the trouble (vtk?)
167                 } // if !npos
168 */
169
170
171                 if (bbGetInputType()==0)
172                 {
173                         Filenames.push_back(temp);       
174                         numberOfFiles++;
175                 } // Type files
176
177       } // if !directory
178         } // for
179         DWORD dwError = GetLastError();
180         if (hFile != INVALID_HANDLE_VALUE) 
181         {
182                 FindClose(hFile);
183         }// hFile
184         if (dwError != ERROR_NO_MORE_FILES) 
185         {
186       LPVOID lpMsgBuf;
187       FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER|
188                     FORMAT_MESSAGE_FROM_SYSTEM|
189                     FORMAT_MESSAGE_IGNORE_INSERTS,
190                     NULL,GetLastError(),
191                     MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
192                     (LPTSTR) &lpMsgBuf,0,NULL);
193
194       //gdcmErrorMacro("FindNextFile error. Error is " << (char *)lpMsgBuf
195       //             <<" for the directory : "<<dirName);
196       return -1;
197         } // dwError
198
199 #else
200   // Real POSIX implementation: scandir is a BSD extension only, and doesn't 
201   // work on debian for example
202
203         DIR* dir = opendir( dirName.c_str() );
204         if (!dir)
205         {
206                 return 0;
207         }
208
209    // According to POSIX, the dirent structure contains a field char d_name[]
210    // of unspecified size, with at most NAME_MAX characters preceeding the
211    // terminating null character. Use of other fields will harm the  porta-
212    // bility of your programs.
213
214         struct stat     buf;
215         dirent                  *d;
216         for (d = readdir(dir); d; d = readdir(dir))
217         {
218         fileName = dirName + d->d_name;
219         std::string temp = fileName;
220         if( stat(fileName.c_str(), &buf) != 0 )
221         {
222                  //gdcmErrorMacro( strerror(errno) );
223         } // stat
224         if ( S_ISREG(buf.st_mode) )    //is it a regular file?
225         {
226                 if ( d->d_name[0]!='.')
227                 {
228
229 /*
230                         std::string::size_type  spacePosition = temp.find_first_of(' ');
231                 if (spacePosition != std::string::npos)
232                         {
233                                         std::cout << "=========================================== File name : [" <<temp << 
234                                 "] contains space(s); Discarted !" << std::endl;
235                         temp.insert(spacePosition, "\\");
236                                         continue;   /// \TODO : fix the trouble (vtk?)
237                 } // if spacePosition
238 */
239
240                                 if (bbGetInputType()==0)
241                                 {
242                         Filenames.push_back(temp);       
243                                 numberOfFiles++;
244                                 } // Type files
245                 } // d_name
246         } else if ( S_ISDIR(buf.st_mode) ) {  //directory?
247                 if ( (d->d_name[0]!='.') && recursive ) //we also skip hidden files
248                 {
249                                 if (bbGetInputType()==1)
250                                 {
251                         Filenames.push_back(fileName);   
252                                 numberOfFiles++;
253                                 } // Type All_directories
254
255                                 tmpNumberOfFiles        = Explore( fileName, recursive, recursiveLevel-1);
256                                 if ((bbGetInputType()==2)&&tmpNumberOfFiles==0)
257                                 {
258                                         Filenames.push_back(fileName);   
259                                 numberOfFiles++;
260                                 } // Type Lsast_directories
261                         numberOfFiles           = numberOfFiles+tmpNumberOfFiles;
262                 }// d_name && recursive
263                 if ( (d->d_name[0]!='.') && !recursive ) { //we also skip hidden files
264                                 if ((bbGetInputType()==1) || (bbGetInputType()==2))
265                                 {
266                         Filenames.push_back(fileName);   
267                                 numberOfFiles++;
268                                 } // Type All_directories
269                         
270                         }// d_name && !recursive
271
272                 } else {
273                 //gdcmErrorMacro( "Unexpected error" );
274                 return -1;
275         } // Regular FILE
276    }
277    if( closedir(dir) != 0 )
278    {
279       //gdcmErrorMacro( strerror(errno) );
280    }// closedir
281 #endif
282
283 } // if recursiveLevel 
284
285         return numberOfFiles;
286 }
287
288
289 //------------------------------------------------------------------------------
290 void FilesFromDirectory::CleanFilenames( std::string basePath )
291 {
292         std::string tmpString;
293         int i,ii,sizeFilenames = Filenames.size();
294         int j,sizeFileEnd = bbGetInputFileEnd().size();
295
296         int okEraseElement;
297         
298 //Selecting just the files in the FileEnd List
299         if (bbGetInputFileEnd().size()!=0)
300         {
301                 for (i=sizeFilenames-1; i>=0; i--)
302                 {
303                         okEraseElement=0;
304                         for (j=0; j<sizeFileEnd; j++)
305                         {
306                                 std::string tmp=Filenames[i].substr( (Filenames[i].length()) - (bbGetInputFileEnd()[j]).length() ) ;
307                                 if (bbGetInputFileEnd()[j].compare( tmp )==0 )
308                                 {
309                                         okEraseElement++;
310                                 } // if FileEnd
311                         } // for j                                      
312
313                         if (okEraseElement==0) 
314                         { 
315                                 Filenames.erase( Filenames.begin()+i );
316                         }
317                 } // for i      
318         } // if FileEnd !=0
319
320         sizeFilenames = Filenames.size();
321
322 // Cleanning paths with spaces  
323         for (i=0; i<sizeFilenames; i++)
324         {
325                 tmpString=Filenames[i];
326
327                 std::string::size_type  spacePosition = tmpString.find_first_of(' ');
328                 if (spacePosition != std::string::npos)
329                 {
330                         std::cout << "=========================================== File name : [" <<tmpString << 
331                 "] contains space(s); Discarted !" << std::endl;
332                         tmpString.insert(spacePosition, "\\");
333                         Filenames[i]=tmpString;
334 //                      continue;   /// \TODO : fix the trouble (vtk?)
335                 } // if spacePosition
336         }
337
338
339 // Alphabetical order   
340         for (i=0; i<sizeFilenames; i++)
341         {
342         for (ii=i; ii<sizeFilenames; ii++)
343                 {
344                         if (Filenames[i]>Filenames[ii]) 
345                 {
346                         tmpString=Filenames[i];
347                         Filenames[i]=Filenames[ii];
348                         Filenames[ii]=tmpString;
349                 } // if 
350         } // for ii
351         } // for i
352
353 // Creating SimpleFilenames
354         unsigned int lenghtBasePath = basePath.length();
355         for (i=0; i<sizeFilenames; i++)
356         {
357                 SimpleFilenames.push_back( Filenames[i].substr( lenghtBasePath ) );
358         } // for i
359
360 }
361
362
363
364
365 /*
366
367 int FilesFromDirectory::Explore(std::string const &dirpath, bool recursive)
368 {
369    Filenames.clear();
370    int numberOfFiles = 0;
371    std::string fileName;
372    std::string dirName = NormalizePath(dirpath);
373 #ifdef _MSC_VER
374    WIN32_FIND_DATA fileData;
375    //assert( dirName[dirName.size()-1] == '' );
376    HANDLE hFile = FindFirstFile((dirName+"*").c_str(), &fileData);
377
378    for(BOOL b = (hFile != INVALID_HANDLE_VALUE); b;
379        b = FindNextFile(hFile, &fileData))
380    {
381       fileName = fileData.cFileName;
382       if ( fileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY )
383       {
384          // Need to check for . and .. to avoid infinite loop
385          if ( fileName != "." && fileName != ".." && recursive )
386          {
387             numberOfFiles += Explore(dirName+fileName, recursive);
388          }
389       }
390       else
391       {
392 //         std::string temp = "\"" +dirName+fileName + "\"";
393          std::string temp = dirName+fileName;
394          std::string::size_type spacePosition = temp.find_first_of(' ');
395                  if (spacePosition != std::string::npos) 
396          {
397    std::cout << "=========================================== File name : [" <<temp << 
398               "] contains space(s); Discarted !" << std::endl;
399             temp.insert(spacePosition, "\\");
400    continue;  /// \TODO : fix the trouble (vtk?)
401          }      
402          Filenames.push_back(temp);
403          numberOfFiles++;
404       }
405    }
406    DWORD dwError = GetLastError();
407    if (hFile != INVALID_HANDLE_VALUE) 
408       FindClose(hFile);
409    if (dwError != ERROR_NO_MORE_FILES) 
410    {
411       LPVOID lpMsgBuf;
412       FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER|
413                     FORMAT_MESSAGE_FROM_SYSTEM|
414                     FORMAT_MESSAGE_IGNORE_INSERTS,
415                     NULL,GetLastError(),
416                     MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
417                     (LPTSTR) &lpMsgBuf,0,NULL);
418
419       //gdcmErrorMacro("FindNextFile error. Error is " << (char *)lpMsgBuf
420       //             <<" for the directory : "<<dirName);
421       return -1;
422    }
423
424 #else
425   // Real POSIX implementation: scandir is a BSD extension only, and doesn't 
426   // work on debian for example
427
428    DIR* dir = opendir(dirName.c_str());
429    if (!dir)
430    {
431       return 0;
432    }
433
434    // According to POSIX, the dirent structure contains a field char d_name[]
435    // of unspecified size, with at most NAME_MAX characters preceeding the
436    // terminating null character. Use of other fields will harm the  porta-
437    // bility of your programs.
438
439    struct stat buf;
440    dirent *d;
441    for (d = readdir(dir); d; d = readdir(dir))
442    {
443       fileName = dirName + d->d_name;
444       std::string temp = fileName;
445       if( stat(fileName.c_str(), &buf) != 0 )
446       {
447          //gdcmErrorMacro( strerror(errno) );
448       }
449       if ( S_ISREG(buf.st_mode) )    //is it a regular file?
450       {
451          if ( d->d_name[0]!='.')
452          {
453          
454              std::string::size_type  spacePosition = temp.find_first_of(' ');
455              if (spacePosition != std::string::npos)
456              {
457    std::cout << "=========================================== File name : [" <<temp << 
458               "] contains space(s); Discarted !" << std::endl;
459                  temp.insert(spacePosition, "\\");
460    continue;   /// \TODO : fix the trouble (vtk?)
461              }
462              Filenames.push_back(temp);  
463              numberOfFiles++;
464          }
465       }
466       else if ( S_ISDIR(buf.st_mode) ) //directory?
467       {
468          if ( d->d_name[0] != '.' && recursive ) //we also skip hidden files
469          {
470             numberOfFiles += Explore( fileName, recursive);
471          }
472       }
473       else
474       {
475          //gdcmErrorMacro( "Unexpected error" );
476          return -1;
477       }
478    }
479    if( closedir(dir) != 0 )
480    {
481       //gdcmErrorMacro( strerror(errno) );
482    }
483 #endif
484
485   std::string tmpString;
486   int i,ii,sizeFilenames = Filenames.size();
487   for (i=0; i<sizeFilenames; i++)
488   {
489     for (ii=i; ii<sizeFilenames; ii++)
490     {
491         if (Filenames[i]>Filenames[ii]) 
492         {
493           tmpString=Filenames[i];
494           Filenames[i]=Filenames[ii];
495           Filenames[ii]=tmpString;
496         } // if 
497     } // for ii
498   } // for i
499
500   return numberOfFiles;
501 }
502 */
503
504 }
505 // EO namespace bbstd
506
507