fw4spl
fwDcmtkIO/src/fwDcmtkIO/helper/DicomDir.cpp
1 /* ***** BEGIN LICENSE BLOCK *****
2  * FW4SPL - Copyright (C) IRCAD, 2009-2016.
3  * Distributed under the terms of the GNU Lesser General Public License (LGPL) as
4  * published by the Free Software Foundation.
5  * ****** END LICENSE BLOCK ****** */
6 
7 #include <dcmtk/config/osconfig.h>
8 
9 #include "fwDcmtkIO/helper/DicomDir.hpp"
10 
11 #include <fwCore/exceptionmacros.hpp>
12 #include <fwCore/spyLog.hpp>
13 
14 #include <fwDcmtkTools/Dictionary.hpp>
15 
16 #include <boost/algorithm/string/classification.hpp>
17 #include <boost/algorithm/string/regex.hpp>
18 #include <boost/algorithm/string/split.hpp>
19 #include <boost/filesystem/operations.hpp>
20 #include <boost/regex.h>
21 
22 #include <dcmtk/dcmdata/dcdeftag.h>
23 #include <dcmtk/dcmdata/dcdicdir.h>
24 #include <dcmtk/dcmnet/diutil.h>
25 
26 namespace fwDcmtkIO
27 {
28 namespace helper
29 {
30 
31 bool DicomDir::readDicomDir(const ::boost::filesystem::path& root, std::vector<std::string>& dicomFiles)
32 {
33  SLM_ASSERT("You must specify a valid directory.", ::boost::filesystem::is_directory(root));
34 
35  //Load dictionary
37 
38  bool result = false;
39 
40  ::boost::filesystem::path dicomDirPath = root / "dicomdir";
41  bool dicomdirExists = ::boost::filesystem::exists(dicomDirPath) && !::boost::filesystem::is_directory(dicomDirPath);
42 
43  if(!dicomdirExists)
44  {
45  dicomDirPath = root / "DICOMDIR";
46  dicomdirExists = ::boost::filesystem::exists(dicomDirPath) && !::boost::filesystem::is_directory(dicomDirPath);
47  }
48 
49  if(dicomdirExists)
50  {
51  DcmDicomDir dicomDir(dicomDirPath.string().c_str());
52  DcmDirectoryRecord* rootRecord = &(dicomDir.getRootRecord());
53  DcmDirectoryRecord* patientRecord = NULL;
54  DcmDirectoryRecord* studyRecord = NULL;
55  DcmDirectoryRecord* seriesRecord = NULL;
56  DcmDirectoryRecord* fileRecord = NULL;
57  OFString tmpString;
58 
59  //Root level
60  if (rootRecord != NULL)
61  {
62  result = true;
63 
64  try
65  {
66  //Patient level
67  while (((patientRecord = rootRecord->nextSub(patientRecord)) != NULL))
68  {
69  //Study level
70  while (((studyRecord = patientRecord->nextSub(studyRecord)) != NULL))
71  {
72  //Series level
73  while (((seriesRecord = studyRecord->nextSub(seriesRecord)) != NULL))
74  {
75  //Instance level
76  while ((fileRecord = seriesRecord->nextSub(fileRecord)) != NULL)
77  {
78  if (fileRecord->findAndGetOFStringArray(DCM_ReferencedFileID, tmpString).good())
79  {
80  ::boost::filesystem::path realPath = DicomDir::getRealFilename(root,
81  tmpString.c_str());
82  dicomFiles.push_back(realPath.string());
83  }
84  else
85  {
86  SLM_WARN("Dicom instance doesn't have a referenced file id.");
87  }
88  }
89  }
90  }
91  }
92  }
93  catch(std::exception e)
94  {
95  result = false;
96  dicomFiles.clear();
97  }
98  }
99  else
100  {
101  SLM_WARN("Root record is null, unable to get information from dicomdir file.");
102  }
103 
104  }
105  else
106  {
107  SLM_WARN("Dicomdir file is missing");
108  }
109 
110  return result;
111 }
112 
113 // ----------------------------------------------------------------------------
114 
115 std::string DicomDir::createRegex(std::string filename)
116 {
117  std::string regex = "";
118  for(std::string::iterator it = filename.begin(); it != filename.end(); ++it)
119  {
120  char upper = *it;
121  char lower = static_cast<char>(upper + 32);
122 
123  std::stringstream ss;
124 
125  //For uppercase characters allow lowercase version
126  if(upper >= 'A' && upper <= 'Z')
127  {
128  ss << "[" << upper << lower << "]";
129  regex += ss.str();
130  }
131  //For other characters just copy them
132  else
133  {
134  ss << upper;
135  regex += ss.str();
136  }
137  }
138 
139  return regex;
140 }
141 
142 // ----------------------------------------------------------------------------
143 
144 ::boost::filesystem::path DicomDir::getRealFilename(
145  const ::boost::filesystem::path& root, const std::string& filename)
146 {
147  ::boost::filesystem::path result = root;
148  std::vector<std::string> elements;
149  ::boost::split(elements, filename, ::boost::is_any_of("/\\"));
150 
151  //For every part of the path (going through the hierarchy)
152  for(std::vector<std::string>::iterator it = elements.begin(); it != elements.end(); ++it)
153  {
154  std::string current = *it;
155  ::boost::regex regex(DicomDir::createRegex(current));
156 
157  ::boost::filesystem::directory_iterator dirIt(result), dirItEnd;
158  std::string child;
159  bool matchFound = false;
160 
161  //Check if a file in the directory matches the regex of the dicom path
162  for (; dirIt != dirItEnd; ++dirIt)
163  {
164  child = dirIt->path().filename().string();
165  if (::boost::regex_match(child, regex))
166  {
167  FW_RAISE_IF("There is more than one file matching the uppercase filename stored "
168  "in the dicom instance: \""+filename+"\"", matchFound);
169  matchFound = true;
170  result /= child;
171  }
172 
173  }
174 
175  FW_RAISE_IF("There is no file matching the uppercase filename stored in the dicom instance: \""+filename+"\"",
176  !matchFound);
177  }
178 
179 
180  return result;
181 }
182 
183 } //helper
184 } //fwDcmtkIO
static FWDCMTKTOOLS_API void loadDictionary()
Load the DICOM dictionary.
Definition: Dictionary.cpp:25
static FWDCMTKIO_API bool readDicomDir(const ::boost::filesystem::path &root, std::vector< std::string > &dicomFiles)
Find Dicom instances in a DicomDir file.
#define SLM_WARN(message)
Definition: spyLog.hpp:261
#define SLM_ASSERT(message, cond)
work like &#39;assert&#39; from &#39;cassert&#39;, with in addition a message logged by spylog (with FATAL loglevel) ...
Definition: spyLog.hpp:308
fwDcmtkIO contains classes used to pull Dicom images from a pacs using dcmtk library.
Definition: Codec.hpp:12
This file defines SpyLog macros. These macros are used to log messages to a file or to the console du...