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