]> Creatis software - gdcm.git/blob - src/gdcmDirList.cxx
Fix bug in windows part
[gdcm.git] / src / gdcmDirList.cxx
1 /*=========================================================================
2                                                                                 
3   Program:   gdcm
4   Module:    $RCSfile: gdcmDirList.cxx,v $
5   Language:  C++
6   Date:      $Date: 2009/05/19 15:04:15 $
7   Version:   $Revision: 1.67 $
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);
167        b = FindNextFile(hFile, &fileData))
168    {
169       fileName = dirName + 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 (all)  // meaningfull only when recursive=false
175       {
176          Filenames.push_back( fileName );
177          numberOfFiles++;
178       }
179       else
180       {
181         if ( !( fileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ) )    //is it a regular file?
182         {
183            Filenames.push_back( fileName );
184            numberOfFiles++;
185
186         }
187         else if ( fileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ) //directory?
188         {
189            if ( GDCM_NAME_SPACE::Util::GetName(fileName)[0] != '.' && recursive ) //we also skip hidden files
190            {
191               numberOfFiles += Explore( fileName, recursive);
192            }
193         }
194         else
195         {
196            gdcmErrorMacro( "Unexpected error" );
197            return -1;
198         }
199      }
200    }
201
202    DWORD dwError = GetLastError();
203    if (hFile != INVALID_HANDLE_VALUE) 
204       FindClose(hFile);
205    if (dwError != ERROR_NO_MORE_FILES) 
206    {
207       LPVOID lpMsgBuf;
208       FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER|
209                     FORMAT_MESSAGE_FROM_SYSTEM|
210                     FORMAT_MESSAGE_IGNORE_INSERTS,
211                     NULL,GetLastError(),
212                     MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
213                     (LPTSTR) &lpMsgBuf,0,NULL);
214
215       gdcmErrorMacro("FindNextFile error. Error is " << (char *)lpMsgBuf
216                    <<" for the directory : "<<dirName);
217       return -1;
218    }
219
220 #else
221   // Real POSIX implementation: scandir is a BSD extension only, and doesn't 
222   // work on debian for example
223
224    DIR* dir = opendir(dirName.c_str());
225    if (!dir)
226    {
227       return 0;
228    }
229
230    // According to POSIX, the dirent structure contains a field char d_name[]
231    // of unspecified size, with at most NAME_MAX characters preceeding the
232    // terminating null character. Use of other fields will harm the  porta-
233    // bility of your programs.
234
235    struct stat buf;
236    dirent *d;
237    for (d = readdir(dir); d; d = readdir(dir))
238    {
239       fileName = dirName + d->d_name;
240       //std::cout << d->d_name << std::endl;
241       // avoid infinite loop!  
242       if ( GDCM_NAME_SPACE::Util::GetName(d->d_name) == "." || GDCM_NAME_SPACE::Util::GetName(d->d_name) == "..")
243          continue;      
244       
245       if( stat(fileName.c_str(), &buf) != 0 )
246       {
247          gdcmErrorMacro( strerror(errno) );
248       }
249       
250       if (all)  // meaningfull only when recursive=false
251       {
252          Filenames.push_back( fileName );
253          numberOfFiles++;      
254       }
255       else
256       {
257         if ( S_ISREG(buf.st_mode) )    //is it a regular file?
258         {
259            Filenames.push_back( fileName );
260            numberOfFiles++;
261         }
262         else if ( S_ISDIR(buf.st_mode) ) //directory?
263         {
264            if ( d->d_name[0] != '.' && recursive ) //we also skip hidden files
265            {
266               numberOfFiles += Explore( fileName, recursive);
267            }
268         }
269         else
270         {
271            gdcmErrorMacro( "Unexpected error" );
272            return -1;
273         }
274      }
275    }
276    
277    if( closedir(dir) != 0 )
278    {
279       gdcmErrorMacro( strerror(errno) );
280    }
281 #endif
282
283   return numberOfFiles;
284 }
285
286 //-----------------------------------------------------------------------------
287 // Print
288 /**
289  * \brief   Print method
290  * @param os ostream to write to 
291  */
292 void DirList::Print(std::ostream &os, std::string const &)
293 {
294    std::copy(Filenames.begin(), Filenames.end(), 
295              std::ostream_iterator<std::string>(os, "\n"));
296 }
297
298 //-----------------------------------------------------------------------------
299 } // end namespace gdcm