]> Creatis software - gdcm.git/blob - src/gdcmDicomDir.cxx
Ops! The last Meta tag was missing
[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=begin;j !=listEntries.end();++j) 
206    {
207       if((*j)->GetValue()=="PATIENT ") {
208          k = j; 
209          break;
210       }
211    }   
212    AddObjectToEnd(gdcmDicomDir::GDCM_META,begin,k);       
213     
214    for(ListTag::iterator i=k;i !=listEntries.end();++i) 
215    {
216       std::string v=(*i)->GetValue();
217       if(v=="PATIENT ") 
218       {
219          end=i;
220          AddObjectToEnd(type,begin,end);
221
222          type=gdcmDicomDir::GDCM_PATIENT;
223          begin=end;
224       } 
225
226       if(v=="STUDY ")
227       {
228          end=i;
229          AddObjectToEnd(type,begin,end);
230
231          type=gdcmDicomDir::GDCM_STUDY;
232          begin=end;
233       }
234
235       if(v=="SERIES") 
236       {
237          end=i;
238          AddObjectToEnd(type,begin,end);
239
240          type=gdcmDicomDir::GDCM_SERIE;
241          begin=end;
242       }
243
244       if(v=="IMAGE ") 
245       {
246          end=i;
247          AddObjectToEnd(type,begin,end);
248
249          type=gdcmDicomDir::GDCM_IMAGE;
250          begin=end;
251       }
252    }
253
254    end=GetListEntry().end();
255    AddObjectToEnd(type,begin,end);
256 }
257 /*
258  * \ingroup gdcmDicomDir
259  * \brief   
260  * @param   type
261  * @param   begin
262  * @param   end
263  */
264 void gdcmDicomDir::AddObjectToEnd(gdcmDicomDirType type,ListTag::iterator begin,ListTag::iterator end)
265 {
266    if(begin==end)
267       return;
268
269    switch(type)
270    {
271       case gdcmDicomDir::GDCM_META:
272          AddMetaToEnd(begin,end);
273          break;      
274       case gdcmDicomDir::GDCM_PATIENT:
275          AddPatientToEnd(begin,end);
276          break;
277       case gdcmDicomDir::GDCM_STUDY:
278          AddStudyToEnd(begin,end);
279          break;
280       case gdcmDicomDir::GDCM_SERIE:
281          AddSerieToEnd(begin,end);
282          break;
283       case gdcmDicomDir::GDCM_IMAGE:
284          AddImageToEnd(begin,end);
285          break;
286    }
287 }
288
289
290 /*
291  * \ingroup gdcmDicomDir
292  * \brief Well ... Not realy to end, there is only one occurence  
293  * @param   begin
294  * @param   end
295 */
296 void gdcmDicomDir::AddMetaToEnd(ListTag::iterator begin,ListTag::iterator end)
297 {
298    metaelems = new gdcmMeta(begin,end);
299 }
300
301 /*
302  * \ingroup gdcmDicomDir
303  * \brief   
304  * @param   begin
305  * @param   end
306 */
307 void gdcmDicomDir::AddPatientToEnd(ListTag::iterator begin,ListTag::iterator end)
308 {
309    patients.push_back(new gdcmPatient(begin,end));
310 }
311
312 /*
313  * \ingroup gdcmDicomDir
314  * \brief   
315  * @param   begin
316  * @param   end
317  */
318  void gdcmDicomDir::AddStudyToEnd(ListTag::iterator begin,ListTag::iterator end)
319 {
320    if(patients.size()>0)
321    {
322       ListPatient::iterator itp=patients.end();
323       itp--;
324      (*itp)->AddStudy(new gdcmStudy(begin,end));
325    }
326 }
327 /*
328  * \ingroup gdcmDicomDir
329  * \brief   
330  * @param   begin
331  * @param   end
332  */
333 void gdcmDicomDir::AddSerieToEnd(ListTag::iterator begin,ListTag::iterator end)
334 {
335    if(patients.size()>0)
336    {
337       ListPatient::iterator itp=patients.end();
338       itp--;
339
340       if((*itp)->GetStudies().size()>0)
341       {
342          ListStudy::iterator itst=(*itp)->GetStudies().end();
343          itst--;
344         (*itst)->AddSerie(new gdcmSerie(begin,end));
345       }
346    }
347 }
348
349 /*
350  * \ingroup gdcmDicomDir
351  * @param   begin
352  * @param   end
353  * @param   
354  */
355  void gdcmDicomDir::AddImageToEnd(ListTag::iterator begin,ListTag::iterator end)
356 {
357    if(patients.size()>0)
358    {
359       ListPatient::iterator itp=patients.end();
360       itp--;
361
362       if((*itp)->GetStudies().size()>0)
363       {
364          ListStudy::iterator itst=(*itp)->GetStudies().end();
365          itst--;
366
367          if((*itst)->GetSeries().size()>0)
368          {
369             ListSerie::iterator its=(*itst)->GetSeries().end();
370             its--;
371            (*its)->AddImage(new gdcmImage(begin,end));
372          }
373       }
374    }
375 }
376
377 /*
378  * \ingroup gdcmDicomDir
379  * \brief   
380  * @param   path
381  * @param   list
382  */
383 void gdcmDicomDir::SetElements(std::string &path,ListHeader &list)
384 {
385    std::string patPrevName="", patPrevID="";
386    std::string studPrevInstanceUID="", studPrevID="";
387    std::string serPrevInstanceUID="", serPrevID="";
388
389    std::string patCurName, patCurID;
390    std::string studCurInstanceUID, studCurID;
391    std::string serCurInstanceUID, serCurID;
392
393    SetElement(path,GDCM_NONE,NULL);
394
395    ListTag::iterator debPat=listEntries.begin();
396    for(ListHeader::iterator it=list.begin();it!=list.end();++it) 
397    {
398       // get the current file characteristics
399       patCurName=(*it)->GetEntryByNumber(0x0010,0x0010); 
400       patCurID=(*it)->GetEntryByNumber(0x0010,0x0011); 
401       studCurInstanceUID=(*it)->GetEntryByNumber(0x0020,0x000d);            
402       studCurID=(*it)->GetEntryByNumber(0x0020,0x0010);            
403       serCurInstanceUID=(*it)->GetEntryByNumber(0x0020,0x000e);            
404       serCurID=(*it)->GetEntryByNumber(0x0020,0x0011);
405
406       if(patCurName!=patPrevName || patCurID!=patPrevID) 
407          SetElement(path,GDCM_PATIENT,*it);
408
409       // if new Study Deal with 'STUDY' Elements   
410       if(studCurInstanceUID!=studPrevInstanceUID || studCurID!=studPrevID) 
411          SetElement(path,GDCM_STUDY,*it);
412
413       // if new Serie Deal with 'SERIE' Elements   
414       if(serCurInstanceUID!=serPrevInstanceUID || serCurID!=serPrevID) 
415          SetElement(path,GDCM_SERIE,*it);
416       
417       // Always Deal with 'IMAGE' Elements  
418       SetElement(path,GDCM_IMAGE,*it);
419
420       patPrevName=patCurName;
421       patPrevID=patCurID;
422       studPrevInstanceUID=studCurInstanceUID;
423       studPrevID=studCurID;
424       serPrevInstanceUID=serCurInstanceUID;
425       serPrevID=serCurID;
426    }
427 }
428
429 /*
430  * \ingroup gdcmDicomDir
431  * \brief   
432  * @param   path
433  * @param   type
434  * @param   header
435  */
436 void gdcmDicomDir::SetElement(std::string &path,gdcmDicomDirType type,gdcmHeader *header)
437 {
438    std::list<gdcmElement> elemList;
439    std::list<gdcmElement>::iterator it;
440    guint16 tmpGr, tmpEl;
441    gdcmDictEntry *dictEntry;
442    gdcmHeaderEntry *entry;
443    std::string val;
444
445    switch(type)
446    {
447       case GDCM_PATIENT:
448          elemList=gdcmGlobal::GetDicomDirElements()->GetPatientElements();
449          break;
450       case GDCM_STUDY:
451          elemList=gdcmGlobal::GetDicomDirElements()->GetStudyElements();
452          break;
453       case GDCM_SERIE:
454          elemList=gdcmGlobal::GetDicomDirElements()->GetSerieElements();
455          break;
456       case GDCM_IMAGE:
457          elemList=gdcmGlobal::GetDicomDirElements()->GetImageElements();
458          break;
459       case GDCM_NONE:
460          elemList=gdcmGlobal::GetDicomDirElements()->GetMetaElements();
461          break;
462       default:
463          return;
464    }
465
466    for(it=elemList.begin();it!=elemList.end();++it)
467    {
468       tmpGr=it->group;
469       tmpEl=it->elem;
470
471       dictEntry=GetPubDict()->GetDictEntryByNumber(tmpGr,tmpEl);
472       entry=new gdcmHeaderEntry(dictEntry);
473       entry->SetOffset(0); // just to avoid missprinting
474
475       if(header)
476          val=header->GetEntryByNumber(tmpGr,tmpEl);
477       else
478          val=GDCM_UNFOUND;
479
480       if(val==GDCM_UNFOUND) 
481       {
482          if((tmpGr==0x0004) &&(tmpEl==0x1130) )
483          {
484             // TODO force the *end* File Name(remove path)
485             val=path;
486          }
487          else if( (tmpGr==0x0004) && (tmpEl==0x1500) ) // Only used for image
488          {
489             if(header->GetFileName().substr(0,path.length())!=path)
490             {
491                dbg.Verbose(0, "gdcmDicomDir::SetElement : the base path of file name is incorrect");
492                val=header->GetFileName();
493             }
494             else
495                val=&(header->GetFileName()[path.length()]);
496          }
497          else
498          {
499             val=it->value;
500          }
501       }
502       entry->SetValue(val);
503
504       if(dictEntry)
505       {
506          if( (dictEntry->GetVR()=="UL") || (dictEntry->GetVR()=="SL") ) 
507          {
508             entry->SetLength(4);
509          } 
510          else if( (dictEntry->GetVR()=="US") || (dictEntry->GetVR()=="SS") ) 
511          {
512             entry->SetLength(2); 
513          } 
514          else if(dictEntry->GetVR()=="SQ") 
515          {
516             entry->SetLength(0xffffffff);
517          }
518          else
519          {
520             entry->SetLength(entry->GetValue().length());        
521          }
522       }
523
524       listEntries.push_back(entry);
525    }     
526 }
527
528 bool gdcmDicomDir::HeaderLessThan(gdcmHeader *header1,gdcmHeader *header2)
529 {
530    return(*header1<*header2);
531 }
532
533 //-----------------------------------------------------------------------------