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