]> Creatis software - gdcm.git/blob - src/gdcmDirList.cxx
f9b7ecb18bfc0574486a3e91d788c86973646f29
[gdcm.git] / src / gdcmDirList.cxx
1 /*=========================================================================
2                                                                                 
3   Program:   gdcm
4   Module:    $RCSfile: gdcmDirList.cxx,v $
5   Language:  C++
6   Date:      $Date: 2008/02/13 18:53:33 $
7   Version:   $Revision: 1.65 $
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)
48 {
49    DirName = dirName;
50    Explore(dirName, recursive);
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  */
155 int DirList::Explore(std::string const &dirpath, bool recursive)
156 {
157    int numberOfFiles = 0;
158    std::string fileName;
159    std::string dirName = Util::NormalizePath(dirpath);
160 #ifdef _MSC_VER
161    WIN32_FIND_DATA fileData;
162    //assert( dirName[dirName.size()-1] == '' );
163    HANDLE hFile = FindFirstFile((dirName+"*").c_str(), &fileData);
164
165    for(BOOL b = (hFile != INVALID_HANDLE_VALUE); b;
166        b = FindNextFile(hFile, &fileData))
167    {
168       fileName = fileData.cFileName;
169       if ( fileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY )
170       {
171          // Need to check for . and .. to avoid infinite loop
172          if ( fileName != "." && fileName != ".." && recursive )
173          {
174             numberOfFiles += Explore(dirName+fileName,recursive);
175          }
176       }
177       else
178       {
179          Filenames.push_back(dirName+fileName);
180          numberOfFiles++;
181       }
182    }
183    DWORD dwError = GetLastError();
184    if (hFile != INVALID_HANDLE_VALUE) 
185       FindClose(hFile);
186    if (dwError != ERROR_NO_MORE_FILES) 
187    {
188       LPVOID lpMsgBuf;
189       FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER|
190                     FORMAT_MESSAGE_FROM_SYSTEM|
191                     FORMAT_MESSAGE_IGNORE_INSERTS,
192                     NULL,GetLastError(),
193                     MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
194                     (LPTSTR) &lpMsgBuf,0,NULL);
195
196       gdcmErrorMacro("FindNextFile error. Error is " << (char *)lpMsgBuf
197                    <<" for the directory : "<<dirName);
198       return -1;
199    }
200
201 #else
202   // Real POSIX implementation: scandir is a BSD extension only, and doesn't 
203   // work on debian for example
204
205    DIR* dir = opendir(dirName.c_str());
206    if (!dir)
207    {
208       return 0;
209    }
210
211    // According to POSIX, the dirent structure contains a field char d_name[]
212    // of unspecified size, with at most NAME_MAX characters preceeding the
213    // terminating null character. Use of other fields will harm the  porta-
214    // bility of your programs.
215
216    struct stat buf;
217    dirent *d;
218    for (d = readdir(dir); d; d = readdir(dir))
219    {
220       fileName = dirName + d->d_name;
221       if( stat(fileName.c_str(), &buf) != 0 )
222       {
223          gdcmErrorMacro( strerror(errno) );
224       }
225       if ( S_ISREG(buf.st_mode) )    //is it a regular file?
226       {
227          Filenames.push_back( fileName );
228          numberOfFiles++;
229       }
230       else if ( S_ISDIR(buf.st_mode) ) //directory?
231       {
232          if ( d->d_name[0] != '.' && recursive ) //we also skip hidden files
233          {
234             numberOfFiles += Explore( fileName, recursive);
235          }
236       }
237       else
238       {
239          gdcmErrorMacro( "Unexpected error" );
240          return -1;
241       }
242    }
243    if( closedir(dir) != 0 )
244    {
245       gdcmErrorMacro( strerror(errno) );
246    }
247 #endif
248
249   return numberOfFiles;
250 }
251
252 //-----------------------------------------------------------------------------
253 // Print
254 /**
255  * \brief   Print method
256  * @param os ostream to write to 
257  */
258 void DirList::Print(std::ostream &os, std::string const &)
259 {
260    std::copy(Filenames.begin(), Filenames.end(), 
261              std::ostream_iterator<std::string>(os, "\n"));
262 }
263
264 //-----------------------------------------------------------------------------
265 } // end namespace gdcm