]> Creatis software - gdcm.git/blob - src/gdcmDirList.cxx
18da29ffd4959cbab39eb60ec1ba51a4c0101f20
[gdcm.git] / src / gdcmDirList.cxx
1 /*=========================================================================
2                                                                                 
3   Program:   gdcm
4   Module:    $RCSfile: gdcmDirList.cxx,v $
5   Language:  C++
6   Date:      $Date: 2009/02/05 09:03:26 $
7   Version:   $Revision: 1.66 $
8                                                                                 
9   Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de
10   l'Image). All rights reserved. See Doc/License.txt or
11   http://www.creatis.insa-lyon.fr/Public/Gdcm/License.html for details.
12                                                                                 
13      This software is distributed WITHOUT ANY WARRANTY; without even
14      the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15      PURPOSE.  See the above copyright notices for more information.
16                                                                                 
17 =========================================================================*/
18
19 #include "gdcmDirList.h"
20 #include "gdcmUtil.h"
21 #include "gdcmDebug.h"
22
23 #include "gdcmDicomDirImage.h"
24
25 #include <iterator>
26 #include <assert.h>
27 #include <errno.h>
28 #include <sys/stat.h>  //stat function
29
30 #ifdef _MSC_VER
31    #include <windows.h>
32    #include <direct.h>
33 #else
34    #include <dirent.h>   
35    #include <sys/types.h>
36 #endif
37
38 namespace GDCM_NAME_SPACE
39 {
40 //-----------------------------------------------------------------------------
41 // Constructor / Destructor
42 /**
43  * \brief Constructor  
44  * @param  dirName root directory name
45  * @param  recursive whether we want to explore recursively or not 
46  */
47 DirList::DirList(std::string const &dirName, bool recursive, bool all)
48 {
49    DirName = dirName;
50    Explore(dirName, recursive, all);
51 }
52
53 /**
54  * \brief Constructor  
55  * @param  se DicomDirSerie we want to explore
56  */
57 DirList::DirList(DicomDirSerie *se)
58 {
59    Explore(se);
60 }
61 /**
62  * \brief  Destructor
63  */
64 DirList::~DirList()
65 {
66 }
67
68 //-----------------------------------------------------------------------------
69 // Public
70 /**
71  * \brief Tells us if file name corresponds to a Directory   
72  * @param  dirName file name to check
73  * @return true if the file IS a Directory
74  */
75 bool DirList::IsDirectory(std::string const &dirName)
76 {
77    struct stat fs;
78    // std::cout << "dirName[dirName.size()-1] [" << dirName[dirName.size()-1] << "]"
79    //           << std::endl;
80    //assert( dirName[dirName.size()-1] != GDCM_FILESEPARATOR );
81    if ( stat(dirName.c_str(), &fs) == 0 )
82    {
83 #if _WIN32
84       return ((fs.st_mode & _S_IFDIR) != 0);
85 #else
86       return S_ISDIR(fs.st_mode);
87 #endif
88    }
89    else
90    {
91       gdcmStaticWarningMacro("[" << dirName << "] not found or is not a Directory");
92       //gdcmStaticErrorMacro( strerror(errno) );
93       return false;
94    }
95 }
96
97 /**
98  * \brief   Get the first entry while visiting Filenames
99  * \return  The first  if found, otherwhise ""
100  */ 
101 std::string DirList::GetFirst()
102 {
103    ItDirList = Filenames.begin();
104    if (ItDirList != Filenames.end())
105       return *ItDirList;
106    return "";
107
108
109 /**
110  * \brief   Get the next entry while visiting Filenames
111  * \return  The next  if found, otherwhise ""
112  */ 
113 std::string DirList::GetNext()
114 {
115    gdcmAssertMacro (ItDirList != Filenames.end())
116    {
117       ++ItDirList;
118       if (ItDirList != Filenames.end())
119          return *ItDirList;      
120    }
121    return "";
122
123
124 //-----------------------------------------------------------------------------
125 // Protected
126
127 //-----------------------------------------------------------------------------
128 // Private
129
130 /**
131  * \brief   Explores a DicomDirSerie
132  *          return number of files found
133  * @param  se DicomDirSerie to explore
134  */
135 int DirList::Explore(DicomDirSerie *se)
136 {
137    int numberOfFiles = 0;
138
139    DicomDirImage *im = se->GetFirstImage();
140    while ( im ) 
141    { 
142       Filenames.push_back( im->GetEntryString(0x0004, 0x1500) );// File name (Referenced File ID)
143       numberOfFiles++;           
144       im = se->GetNextImage();   
145    }
146    return numberOfFiles;
147 }
148    
149 /**
150  * \brief   Explore a directory with possibility of recursion
151  *          return number of files read
152  * @param  dirpath   directory to explore
153  * @param  recursive whether we want recursion or not
154  * @param all whether we want all (i.e; File names + Directory names) default=false
155  */
156 int DirList::Explore(std::string const &dirpath, bool recursive, bool all)
157 {
158    int numberOfFiles = 0;
159    std::string fileName;
160    std::string dirName = Util::NormalizePath(dirpath);
161 #ifdef _MSC_VER
162    WIN32_FIND_DATA fileData;
163    //assert( dirName[dirName.size()-1] == '' );
164    HANDLE hFile = FindFirstFile((dirName+"*").c_str(), &fileData);
165
166    for(BOOL b = (hFile != INVALID_HANDLE_VALUE); b;
167        b = FindNextFile(hFile, &fileData))
168    {
169       fileName = fileData.cFileName;
170       // avoid infinite loop! 
171       if ( GDCM_NAME_SPACE::Util::GetName(fileName) == "." || GDCM_NAME_SPACE::Util::GetName(fileName) == "..")
172          continue;
173
174       if ( ( fileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ) || !all) ) 
175       // all : whe return ALL the names, no recursion
176       {
177          numberOfFiles += Explore(dirName+fileName,recursive);
178       }
179       else
180       {
181          Filenames.push_back(dirName+fileName);
182          numberOfFiles++;
183       }
184    }
185    DWORD dwError = GetLastError();
186    if (hFile != INVALID_HANDLE_VALUE) 
187       FindClose(hFile);
188    if (dwError != ERROR_NO_MORE_FILES) 
189    {
190       LPVOID lpMsgBuf;
191       FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER|
192                     FORMAT_MESSAGE_FROM_SYSTEM|
193                     FORMAT_MESSAGE_IGNORE_INSERTS,
194                     NULL,GetLastError(),
195                     MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
196                     (LPTSTR) &lpMsgBuf,0,NULL);
197
198       gdcmErrorMacro("FindNextFile error. Error is " << (char *)lpMsgBuf
199                    <<" for the directory : "<<dirName);
200       return -1;
201    }
202
203 #else
204   // Real POSIX implementation: scandir is a BSD extension only, and doesn't 
205   // work on debian for example
206
207    DIR* dir = opendir(dirName.c_str());
208    if (!dir)
209    {
210       return 0;
211    }
212
213    // According to POSIX, the dirent structure contains a field char d_name[]
214    // of unspecified size, with at most NAME_MAX characters preceeding the
215    // terminating null character. Use of other fields will harm the  porta-
216    // bility of your programs.
217
218    struct stat buf;
219    dirent *d;
220    for (d = readdir(dir); d; d = readdir(dir))
221    {
222       fileName = dirName + d->d_name;
223       //std::cout << d->d_name << std::endl;
224       // avoid infinite loop!  
225       if ( GDCM_NAME_SPACE::Util::GetName(d->d_name) == "." || GDCM_NAME_SPACE::Util::GetName(d->d_name) == "..")
226          continue;      
227       
228       if( stat(fileName.c_str(), &buf) != 0 )
229       {
230          gdcmErrorMacro( strerror(errno) );
231       }
232       
233       if (all)  // meaningfull only when recursive=false
234       {
235          Filenames.push_back( fileName );
236          numberOfFiles++;      
237       }
238       else
239       {
240         if ( S_ISREG(buf.st_mode) )    //is it a regular file?
241         {
242            Filenames.push_back( fileName );
243            numberOfFiles++;
244         }
245         else if ( S_ISDIR(buf.st_mode) ) //directory?
246         {
247            if ( d->d_name[0] != '.' && recursive ) //we also skip hidden files
248            {
249               numberOfFiles += Explore( fileName, recursive);
250            }
251         }
252         else
253         {
254            gdcmErrorMacro( "Unexpected error" );
255            return -1;
256         }
257      }
258    }
259    
260    if( closedir(dir) != 0 )
261    {
262       gdcmErrorMacro( strerror(errno) );
263    }
264 #endif
265
266   return numberOfFiles;
267 }
268
269 //-----------------------------------------------------------------------------
270 // Print
271 /**
272  * \brief   Print method
273  * @param os ostream to write to 
274  */
275 void DirList::Print(std::ostream &os, std::string const &)
276 {
277    std::copy(Filenames.begin(), Filenames.end(), 
278              std::ostream_iterator<std::string>(os, "\n"));
279 }
280
281 //-----------------------------------------------------------------------------
282 } // end namespace gdcm