]> Creatis software - gdcm.git/blob - src/gdcmDicomDir.cxx
*** empty log message ***
[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    metaElems=NULL;
31
32    if( GetListEntry().begin()==GetListEntry().end() ) 
33    {
34       dbg.Verbose(0, "gdcmDicomDir::gdcmDicomDir : entry list empty");
35
36       if(parseDir)
37       {
38          dbg.Verbose(0, "gdcmDicomDir::gdcmDicomDir : Parse directory and create the DicomDir");
39          ParseDirectory();
40       }
41    }
42    else
43       CreateDicomDir();
44 }
45
46 /*
47  * \ingroup gdcmDicomDir
48  * \brief  Canonical destructor 
49  */
50 gdcmDicomDir::~gdcmDicomDir() 
51 {
52    if(metaElems)
53       delete metaElems;
54    
55    for(ListPatient::iterator cc=patients.begin();cc!=patients.end();++cc)
56    {
57       delete *cc;
58    }
59 }
60
61 //-----------------------------------------------------------------------------
62 // Print
63 /*
64  * \ingroup gdcmDicomDir
65  * \brief  Canonical Printer 
66  */
67 void gdcmDicomDir::Print(std::ostream &os)
68 {
69    if(metaElems)
70    {
71       metaElems->SetPrintLevel(printLevel);
72       metaElems->Print(os);   
73    }
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 create a gdcmDicomDir from a root Directory 
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 DicomDir 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 create a 'gdcmDicomDir' from a DICOMDIR gdcmHeader 
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_META;
193    ListTag::iterator begin;
194    ListTag::iterator end;
195
196    begin=listEntries.begin();
197    end=begin;
198    for(ListTag::iterator i=end;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    if(begin!=end)
239    {
240       end=GetListEntry().end();
241       AddObjectToEnd(type,begin,end);
242    }
243 }
244 /*
245  * \ingroup gdcmDicomDir
246  * \brief   
247  * @param   type
248  * @param   begin
249  * @param   end
250  */
251 void gdcmDicomDir::AddObjectToEnd(gdcmDicomDirType type,ListTag::iterator begin,ListTag::iterator end)
252 {
253    if(begin==end)
254       return;
255
256    switch(type)
257    {
258       case gdcmDicomDir::GDCM_META:
259          AddMetaToEnd(begin,end);
260          break;      
261       case gdcmDicomDir::GDCM_PATIENT:
262          AddPatientToEnd(begin,end);
263          break;
264       case gdcmDicomDir::GDCM_STUDY:
265          AddStudyToEnd(begin,end);
266          break;
267       case gdcmDicomDir::GDCM_SERIE:
268          AddSerieToEnd(begin,end);
269          break;
270       case gdcmDicomDir::GDCM_IMAGE:
271          AddImageToEnd(begin,end);
272          break;
273    }
274 }
275
276 /*
277  * \ingroup gdcmDicomDir
278  * \brief Well ... Not realy to end, there is only one occurence  
279  * @param   begin
280  * @param   end
281 */
282 void gdcmDicomDir::AddMetaToEnd(ListTag::iterator begin,ListTag::iterator end)
283 {
284    if(metaElems)
285       delete metaElems;
286    metaElems = new gdcmMeta(begin,end);
287 }
288
289 /*
290  * \ingroup gdcmDicomDir
291  * \brief   
292  * @param   begin
293  * @param   end
294 */
295 void gdcmDicomDir::AddPatientToEnd(ListTag::iterator begin,ListTag::iterator end)
296 {
297    patients.push_back(new gdcmPatient(begin,end));
298 }
299
300 /*
301  * \ingroup gdcmDicomDir
302  * \brief   
303  * @param   begin
304  * @param   end
305  */
306  void gdcmDicomDir::AddStudyToEnd(ListTag::iterator begin,ListTag::iterator end)
307 {
308    if(patients.size()>0)
309    {
310       ListPatient::iterator itp=patients.end();
311       itp--;
312      (*itp)->AddStudy(new gdcmStudy(begin,end));
313    }
314 }
315 /*
316  * \ingroup gdcmDicomDir
317  * \brief   
318  * @param   begin
319  * @param   end
320  */
321 void gdcmDicomDir::AddSerieToEnd(ListTag::iterator begin,ListTag::iterator end)
322 {
323    if(patients.size()>0)
324    {
325       ListPatient::iterator itp=patients.end();
326       itp--;
327
328       if((*itp)->GetStudies().size()>0)
329       {
330          ListStudy::iterator itst=(*itp)->GetStudies().end();
331          itst--;
332         (*itst)->AddSerie(new gdcmSerie(begin,end));
333       }
334    }
335 }
336
337 /*
338  * \ingroup gdcmDicomDir
339  * @param   begin
340  * @param   end
341  * @param   
342  */
343  void gdcmDicomDir::AddImageToEnd(ListTag::iterator begin,ListTag::iterator end)
344 {
345    if(patients.size()>0)
346    {
347       ListPatient::iterator itp=patients.end();
348       itp--;
349
350       if((*itp)->GetStudies().size()>0)
351       {
352          ListStudy::iterator itst=(*itp)->GetStudies().end();
353          itst--;
354
355          if((*itst)->GetSeries().size()>0)
356          {
357             ListSerie::iterator its=(*itst)->GetSeries().end();
358             its--;
359            (*its)->AddImage(new gdcmImage(begin,end));
360          }
361       }
362    }
363 }
364
365 /*
366  * \ingroup gdcmDicomDir
367  * \brief   
368  * @param   path
369  * @param   list
370  */
371 void gdcmDicomDir::SetElements(std::string &path,ListHeader &list)
372 {
373    std::string patPrevName="", patPrevID="";
374    std::string studPrevInstanceUID="", studPrevID="";
375    std::string serPrevInstanceUID="", serPrevID="";
376
377    std::string patCurName, patCurID;
378    std::string studCurInstanceUID, studCurID;
379    std::string serCurInstanceUID, serCurID;
380
381    SetElement(path,GDCM_NONE,NULL);
382
383    ListTag::iterator debPat=listEntries.begin();
384    for(ListHeader::iterator it=list.begin();it!=list.end();++it) 
385    {
386       // get the current file characteristics
387       patCurName=(*it)->GetEntryByNumber(0x0010,0x0010); 
388       patCurID=(*it)->GetEntryByNumber(0x0010,0x0011); 
389       studCurInstanceUID=(*it)->GetEntryByNumber(0x0020,0x000d);            
390       studCurID=(*it)->GetEntryByNumber(0x0020,0x0010);            
391       serCurInstanceUID=(*it)->GetEntryByNumber(0x0020,0x000e);            
392       serCurID=(*it)->GetEntryByNumber(0x0020,0x0011);
393
394       if(patCurName!=patPrevName || patCurID!=patPrevID) 
395          SetElement(path,GDCM_PATIENT,*it);
396
397       // if new Study Deal with 'STUDY' Elements   
398       if(studCurInstanceUID!=studPrevInstanceUID || studCurID!=studPrevID) 
399          SetElement(path,GDCM_STUDY,*it);
400
401       // if new Serie Deal with 'SERIE' Elements   
402       if(serCurInstanceUID!=serPrevInstanceUID || serCurID!=serPrevID) 
403          SetElement(path,GDCM_SERIE,*it);
404       
405       // Always Deal with 'IMAGE' Elements  
406       SetElement(path,GDCM_IMAGE,*it);
407
408       patPrevName=patCurName;
409       patPrevID=patCurID;
410       studPrevInstanceUID=studCurInstanceUID;
411       studPrevID=studCurID;
412       serPrevInstanceUID=serCurInstanceUID;
413       serPrevID=serCurID;
414    }
415 }
416
417 /*
418  * \ingroup gdcmDicomDir
419  * \brief   
420  * @param   path
421  * @param   type
422  * @param   header
423  */
424 void gdcmDicomDir::SetElement(std::string &path,gdcmDicomDirType type,gdcmHeader *header)
425 {
426    std::list<gdcmElement> elemList;
427    std::list<gdcmElement>::iterator it;
428    guint16 tmpGr, tmpEl;
429    gdcmDictEntry *dictEntry;
430    gdcmHeaderEntry *entry;
431    std::string val;
432
433    switch(type)
434    {
435       case GDCM_PATIENT:
436          elemList=gdcmGlobal::GetDicomDirElements()->GetPatientElements();
437          break;
438       case GDCM_STUDY:
439          elemList=gdcmGlobal::GetDicomDirElements()->GetStudyElements();
440          break;
441       case GDCM_SERIE:
442          elemList=gdcmGlobal::GetDicomDirElements()->GetSerieElements();
443          break;
444       case GDCM_IMAGE:
445          elemList=gdcmGlobal::GetDicomDirElements()->GetImageElements();
446          break;
447       case GDCM_NONE:
448          elemList=gdcmGlobal::GetDicomDirElements()->GetMetaElements();
449          break;
450       default:
451          return;
452    }
453
454    for(it=elemList.begin();it!=elemList.end();++it)
455    {
456       tmpGr=it->group;
457       tmpEl=it->elem;
458
459       dictEntry=GetPubDict()->GetDictEntryByNumber(tmpGr,tmpEl);
460       entry=new gdcmHeaderEntry(dictEntry);
461       entry->SetOffset(0); // just to avoid missprinting
462
463       if(header)
464          val=header->GetEntryByNumber(tmpGr,tmpEl);
465       else
466          val=GDCM_UNFOUND;
467
468       if(val==GDCM_UNFOUND) 
469       {
470          if((tmpGr==0x0004) &&(tmpEl==0x1130) )
471          {
472             // TODO force the *end* File Name(remove path)
473             val=path;
474          }
475          else if( (tmpGr==0x0004) && (tmpEl==0x1500) ) // Only used for image
476          {
477             if(header->GetFileName().substr(0,path.length())!=path)
478             {
479                dbg.Verbose(0, "gdcmDicomDir::SetElement : the base path of file name is incorrect");
480                val=header->GetFileName();
481             }
482             else
483                val=&(header->GetFileName()[path.length()]);
484          }
485          else
486          {
487             val=it->value;
488          }
489       }
490       entry->SetValue(val);
491
492       if(dictEntry)
493       {
494          if( (dictEntry->GetVR()=="UL") || (dictEntry->GetVR()=="SL") ) 
495          {
496             entry->SetLength(4);
497          } 
498          else if( (dictEntry->GetVR()=="US") || (dictEntry->GetVR()=="SS") ) 
499          {
500             entry->SetLength(2); 
501          } 
502          else if(dictEntry->GetVR()=="SQ") 
503          {
504             entry->SetLength(0xffffffff);
505          }
506          else
507          {
508             entry->SetLength(entry->GetValue().length());        
509          }
510       }
511
512       listEntries.push_back(entry);
513    }     
514 }
515
516 bool gdcmDicomDir::HeaderLessThan(gdcmHeader *header1,gdcmHeader *header2)
517 {
518    return(*header1<*header2);
519 }
520
521 //-----------------------------------------------------------------------------