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