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