]> Creatis software - gdcm.git/blob - src/gdcmDicomDir.cxx
* FIX : sort the images in the dicom dir
[gdcm.git] / src / gdcmDicomDir.cxx
1 // gdcmDicomDir.cxx
2 //-----------------------------------------------------------------------------
3 #include "gdcmDicomDir.h"
4 #include "gdcmStudy.h"
5 #include "gdcmSerie.h"
6 #include "gdcmImage.h"
7 #include "gdcmDirList.h"
8 #include "gdcmUtil.h"
9
10 #include <string>
11 #include <algorithm>
12
13 #include <sys/types.h>
14 #include <errno.h>
15
16 //-----------------------------------------------------------------------------
17 // Constructor / Destructor
18 /*
19  * \ingroup gdcmDicomDir
20  * \brief   
21  * @param   Filename
22  * @param   exception_on_error
23  */
24 gdcmDicomDir::gdcmDicomDir(const char *FileName, bool parseDir,
25                            bool exception_on_error):
26    gdcmParser(FileName,exception_on_error,true)
27 {
28    if( GetListEntry().begin()==GetListEntry().end() ) 
29    {
30       dbg.Verbose(0, "gdcmDicomDir::gdcmDicomDir : entry list empty");
31
32       if(parseDir)
33       {
34          dbg.Verbose(0, "gdcmDicomDir::gdcmDicomDir : Parse directory and create the DicomDir");
35          ParseDirectory();
36       }
37    }
38    else
39       CreateDicomDir();
40 }
41
42 /*
43  * \ingroup gdcmDicomDir
44  * \brief   
45  * @param   exception_on_error
46  */
47 /*gdcmDicomDir::gdcmDicomDir(ListTag *l,
48                            bool exception_on_error):                           
49    gdcmParser(exception_on_error )  
50 {    
51    listEntries=*l;
52    CreateDicomDir();
53 }*/
54
55 /*
56  * \ingroup gdcmDicomDir
57  * \brief  Canonical destructor 
58  */
59 gdcmDicomDir::~gdcmDicomDir() 
60 {
61    for(ListPatient::iterator cc=patients.begin();cc!=patients.end();++cc)
62    {
63       delete *cc;
64    }
65 }
66
67 //-----------------------------------------------------------------------------
68 // Print
69 void gdcmDicomDir::Print(std::ostream &os)
70 {
71    for(ListPatient::iterator cc=patients.begin();cc!=patients.end();++cc)
72    {
73      (*cc)->SetPrintLevel(printLevel);
74      (*cc)->Print(os);
75    }
76 }
77
78 //-----------------------------------------------------------------------------
79 // Public
80 /**
81  * \ingroup gdcmDicomDir
82  * \brief   writes on disc a DICOMDIR
83  * \ warning does NOT add the missing elements in the header :
84  * \         it's up to the user doing it !
85  * @param  fileName file to be written to 
86  * @return
87  */
88 bool gdcmDicomDir::Write(std::string fileName) 
89 {
90    FILE * fp1;
91
92    fp1=fopen(fileName.c_str(),"wb");
93    if(fp1==NULL) 
94    {
95       printf("Failed to open(write) File [%s] \n",fileName.c_str());
96       return(false);
97    }
98
99    char * filePreamble;
100    filePreamble=(char*)calloc(128,1);
101    fwrite(filePreamble,128,1,fp1);
102    fwrite("DICM",4,1,fp1);
103    free(filePreamble);
104
105    WriteEntries(fp1,DICOMDIR);
106
107    fclose(fp1);
108
109    return true;
110 }
111
112 void gdcmDicomDir::ParseDirectory(void)
113 {
114    NewDicomDir(GetPath());
115    CreateDicomDir();
116 }
117
118 //-----------------------------------------------------------------------------
119 // Protected
120 /*
121  * \ingroup gdcmDicomDir
122  * \brief   
123  * @param   
124  */
125 void gdcmDicomDir::NewDicomDir(std::string path)
126 {
127    gdcmDirList fileList(path,1);
128    ListHeader list;
129    gdcmHeader *header;
130
131    listEntries.clear();
132    patients.clear();
133
134    for(gdcmDirList::iterator it=fileList.begin(); 
135        it!=fileList.end(); ++it) 
136    {
137       header=new gdcmHeader(it->c_str());
138       if(header->IsReadable())
139          list.push_back(header);
140       else
141          delete header;
142    }
143
144    std::sort(list.begin(),list.end(),gdcmDicomDir::HeaderLessThan);
145
146    SetElements(path,list);
147 }
148
149 /*
150  * \ingroup gdcmDicomDir
151  * \brief   Get the dicom dir path
152  * @param   
153  */
154 std::string gdcmDicomDir::GetPath(void)
155 {
156    std::string path=GetFileName();
157
158    int pos1=path.rfind("/");
159    int pos2=path.rfind("\\");
160    if(pos1>pos2)
161       path.resize(pos1);
162    else
163       path.resize(pos2);
164
165    return(path);
166 }
167
168 //-----------------------------------------------------------------------------
169 // Private
170 /*
171  * \ingroup gdcmDicomDir
172  * \brief   
173  * @param   
174  */
175 void gdcmDicomDir::CreateDicomDir()
176 {
177    // The list is parsed. When a tag is found :
178    //  1 - we save the beginning iterator
179    //  2 - we continue to parse
180    //  3 - we find an other tag
181    //       + we create the object for the precedent tag
182    //       + loop to 1 -
183
184    gdcmDicomDirType type=gdcmDicomDir::GDCM_NONE;
185    ListTag::iterator begin;
186    ListTag::iterator end;
187
188    begin=listEntries.begin();
189    end=begin;
190    for(ListTag::iterator i=listEntries.begin();i !=listEntries.end();++i) 
191    {
192       std::string v=(*i)->GetValue();
193       if(v=="PATIENT ") 
194       {
195          end=i;
196          AddObjectToEnd(type,begin,end);
197
198          type=gdcmDicomDir::GDCM_PATIENT;
199          begin=end;
200       } 
201
202       if(v=="STUDY ")
203       {
204          end=i;
205          AddObjectToEnd(type,begin,end);
206
207          type=gdcmDicomDir::GDCM_STUDY;
208          begin=end;
209       }
210
211       if(v=="SERIES") 
212       {
213          end=i;
214          AddObjectToEnd(type,begin,end);
215
216          type=gdcmDicomDir::GDCM_SERIE;
217          begin=end;
218       }
219
220       if(v=="IMAGE ") 
221       {
222          end=i;
223          AddObjectToEnd(type,begin,end);
224
225          type=gdcmDicomDir::GDCM_IMAGE;
226          begin=end;
227       }
228    }
229
230    end=GetListEntry().end();
231    AddObjectToEnd(type,begin,end);
232 }
233 /*
234  * \ingroup gdcmDicomDir
235  * \brief   
236  * @param   
237  */
238 void gdcmDicomDir::AddObjectToEnd(gdcmDicomDirType type,ListTag::iterator begin,ListTag::iterator end)
239 {
240    if(begin==end)
241       return;
242
243    switch(type)
244    {
245       case gdcmDicomDir::GDCM_PATIENT:
246          AddPatientToEnd(begin,end);
247          break;
248       case gdcmDicomDir::GDCM_STUDY:
249          AddStudyToEnd(begin,end);
250          break;
251       case gdcmDicomDir::GDCM_SERIE:
252          AddSerieToEnd(begin,end);
253          break;
254       case gdcmDicomDir::GDCM_IMAGE:
255          AddImageToEnd(begin,end);
256          break;
257    }
258 }
259
260 /*
261  * \ingroup gdcmDicomDir
262  * \brief   
263  * @param   
264  */
265 void gdcmDicomDir::AddPatientToEnd(ListTag::iterator begin,ListTag::iterator end)
266 {
267    patients.push_back(new gdcmPatient(begin,end));
268 }
269
270 /*
271  * \ingroup gdcmDicomDir
272  * \brief   
273  * @param   
274  */
275  void gdcmDicomDir::AddStudyToEnd(ListTag::iterator begin,ListTag::iterator end)
276 {
277    if(patients.size()>0)
278    {
279       ListPatient::iterator itp=patients.end();
280       itp--;
281      (*itp)->AddStudy(new gdcmStudy(begin,end));
282    }
283 }
284 /*
285  * \ingroup gdcmDicomDir
286  * \brief   
287  * @param   
288  */
289 void gdcmDicomDir::AddSerieToEnd(ListTag::iterator begin,ListTag::iterator end)
290 {
291    if(patients.size()>0)
292    {
293       ListPatient::iterator itp=patients.end();
294       itp--;
295
296       if((*itp)->GetStudies().size()>0)
297       {
298          ListStudy::iterator itst=(*itp)->GetStudies().end();
299          itst--;
300         (*itst)->AddSerie(new gdcmSerie(begin,end));
301       }
302    }
303 }
304
305 /*
306  * \ingroup gdcmDicomDir
307  * \brief   
308  * @param   
309  */
310  void gdcmDicomDir::AddImageToEnd(ListTag::iterator begin,ListTag::iterator end)
311 {
312    if(patients.size()>0)
313    {
314       ListPatient::iterator itp=patients.end();
315       itp--;
316
317       if((*itp)->GetStudies().size()>0)
318       {
319          ListStudy::iterator itst=(*itp)->GetStudies().end();
320          itst--;
321
322          if((*itst)->GetSeries().size()>0)
323          {
324             ListSerie::iterator its=(*itst)->GetSeries().end();
325             its--;
326            (*its)->AddImage(new gdcmImage(begin,end));
327          }
328       }
329    }
330 }
331
332 /*
333  * \ingroup gdcmDicomDir
334  * \brief   
335  * @param   
336  */
337 void gdcmDicomDir::SetElements(std::string &path,ListHeader &list)
338 {
339    std::string patPrevName="", patPrevID="";
340    std::string studPrevInstanceUID="", studPrevID="";
341    std::string serPrevInstanceUID="", serPrevID="";
342
343    std::string patCurName, patCurID;
344    std::string studCurInstanceUID, studCurID;
345    std::string serCurInstanceUID, serCurID;
346
347    SetElement(path,GDCM_NONE,NULL);
348
349    ListTag::iterator debPat=listEntries.begin();
350    for(ListHeader::iterator it=list.begin();it!=list.end();++it) 
351    {
352       // get the current file characteristics
353       patCurName=(*it)->GetEntryByNumber(0x0010,0x0010); 
354       patCurID=(*it)->GetEntryByNumber(0x0010,0x0011); 
355       studCurInstanceUID=(*it)->GetEntryByNumber(0x0020,0x000d);            
356       studCurID=(*it)->GetEntryByNumber(0x0020,0x0010);            
357       serCurInstanceUID=(*it)->GetEntryByNumber(0x0020,0x000e);            
358       serCurID=(*it)->GetEntryByNumber(0x0020,0x0011);
359
360       if(patCurName!=patPrevName || patCurID!=patPrevID) 
361          SetElement(path,GDCM_PATIENT,*it);
362
363       // if new Study Deal with 'STUDY' Elements   
364       if(studCurInstanceUID!=studPrevInstanceUID || studCurID!=studPrevID) 
365          SetElement(path,GDCM_STUDY,*it);
366
367       // if new Serie Deal with 'SERIE' Elements   
368       if(serCurInstanceUID!=serPrevInstanceUID || serCurID!=serPrevID) 
369       {
370          SetElement(path,GDCM_SERIE,*it);
371       } 
372       
373       // Always Deal with 'IMAGE' Elements  
374       SetElement(path,GDCM_IMAGE,*it);
375
376       patPrevName=patCurName;
377       patPrevID=patCurID;
378       studPrevInstanceUID=studCurInstanceUID;
379       studPrevID=studCurID;
380       serPrevInstanceUID=serCurInstanceUID;
381       serPrevID=serCurID;
382    }
383 }
384
385 /*
386  * \ingroup gdcmDicomDir
387  * \brief   
388  * @param   
389  */
390 void gdcmDicomDir::SetElement(std::string &path,gdcmDicomDirType type,gdcmHeader *header)
391 {
392    std::list<gdcmElement> elemList;
393    std::list<gdcmElement>::iterator it;
394    guint16 tmpGr, tmpEl;
395    gdcmDictEntry *dictEntry;
396    gdcmHeaderEntry *entry;
397    std::string val;
398
399    switch(type)
400    {
401       case GDCM_PATIENT:
402          elemList=gdcmGlobal::GetDicomDirElements()->GetPatientElements();
403          break;
404       case GDCM_STUDY:
405          elemList=gdcmGlobal::GetDicomDirElements()->GetStudyElements();
406          break;
407       case GDCM_SERIE:
408          elemList=gdcmGlobal::GetDicomDirElements()->GetSerieElements();
409          break;
410       case GDCM_IMAGE:
411          elemList=gdcmGlobal::GetDicomDirElements()->GetImageElements();
412          break;
413       case GDCM_NONE:
414          elemList=gdcmGlobal::GetDicomDirElements()->GetMetaElements();
415          break;
416       default:
417          return;
418    }
419
420    for(it=elemList.begin();it!=elemList.end();++it)
421    {
422       tmpGr=it->group;
423       tmpEl=it->elem;
424
425       dictEntry=GetPubDict()->GetDictEntryByNumber(tmpGr,tmpEl);
426       entry=new gdcmHeaderEntry(dictEntry);
427       entry->SetOffset(0); // just to avoid missprinting
428
429       if(header)
430          val=header->GetEntryByNumber(tmpGr,tmpEl);
431       else
432          val=GDCM_UNFOUND;
433
434       if(val==GDCM_UNFOUND) 
435       {
436          if((tmpGr==0x0004) &&(tmpEl==0x1130) )
437          {
438             // TODO force the *end* File Name(remove path)
439             val=path;
440          }
441          else if( (tmpGr==0x0004) && (tmpEl==0x1500) ) // Only used for image
442          {
443             if(header->GetFileName().substr(0,path.length())!=path)
444             {
445                dbg.Verbose(0, "gdcmDicomDir::SetElement : the base path of file name is incorrect");
446                val=header->GetFileName();
447             }
448             else
449                val=&(header->GetFileName()[path.length()]);
450          }
451          else
452          {
453             val=it->value;
454          }
455       }
456       entry->SetValue(val);
457
458       if(dictEntry)
459       {
460          if( (dictEntry->GetVR()=="UL") || (dictEntry->GetVR()=="SL") ) 
461          {
462             entry->SetLength(4);
463          } 
464          else if( (dictEntry->GetVR()=="US") || (dictEntry->GetVR()=="SS") ) 
465          {
466             entry->SetLength(2); 
467          } 
468          else if(dictEntry->GetVR()=="SQ") 
469          {
470             entry->SetLength(0xffffffff);
471          }
472          else
473          {
474             entry->SetLength(entry->GetValue().length());        
475          }
476       }
477
478       listEntries.push_back(entry);
479    }     
480 }
481
482 bool gdcmDicomDir::HeaderLessThan(gdcmHeader *header1,gdcmHeader *header2)
483 {
484    return(*header1<*header2);
485 }
486
487 //-----------------------------------------------------------------------------