]> Creatis software - gdcm.git/blob - src/gdcmDicomDir.cxx
Fix &reference syntax pb
[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    for(ListPatient::iterator cc=patients.begin();cc!=patients.end();++cc)
62    {
63       delete *cc;
64    }
65 }
66
67 //-----------------------------------------------------------------------------
68 // Print
69 /*
70  * \ingroup gdcmDicomDir
71  * \brief  Canonical Printer 
72  */
73 void gdcmDicomDir::Print(std::ostream &os)
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   
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       header=new gdcmHeader(it->c_str());
146       if(header->IsReadable())
147          list.push_back(header);
148       else
149          delete header;
150    }
151
152    std::sort(list.begin(),list.end(),gdcmDicomDir::HeaderLessThan);
153
154    std::string tmp=fileList.GetDirName();
155    SetElements(tmp,list);
156 }
157
158 /*
159  * \ingroup gdcmDicomDir
160  * \brief   Get the dicom dir path
161  * @param   
162  */
163 std::string gdcmDicomDir::GetPath(void)
164 {
165    std::string path=GetFileName();
166
167    int pos1=path.rfind("/");
168    int pos2=path.rfind("\\");
169    if(pos1>pos2)
170       path.resize(pos1);
171    else
172       path.resize(pos2);
173
174    return(path);
175 }
176
177 //-----------------------------------------------------------------------------
178 // Private
179 /*
180  * \ingroup gdcmDicomDir
181  * \brief   
182  * @param   
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_NONE;
194    ListTag::iterator begin;
195    ListTag::iterator end;
196
197    begin=listEntries.begin();
198    end=begin;
199    for(ListTag::iterator i=listEntries.begin();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    end=GetListEntry().end();
240    AddObjectToEnd(type,begin,end);
241 }
242 /*
243  * \ingroup gdcmDicomDir
244  * \brief   
245  * @param   type
246  * @param   begin
247  * @param   end
248  */
249 void gdcmDicomDir::AddObjectToEnd(gdcmDicomDirType type,ListTag::iterator begin,ListTag::iterator end)
250 {
251    if(begin==end)
252       return;
253
254    switch(type)
255    {
256       case gdcmDicomDir::GDCM_PATIENT:
257          AddPatientToEnd(begin,end);
258          break;
259       case gdcmDicomDir::GDCM_STUDY:
260          AddStudyToEnd(begin,end);
261          break;
262       case gdcmDicomDir::GDCM_SERIE:
263          AddSerieToEnd(begin,end);
264          break;
265       case gdcmDicomDir::GDCM_IMAGE:
266          AddImageToEnd(begin,end);
267          break;
268    }
269 }
270
271 /*
272  * \ingroup gdcmDicomDir
273  * \brief   
274  * @param   begin
275  * @param   end
276 */
277 void gdcmDicomDir::AddPatientToEnd(ListTag::iterator begin,ListTag::iterator end)
278 {
279    patients.push_back(new gdcmPatient(begin,end));
280 }
281
282 /*
283  * \ingroup gdcmDicomDir
284  * \brief   
285  * @param   begin
286  * @param   end
287  */
288  void gdcmDicomDir::AddStudyToEnd(ListTag::iterator begin,ListTag::iterator end)
289 {
290    if(patients.size()>0)
291    {
292       ListPatient::iterator itp=patients.end();
293       itp--;
294      (*itp)->AddStudy(new gdcmStudy(begin,end));
295    }
296 }
297 /*
298  * \ingroup gdcmDicomDir
299  * \brief   
300  * @param   begin
301  * @param   end
302  */
303 void gdcmDicomDir::AddSerieToEnd(ListTag::iterator begin,ListTag::iterator end)
304 {
305    if(patients.size()>0)
306    {
307       ListPatient::iterator itp=patients.end();
308       itp--;
309
310       if((*itp)->GetStudies().size()>0)
311       {
312          ListStudy::iterator itst=(*itp)->GetStudies().end();
313          itst--;
314         (*itst)->AddSerie(new gdcmSerie(begin,end));
315       }
316    }
317 }
318
319 /*
320  * \ingroup gdcmDicomDir
321  * @param   begin
322  * @param   end
323  * @param   
324  */
325  void gdcmDicomDir::AddImageToEnd(ListTag::iterator begin,ListTag::iterator end)
326 {
327    if(patients.size()>0)
328    {
329       ListPatient::iterator itp=patients.end();
330       itp--;
331
332       if((*itp)->GetStudies().size()>0)
333       {
334          ListStudy::iterator itst=(*itp)->GetStudies().end();
335          itst--;
336
337          if((*itst)->GetSeries().size()>0)
338          {
339             ListSerie::iterator its=(*itst)->GetSeries().end();
340             its--;
341            (*its)->AddImage(new gdcmImage(begin,end));
342          }
343       }
344    }
345 }
346
347 /*
348  * \ingroup gdcmDicomDir
349  * \brief   
350  * @param   path
351  * @param   list
352  */
353 void gdcmDicomDir::SetElements(std::string &path,ListHeader &list)
354 {
355    std::string patPrevName="", patPrevID="";
356    std::string studPrevInstanceUID="", studPrevID="";
357    std::string serPrevInstanceUID="", serPrevID="";
358
359    std::string patCurName, patCurID;
360    std::string studCurInstanceUID, studCurID;
361    std::string serCurInstanceUID, serCurID;
362
363    SetElement(path,GDCM_NONE,NULL);
364
365    ListTag::iterator debPat=listEntries.begin();
366    for(ListHeader::iterator it=list.begin();it!=list.end();++it) 
367    {
368       // get the current file characteristics
369       patCurName=(*it)->GetEntryByNumber(0x0010,0x0010); 
370       patCurID=(*it)->GetEntryByNumber(0x0010,0x0011); 
371       studCurInstanceUID=(*it)->GetEntryByNumber(0x0020,0x000d);            
372       studCurID=(*it)->GetEntryByNumber(0x0020,0x0010);            
373       serCurInstanceUID=(*it)->GetEntryByNumber(0x0020,0x000e);            
374       serCurID=(*it)->GetEntryByNumber(0x0020,0x0011);
375
376       if(patCurName!=patPrevName || patCurID!=patPrevID) 
377          SetElement(path,GDCM_PATIENT,*it);
378
379       // if new Study Deal with 'STUDY' Elements   
380       if(studCurInstanceUID!=studPrevInstanceUID || studCurID!=studPrevID) 
381          SetElement(path,GDCM_STUDY,*it);
382
383       // if new Serie Deal with 'SERIE' Elements   
384       if(serCurInstanceUID!=serPrevInstanceUID || serCurID!=serPrevID) 
385       {
386          SetElement(path,GDCM_SERIE,*it);
387       } 
388       
389       // Always Deal with 'IMAGE' Elements  
390       SetElement(path,GDCM_IMAGE,*it);
391
392       patPrevName=patCurName;
393       patPrevID=patCurID;
394       studPrevInstanceUID=studCurInstanceUID;
395       studPrevID=studCurID;
396       serPrevInstanceUID=serCurInstanceUID;
397       serPrevID=serCurID;
398    }
399 }
400
401 /*
402  * \ingroup gdcmDicomDir
403  * \brief   
404  * @param   path
405  * @param   type
406  * @param   header
407  */
408 void gdcmDicomDir::SetElement(std::string &path,gdcmDicomDirType type,gdcmHeader *header)
409 {
410    std::list<gdcmElement> elemList;
411    std::list<gdcmElement>::iterator it;
412    guint16 tmpGr, tmpEl;
413    gdcmDictEntry *dictEntry;
414    gdcmHeaderEntry *entry;
415    std::string val;
416
417    switch(type)
418    {
419       case GDCM_PATIENT:
420          elemList=gdcmGlobal::GetDicomDirElements()->GetPatientElements();
421          break;
422       case GDCM_STUDY:
423          elemList=gdcmGlobal::GetDicomDirElements()->GetStudyElements();
424          break;
425       case GDCM_SERIE:
426          elemList=gdcmGlobal::GetDicomDirElements()->GetSerieElements();
427          break;
428       case GDCM_IMAGE:
429          elemList=gdcmGlobal::GetDicomDirElements()->GetImageElements();
430          break;
431       case GDCM_NONE:
432          elemList=gdcmGlobal::GetDicomDirElements()->GetMetaElements();
433          break;
434       default:
435          return;
436    }
437
438    for(it=elemList.begin();it!=elemList.end();++it)
439    {
440       tmpGr=it->group;
441       tmpEl=it->elem;
442
443       dictEntry=GetPubDict()->GetDictEntryByNumber(tmpGr,tmpEl);
444       entry=new gdcmHeaderEntry(dictEntry);
445       entry->SetOffset(0); // just to avoid missprinting
446
447       if(header)
448          val=header->GetEntryByNumber(tmpGr,tmpEl);
449       else
450          val=GDCM_UNFOUND;
451
452       if(val==GDCM_UNFOUND) 
453       {
454          if((tmpGr==0x0004) &&(tmpEl==0x1130) )
455          {
456             // TODO force the *end* File Name(remove path)
457             val=path;
458          }
459          else if( (tmpGr==0x0004) && (tmpEl==0x1500) ) // Only used for image
460          {
461             if(header->GetFileName().substr(0,path.length())!=path)
462             {
463                dbg.Verbose(0, "gdcmDicomDir::SetElement : the base path of file name is incorrect");
464                val=header->GetFileName();
465             }
466             else
467                val=&(header->GetFileName()[path.length()]);
468          }
469          else
470          {
471             val=it->value;
472          }
473       }
474       entry->SetValue(val);
475
476       if(dictEntry)
477       {
478          if( (dictEntry->GetVR()=="UL") || (dictEntry->GetVR()=="SL") ) 
479          {
480             entry->SetLength(4);
481          } 
482          else if( (dictEntry->GetVR()=="US") || (dictEntry->GetVR()=="SS") ) 
483          {
484             entry->SetLength(2); 
485          } 
486          else if(dictEntry->GetVR()=="SQ") 
487          {
488             entry->SetLength(0xffffffff);
489          }
490          else
491          {
492             entry->SetLength(entry->GetValue().length());        
493          }
494       }
495
496       listEntries.push_back(entry);
497    }     
498 }
499
500 bool gdcmDicomDir::HeaderLessThan(gdcmHeader *header1,gdcmHeader *header2)
501 {
502    return(*header1<*header2);
503 }
504
505 //-----------------------------------------------------------------------------