]> Creatis software - gdcm.git/blob - src/gdcmDicomDir.cxx
Now the tree-like structure describing a DICOMDIR comming from an already
[gdcm.git] / src / gdcmDicomDir.cxx
1 // gdcmDicomDir.cxx
2 //-----------------------------------------------------------------------------
3 #include "gdcmDicomDir.h"
4 #include "gdcmDicomDirStudy.h"
5 #include "gdcmDicomDirSerie.h"
6 #include "gdcmDicomDirImage.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 #include <unistd.h>
16
17 //-----------------------------------------------------------------------------
18 //  For full DICOMDIR description, see:
19 //  PS 3.3-2003, pages 731-750
20 //-----------------------------------------------------------------------------
21 // Constructor / Destructor
22 /*
23  * \ingroup gdcmDicomDir
24  * \brief   Constructor : Parses recursively the directory and creates the DicomDir
25  * \                      or uses an already built DICOMDIR, depending on 'parseDir' value
26  * @param   Name          name of the root directory (parseDir = true)
27  *                        name of the DICOMDIR       (parseDir = false)
28  * @param   parseDir      - true if user passed an entry point 
29  *                        and wants to explore recursively the directories
30  *                        - false if user passed an already built DICOMDIR file
31  *                        and wants to use it 
32  * @param   exception_on_error whether we want to throw an exception or not
33  */
34 gdcmDicomDir::gdcmDicomDir(const char *Name, bool parseDir,
35                            bool exception_on_error):
36    gdcmParser(Name,exception_on_error,true) // true : enable SeQuences
37 {
38  // que l'on ai passe un root directory ou un DICOMDIR
39  // et quelle que soit la valeur de parseDir,
40  // on a lance gdcmParser 
41       
42    startMethod=            NULL;
43    progressMethod=         NULL;
44    endMethod=              NULL;
45    startMethodArgDelete=   NULL;
46    progressMethodArgDelete=NULL;
47    endMethodArgDelete=     NULL;
48    startArg=               NULL;
49    progressArg=            NULL;
50    endArg=                 NULL;
51
52    progress=0.0;
53    abort=false;
54
55    metaElems=NULL;
56
57 // gdcmParser already  executed
58 // if user passed a root directory, sure we didn't get anything
59
60    if( GetListEntry().begin()==GetListEntry().end() ) 
61    {
62      // if parseDir == false, it should be tagged as an error
63       dbg.Verbose(0, "gdcmDicomDir::gdcmDicomDir : entry list empty");
64
65       if(strlen(Name)==1 && Name[0]=='.') { // user passed '.' as Name
66                                             // we get current directory name
67          char*dummy=(char*) malloc(1000);   // TODO : check with Windoze
68          getcwd(dummy,(size_t)1000);
69          SetFileName(dummy); // will be converted into a string
70          free(dummy);        // no longer needed   
71       }
72
73       if(parseDir)
74       {
75          dbg.Verbose(0, "gdcmDicomDir::gdcmDicomDir : Parse directory and create the DicomDir");
76          ParseDirectory();
77       }
78    }
79    else {
80       CreateDicomDir();
81       CheckBoundaries(); // JPR 
82    }   
83  
84 }
85
86 /*
87  * \ingroup gdcmDicomDir
88  * \brief   Constructor : creates an empty gdcmDicomDir
89  * @param   exception_on_error whether we want to throw an exception or not
90  */
91 gdcmDicomDir::gdcmDicomDir(bool exception_on_error):                           
92    gdcmParser(exception_on_error)
93
94    startMethod=            NULL;
95    progressMethod=         NULL;
96    endMethod=              NULL;
97    startMethodArgDelete=   NULL;
98    progressMethodArgDelete=NULL;
99    endMethodArgDelete=     NULL;
100    startArg=               NULL;
101    progressArg=            NULL;
102    endArg=                 NULL;
103
104    progress=0.0;
105    abort=false;
106    std::string pathBidon = ""; // Sorry, NULL not allowed ...
107    SetElement(pathBidon, GDCM_DICOMDIR_META, NULL); // Set the META elements
108    
109    AddDicomDirMetaToEnd(listEntries.begin(),--listEntries.end());
110 }
111
112
113 /*
114  * \ingroup gdcmDicomDir
115  * \brief  Canonical destructor 
116  */
117 gdcmDicomDir::~gdcmDicomDir() 
118 {
119    SetStartMethod(NULL);
120    SetProgressMethod(NULL);
121    SetEndMethod(NULL);
122
123    if(metaElems)
124       delete metaElems;
125    
126    for(ListDicomDirPatient::iterator cc=patients.begin();cc!=patients.end();++cc)
127    {
128       delete *cc;
129    }
130 }
131
132 //-----------------------------------------------------------------------------
133 // Print
134 /*
135  * \ingroup gdcmDicomDir
136  * \brief  Canonical Printer 
137  */
138 void gdcmDicomDir::Print(std::ostream &os)
139 {
140    if(metaElems)
141    {
142       metaElems->SetPrintLevel(printLevel);
143       metaElems->Print(os);   
144    }   
145    for(ListDicomDirPatient::iterator cc=patients.begin();cc!=patients.end();++cc)
146    {
147      (*cc)->SetPrintLevel(printLevel);
148      (*cc)->Print(os);     
149    }
150 }
151
152 //-----------------------------------------------------------------------------
153 // Public
154 /*
155  * \ingroup gdcmDicomDir
156  * \brief  This predicate, based on hopefully reasonable heuristics,
157  *         decides whether or not the current header was properly parsed
158  *         and contains the mandatory information for being considered as
159  *         a well formed and usable DicomDir.
160  * @return true when gdcmParser is the one of a reasonable DicomDir,
161  *         false otherwise. 
162  */
163 bool gdcmDicomDir::IsReadable(void)
164 {
165    if(!gdcmParser::IsReadable())
166       return(false);
167    if(!metaElems)
168       return(false);
169    if(patients.size()<=0)
170       return(false);
171
172    return(true);
173 }
174
175 /*
176  * \ingroup gdcmDicomDir
177  * \brief  fills the whole structure, starting from a root Directory
178  */
179 void gdcmDicomDir::ParseDirectory(void)
180 {
181    CreateDicomDirChainedList(GetFileName());
182    CreateDicomDir();
183 }
184
185 /*
186  * \ingroup gdcmDicomDir
187  * \brief   Set the start method to call when the parsing of the directory starts
188  * @param   method Method to call
189  * @param   arg    Argument to pass to the method
190  * \warning In python : the arg parameter isn't considered
191  */
192 void gdcmDicomDir::SetStartMethod(gdcmMethod *method,void *arg,gdcmMethod *argDelete)
193 {
194    if((startArg)&&(startMethodArgDelete))
195       startMethodArgDelete(startArg);
196
197    startMethod=method;
198    startArg=arg;
199    startMethodArgDelete=argDelete;
200 }
201
202 /*
203  * \ingroup gdcmDicomDir
204  * \brief   Set the method to delete the argument
205  *          The argument is destroyed when the method is changed or when the
206  *          class is destroyed
207  * @param   method Method to call to delete the argument
208  */
209 void gdcmDicomDir::SetStartMethodArgDelete(gdcmMethod *method) 
210 {
211    startMethodArgDelete=method;
212 }
213
214 /*
215  * \ingroup gdcmDicomDir
216  * \brief   Set the progress method to call when the parsing of the directory progress
217  * @param   method Method to call
218  * @param   arg    Argument to pass to the method
219  * \warning In python : the arg parameter isn't considered
220  */
221 void gdcmDicomDir::SetProgressMethod(gdcmMethod *method,void *arg,gdcmMethod *argDelete)
222 {
223    if((progressArg)&&(progressMethodArgDelete))
224       progressMethodArgDelete(progressArg);
225
226    progressMethod=method;
227    progressArg=arg;
228    progressMethodArgDelete=argDelete;
229 }
230
231 /*
232  * \ingroup gdcmDicomDir
233  * \brief   Set the method to delete the argument
234  *          The argument is destroyed when the method is changed or when the 
235  *          class is destroyed          
236  * @param   method Method to call to delete the argument
237  */
238 void gdcmDicomDir::SetProgressMethodArgDelete(gdcmMethod *method)
239 {
240    progressMethodArgDelete=method;
241 }
242
243 /*
244  * \ingroup gdcmDicomDir
245  * \brief   Set the end method to call when the parsing of the directory ends
246  * @param   method Method to call
247  * @param   arg    Argument to pass to the method
248  * \warning In python : the arg parameter isn't considered
249  */
250 void gdcmDicomDir::SetEndMethod(gdcmMethod *method,void *arg,gdcmMethod *argDelete)
251 {
252    if((endArg)&&(endMethodArgDelete))
253       endMethodArgDelete(endArg);
254
255    endMethod=method;
256    endArg=arg;
257    endMethodArgDelete=argDelete;
258 }
259
260 /*
261  * \ingroup gdcmDicomDir
262  * \brief   Set the method to delete the argument
263  *          The argument is destroyed when the method is changed or when the class
264  *          is destroyed
265  * @param   method Method to call to delete the argument
266  */
267 void gdcmDicomDir::SetEndMethodArgDelete(gdcmMethod *method)
268 {
269    endMethodArgDelete=method;
270 }
271
272 /**
273  * \ingroup gdcmDicomDir
274  * \brief   writes on disc a DICOMDIR
275  * \ warning does NOT add the missing elements in the header :
276  *           it's up to the user doing it !
277  * \todo : to be re-written using the DICOMDIR tree-like structure
278  *         *not* the chained list
279  *         (does NOT exist if the DICOMDIR is user-forged !)
280  * @param  fileName file to be written to 
281  * @return false only when fail to open
282  */
283  
284 bool gdcmDicomDir::Write(std::string fileName) 
285 {
286    FILE * fp1;
287
288    fp1=fopen(fileName.c_str(),"wb");
289    if(fp1==NULL) 
290    {
291       printf("Failed to open(write) File [%s] \n",fileName.c_str());
292       return(false);
293    }
294
295    char * filePreamble;
296    filePreamble=(char*)calloc(128,1);
297    fwrite(filePreamble,128,1,fp1);
298    fwrite("DICM",4,1,fp1);
299    free(filePreamble);        
300    //UpdateDirectoryRecordSequenceLength(); // a reecrire en utilisant 
301                                             // la structure arborescente JPR
302    WriteDicomDirEntries(fp1);
303
304    fclose(fp1);
305    return true;
306 }
307
308 /**
309  * \ingroup gdcmParser
310  * \brief   writes on disc according to the DICOMDIR format
311  *          using the tree-like structure
312  * @param   _fp already open file pointer
313  */
314
315 void gdcmDicomDir::WriteDicomDirEntries(FILE *_fp)
316 {   
317    // TODO (?) tester les echecs en ecriture 
318    //          (apres chaque fwrite, dans le WriteEntry)
319
320    gdcmDicomDirMeta *ptrMeta;
321    ListDicomDirPatient::iterator  itPatient;
322    ListDicomDirStudy::iterator    itStudy;
323    ListDicomDirSerie::iterator    itSerie;
324    ListDicomDirImage::iterator    itImage; 
325    ListTag::iterator i; 
326    
327    ptrMeta= GetDicomDirMeta();
328    for(i=ptrMeta->debut();i!=ptrMeta->fin();++i) {
329       WriteEntry(*i,_fp,DICOMDIR);
330    }   
331     
332    itPatient = GetDicomDirPatients().begin(); 
333    while ( itPatient != GetDicomDirPatients().end() ) {
334       for(i=(*itPatient)->debut();i!=(*itPatient)->fin();++i) {
335          WriteEntry(*i,_fp,DICOMDIR);
336       }
337       itStudy = ((*itPatient)->GetDicomDirStudies()).begin();         
338       while (itStudy != (*itPatient)->GetDicomDirStudies().end() ) {    
339          for(i=(*itStudy)->debut();i!=(*itStudy)->fin();++i) {
340             WriteEntry(*i,_fp,DICOMDIR);
341          } 
342          itSerie = ((*itStudy)->GetDicomDirSeries()).begin();
343          while (itSerie != (*itStudy)->GetDicomDirSeries().end() ) {
344             for(i=(*itSerie)->debut();i!=(*itSerie)->fin();++i) {
345                WriteEntry(*i,_fp,DICOMDIR);
346             }
347             itImage = ((*itSerie)->GetDicomDirImages()).begin();
348             while (itImage != (*itSerie)->GetDicomDirImages().end() ) {
349                for(i=(*itImage)->debut();i!=(*itImage)->fin();++i) {
350                   WriteEntry(*i,_fp,DICOMDIR);
351                }
352                ++itImage;                   
353             }
354             ++itSerie;                                
355          }
356          ++itStudy;            
357       } 
358       ++itPatient;     
359    }
360 }   
361    
362 //-----------------------------------------------------------------------------
363 // Protected
364
365 /*
366  * \ingroup gdcmDicomDir
367  * \brief create a gdcmHeader-like chained list from a root Directory 
368  * @param path entry point of the tree-like structure
369  */
370 void gdcmDicomDir::CreateDicomDirChainedList(std::string path)
371 {
372    CallStartMethod();
373
374    gdcmDirList fileList(path,1); // gets recursively the file list
375    unsigned int count=0;
376    ListHeader list;
377    gdcmHeader *header;
378
379    listEntries.clear();
380    patients.clear();
381
382    for(gdcmDirList::iterator it=fileList.begin(); 
383                              it!=fileList.end(); 
384                              ++it) 
385    {
386       progress=(float)(count+1)/(float)fileList.size();
387       CallProgressMethod();
388       if(abort)
389          break;
390
391       header=new gdcmHeader(it->c_str());
392       if(header->IsReadable())
393          list.push_back(header);  // adds the file header to the chained list
394       else
395          delete header;
396
397       count++;
398    }
399    // sorts Patient/Study/Serie/
400    std::sort(list.begin(),list.end(),gdcmDicomDir::HeaderLessThan);
401
402    std::string tmp=fileList.GetDirName();
403       
404    //for each Header of the chained list, add/update the Patient/Study/Serie/Image info
405    SetElements(tmp,list);
406       
407    CallEndMethod();
408 }
409
410
411
412 void gdcmDicomDir::CheckBoundaries()
413 {   
414
415 cout <<"entree ds CheckBoundaries " <<endl;
416    ListDicomDirPatient::iterator  itPatient;
417    ListDicomDirStudy::iterator    itStudy;
418    ListDicomDirSerie::iterator    itSerie;
419    ListDicomDirImage::iterator    itImage; 
420    ListTag::iterator i,j; 
421    
422    GetDicomDirMeta()->ResetBoundaries(0);   
423
424    itPatient = GetDicomDirPatients().begin(); 
425    while ( itPatient != GetDicomDirPatients().end() ) {
426       (*itPatient)->ResetBoundaries(1);            
427       itStudy = ((*itPatient)->GetDicomDirStudies()).begin();         
428       while (itStudy != (*itPatient)->GetDicomDirStudies().end() ) {    
429          (*itStudy)->ResetBoundaries(1); 
430          itSerie = ((*itStudy)->GetDicomDirSeries()).begin();
431          while (itSerie != (*itStudy)->GetDicomDirSeries().end() ) {
432             (*itSerie)->ResetBoundaries(1);
433             itImage = ((*itSerie)->GetDicomDirImages()).begin();
434             while (itImage != (*itSerie)->GetDicomDirImages().end() ) {
435                (*itImage)->ResetBoundaries(1);
436                ++itImage;                   
437             }
438             ++itSerie;                                
439          }
440          ++itStudy;            
441       } 
442       ++itPatient;     
443    }
444
445
446
447 /*
448  * \ingroup gdcmDicomDir
449  * \brief   adds a new Patient to a partially created DICOMDIR
450  */
451 gdcmDicomDirPatient * gdcmDicomDir::NewPatient(void) {
452    std::list<gdcmElement> elemList;
453    std::list<gdcmElement>::iterator it;
454    guint16 tmpGr,tmpEl;
455    gdcmDictEntry *dictEntry;
456    gdcmHeaderEntry *entry;
457    
458    elemList=gdcmGlobal::GetDicomDirElements()->GetDicomDirPatientElements();  
459    std::list<gdcmHeaderEntry *>::iterator debInsertion, finInsertion, i,j; 
460          
461    debInsertion = metaElems->fin(); 
462    ++debInsertion;
463    finInsertion=debInsertion;
464
465    // for all the DicomDirPatient Elements   
466    for(it=elemList.begin();it!=elemList.end();++it) 
467    {
468       tmpGr=it->group;
469       tmpEl=it->elem;
470       dictEntry=GetPubDict()->GetDictEntryByNumber(tmpGr,tmpEl);      
471       entry=new gdcmHeaderEntry(dictEntry);
472       entry->SetOffset(0); // just to avoid missprinting
473       entry->SetValue(it->value);
474
475       if(dictEntry->GetGroup()==0xfffe) 
476          {
477             entry->SetLength(entry->GetValue().length());        
478          }
479       else if( (dictEntry->GetVR()=="UL") || (dictEntry->GetVR()=="SL") ) 
480          {
481             entry->SetLength(4);
482          } 
483       else if( (dictEntry->GetVR()=="US") || (dictEntry->GetVR()=="SS") ) 
484          {
485             entry->SetLength(2); 
486          } 
487       else if(dictEntry->GetVR()=="SQ") 
488          {
489             entry->SetLength(0xffffffff);
490          }
491       else
492          {
493             entry->SetLength(entry->GetValue().length());        
494          } 
495                                               
496       tagHT.insert( PairHT(entry->GetKey(),entry) ); // add in the (multimap) H Table
497       listEntries.insert(debInsertion ,entry);       // en tete de liste des Patients                                            
498       ++finInsertion;
499    }
500
501    i=metaElems->fin();
502    i++;
503
504    gdcmDicomDirPatient *p = new gdcmDicomDirPatient(i, --debInsertion,
505                                                     &tagHT, &listEntries);
506    patients.push_front(p);
507    return p;   
508 }
509
510 /*
511  * \ingroup gdcmDicomDir
512  * \brief   CallStartMethod
513  */
514 void gdcmDicomDir::CallStartMethod(void)
515 {
516    progress=0.0f;
517    abort=false;
518    if(startMethod)
519       startMethod(startArg);
520 }
521 /*
522  * \ingroup gdcmDicomDir
523  * \brief   CallProgressMethod
524  */
525 void gdcmDicomDir::CallProgressMethod(void)
526 {
527    if(progressMethod)
528       progressMethod(progressArg);
529 }
530 /*
531  * \ingroup gdcmDicomDir
532  * \brief   CallEndMethod
533  */
534 void gdcmDicomDir::CallEndMethod(void)
535 {
536    progress=1.0f;
537    if(endMethod)
538       endMethod(endArg);
539 }
540
541 //-----------------------------------------------------------------------------
542 // Private
543 /*
544  * \ingroup gdcmDicomDir
545  * \brief create a 'gdcmDicomDir' from a DICOMDIR gdcmHeader 
546  */
547 void gdcmDicomDir::CreateDicomDir()
548 {
549    // The list is parsed. 
550    //  When a DicomDir tag ("PATIENT", "STUDY", "SERIE", "IMAGE") is found :
551    //  1 - we save the beginning iterator
552    //  2 - we continue to parse
553    //  3 - we find an other tag
554    //       + we create the object for the precedent tag
555    //       + loop to 1 -
556
557    gdcmDicomDirType type=gdcmDicomDir::GDCM_DICOMDIR_META;
558    ListTag::iterator begin;
559    ListTag::iterator end, end2;
560
561    begin=listEntries.begin();
562    end=begin;
563    for(ListTag::iterator i=end;i !=listEntries.end();++i) 
564    {
565       std::string v=(*i)->GetValue();
566       if(v=="PATIENT ") 
567       {
568          end=end2=i;
569          AddObjectToEnd(type,begin,--end2);
570          type=gdcmDicomDir::GDCM_DICOMDIR_PATIENT;
571          begin=end;
572       } 
573
574       if(v=="STUDY ")
575       {
576          end=end2=i;
577          AddObjectToEnd(type,begin,--end2);
578          type=gdcmDicomDir::GDCM_DICOMDIR_STUDY;
579          begin=end;
580       }
581
582       if(v=="SERIES") 
583       {
584          end=end2=i;
585          AddObjectToEnd(type,begin,--end2);
586          type=gdcmDicomDir::GDCM_DICOMDIR_SERIE;
587          begin=end;
588       }
589
590       if(v=="IMAGE ") 
591       {
592          end=end2=i;
593          AddObjectToEnd(type,begin,--end2);
594          type=gdcmDicomDir::GDCM_DICOMDIR_IMAGE;
595          begin=end;
596       }
597    }
598
599    end=end2=listEntries.end();
600    if(begin!=end)
601       AddObjectToEnd(type,begin,--end2);
602 }
603 /*
604  * \ingroup gdcmDicomDir
605  * \brief   AddObjectToEnd
606  * @param   type
607  * @param   begin
608  * @param   end
609  */
610 void gdcmDicomDir::AddObjectToEnd(gdcmDicomDirType type,ListTag::iterator begin,ListTag::iterator end)
611 {
612    if(begin==end)
613       return;
614
615    switch(type)
616    {
617       case gdcmDicomDir::GDCM_DICOMDIR_META:
618          AddDicomDirMetaToEnd(begin,end);
619          break;      
620       case gdcmDicomDir::GDCM_DICOMDIR_PATIENT:
621          AddDicomDirPatientToEnd(begin,end);
622          break;
623       case gdcmDicomDir::GDCM_DICOMDIR_STUDY:
624          AddDicomDirStudyToEnd(begin,end);
625          break;
626       case gdcmDicomDir::GDCM_DICOMDIR_SERIE:
627          AddDicomDirSerieToEnd(begin,end);
628          break;
629       case gdcmDicomDir::GDCM_DICOMDIR_IMAGE:
630          AddDicomDirImageToEnd(begin,end);
631          break;
632    }
633 }
634
635 /*
636  * \ingroup gdcmDicomDir
637  * \brief Well ... Not realy to end, there is only one occurence  
638  * @param   begin
639  * @param   end
640 */
641 void gdcmDicomDir::AddDicomDirMetaToEnd(ListTag::iterator begin,ListTag::iterator end)
642 {
643    if(metaElems)
644       delete metaElems;
645    metaElems = new gdcmDicomDirMeta(begin,end,&tagHT,&listEntries);
646 }
647
648 /*
649  * \ingroup gdcmDicomDir
650  * \brief  AddDicomDirPatientToEnd 
651  * @param   begin
652  * @param   end
653 */
654 void gdcmDicomDir::AddDicomDirPatientToEnd(ListTag::iterator begin,ListTag::iterator end)
655 {
656    patients.push_back(new gdcmDicomDirPatient(begin,end,&tagHT, &listEntries));
657 }
658
659 /*
660  * \ingroup gdcmDicomDir
661  * \brief  AddDicomDirStudyToEnd 
662  * @param   begin
663  * @param   end
664  */
665  void gdcmDicomDir::AddDicomDirStudyToEnd(ListTag::iterator begin,ListTag::iterator end)
666 {
667    if(patients.size()>0)
668    {
669       ListDicomDirPatient::iterator itp=patients.end();
670       itp--;
671      (*itp)->AddDicomDirStudy(new gdcmDicomDirStudy(begin,end,&tagHT, &listEntries));
672    }
673 }
674 /*
675  * \ingroup gdcmDicomDir
676  * \brief  AddDicomDirSerieToEnd 
677  * @param   begin
678  * @param   end
679  */
680 void gdcmDicomDir::AddDicomDirSerieToEnd(ListTag::iterator begin,ListTag::iterator end)
681 {
682    if(patients.size()>0)
683    {
684       ListDicomDirPatient::iterator itp=patients.end();
685       itp--;
686
687       if((*itp)->GetDicomDirStudies().size()>0)
688       {
689          ListDicomDirStudy::iterator itst=(*itp)->GetDicomDirStudies().end();
690          itst--;
691         (*itst)->AddDicomDirSerie(new gdcmDicomDirSerie(begin,end,&tagHT, &listEntries));
692       }
693    }
694 }
695
696 /*
697  * \ingroup gdcmDicomDir
698  * \brief   AddDicomDirImageToEnd
699  * @param   begin
700  * @param   end
701  */
702  void gdcmDicomDir::AddDicomDirImageToEnd(ListTag::iterator begin,ListTag::iterator end)
703 {
704    if(patients.size()>0)
705    {
706       ListDicomDirPatient::iterator itp=patients.end();
707       itp--;
708
709       if((*itp)->GetDicomDirStudies().size()>0)
710       {
711          ListDicomDirStudy::iterator itst=(*itp)->GetDicomDirStudies().end();
712          itst--;
713
714          if((*itst)->GetDicomDirSeries().size()>0)
715          {
716             ListDicomDirSerie::iterator its=(*itst)->GetDicomDirSeries().end();
717             its--;
718            (*its)->AddDicomDirImage(new gdcmDicomDirImage(begin,end,&tagHT, &listEntries));
719          }
720       }
721    }
722 }
723
724 /*
725  * \ingroup gdcmDicomDir
726  * \brief  for each Header of the chained list, add/update the Patient/Study/Serie/Image info 
727  * @param   path path of the root directory
728  * @param   list chained list of Headers
729  */
730 void gdcmDicomDir::SetElements(std::string &path, ListHeader &list)
731 {
732    std::string patPrevName="",         patPrevID="";
733    std::string studPrevInstanceUID="", studPrevID="";
734    std::string serPrevInstanceUID="",  serPrevID="";
735
736    std::string patCurName,         patCurID;
737    std::string studCurInstanceUID, studCurID;
738    std::string serCurInstanceUID,  serCurID;
739
740    SetElement(path,GDCM_DICOMDIR_META,NULL);
741
742    ListTag::iterator debPat=listEntries.begin();
743    for(ListHeader::iterator it=list.begin();it!=list.end();++it) 
744    {
745       // get the current file characteristics
746       patCurName=        (*it)->GetEntryByNumber(0x0010,0x0010); 
747       patCurID=          (*it)->GetEntryByNumber(0x0010,0x0011); 
748       studCurInstanceUID=(*it)->GetEntryByNumber(0x0020,0x000d);            
749       studCurID=         (*it)->GetEntryByNumber(0x0020,0x0010);            
750       serCurInstanceUID= (*it)->GetEntryByNumber(0x0020,0x000e);            
751       serCurID=          (*it)->GetEntryByNumber(0x0020,0x0011);
752
753       if(patCurName!=patPrevName || patCurID!=patPrevID) 
754          SetElement(path,GDCM_DICOMDIR_PATIENT,*it);
755
756       // if new Study Deal with 'STUDY' Elements   
757       if(studCurInstanceUID!=studPrevInstanceUID || studCurID!=studPrevID) 
758          SetElement(path,GDCM_DICOMDIR_STUDY,*it);
759
760       // if new Serie Deal with 'SERIE' Elements   
761       if(serCurInstanceUID!=serPrevInstanceUID || serCurID!=serPrevID) 
762          SetElement(path,GDCM_DICOMDIR_SERIE,*it);
763       
764       // Always Deal with 'IMAGE' Elements  
765       SetElement(path,GDCM_DICOMDIR_IMAGE,*it);
766
767       patPrevName=        patCurName;
768       patPrevID=          patCurID;
769       studPrevInstanceUID=studCurInstanceUID;
770       studPrevID=         studCurID;
771       serPrevInstanceUID= serCurInstanceUID;
772       serPrevID=          serCurID;
773    }
774 }
775
776 /*
777  * \ingroup gdcmDicomDir
778  * \brief   adds to the HTable and at the end of the Chained List
779  *          the gdcmEntries (Dicom Elements) corresponding to the given type
780  * @param   path full path file name(only used when type = GDCM_DICOMDIR_IMAGE
781  * @param   type gdcmObject type to create (GDCM_DICOMDIR_PATIENT, GDCM_DICOMDIR_STUDY, GDCM_DICOMDIR_SERIE ...)
782  * @param   header gdcmHeader of the current file
783  */
784 void gdcmDicomDir::SetElement(std::string &path,gdcmDicomDirType type,gdcmHeader *header)
785 {
786    std::list<gdcmElement> elemList;
787    std::list<gdcmElement>::iterator it;
788    guint16 tmpGr, tmpEl;
789    gdcmDictEntry *dictEntry;
790    gdcmHeaderEntry *entry;
791    std::string val;
792
793    switch(type)
794    {
795       case GDCM_DICOMDIR_PATIENT:
796          elemList=gdcmGlobal::GetDicomDirElements()->GetDicomDirPatientElements();
797          break;
798       case GDCM_DICOMDIR_STUDY:
799          elemList=gdcmGlobal::GetDicomDirElements()->GetDicomDirStudyElements();
800          break;
801       case GDCM_DICOMDIR_SERIE:
802          elemList=gdcmGlobal::GetDicomDirElements()->GetDicomDirSerieElements();
803          break;
804       case GDCM_DICOMDIR_IMAGE:
805          elemList=gdcmGlobal::GetDicomDirElements()->GetDicomDirImageElements();
806          break;
807       case GDCM_DICOMDIR_META:
808          elemList=gdcmGlobal::GetDicomDirElements()->GetDicomDirMetaElements();
809          break;
810       default:
811          return;
812    }
813
814    for(it=elemList.begin();it!=elemList.end();++it)
815    {
816       tmpGr=it->group;
817       tmpEl=it->elem;
818       dictEntry=GetPubDict()->GetDictEntryByNumber(tmpGr,tmpEl);
819       entry=new gdcmHeaderEntry(dictEntry);
820       entry->SetOffset(0); // just to avoid missprinting
821
822       if(header)
823          val=header->GetEntryByNumber(tmpGr,tmpEl);
824       else
825          val=GDCM_UNFOUND;
826
827       if(val==GDCM_UNFOUND) 
828       {
829          if((tmpGr==0x0004) &&(tmpEl==0x1130) ) // File-set ID
830          {       
831            // force to the *end* File Name
832            val=GetName(path);               
833          }
834          else if( (tmpGr==0x0004) && (tmpEl==0x1500) ) // Only used for image
835          {
836             if(header->GetFileName().substr(0,path.length())!=path)
837             {
838                dbg.Verbose(0, "gdcmDicomDir::SetElement : the base path of file name is incorrect");
839                val=header->GetFileName();
840             }
841             else {
842                val=&(header->GetFileName().c_str()[path.length()]);
843             }   
844          }
845          else
846          {
847             val=it->value;
848          }
849       } 
850       else
851       {
852          if (header->GetEntryLengthByNumber(tmpGr,tmpEl)== 0)
853             val=it->value;
854       }
855             
856       entry->SetValue(val);
857
858       if(dictEntry)
859       {
860          if(dictEntry->GetGroup()==0xfffe) 
861          {
862             entry->SetLength(entry->GetValue().length());        
863          }
864          else if( (dictEntry->GetVR()=="UL") || (dictEntry->GetVR()=="SL") ) 
865          {
866             entry->SetLength(4);
867          } 
868          else if( (dictEntry->GetVR()=="US") || (dictEntry->GetVR()=="SS") ) 
869          {
870             entry->SetLength(2); 
871          } 
872          else if(dictEntry->GetVR()=="SQ") 
873          {
874             entry->SetLength(0xffffffff);
875          }
876          else
877          {
878             entry->SetLength(entry->GetValue().length());        
879          }
880       }
881       //AddHeaderEntry(entry); // both in H Table and in chained list
882       tagHT.insert( PairHT( entry->GetKey(),entry) );
883       listEntries.push_back(entry);  
884       //wasUpdated = 1; // is private
885    }     
886 }
887
888 bool gdcmDicomDir::HeaderLessThan(gdcmHeader *header1,gdcmHeader *header2)
889 {
890    return(*header1<*header2);
891 }
892
893
894
895 void gdcmDicomDir::UpdateDirectoryRecordSequenceLength() {
896    int offset = 0;
897    ListTag::iterator it;
898    guint16 gr, el;
899    std::string vr;
900    for(it=listEntries.begin();it!=listEntries.end();++it) {
901       gr = (*it)->GetGroup();
902       el = (*it)->GetElement();
903       vr = (*it)->GetVR();      
904       if (gr !=0xfffe) {
905          if ( (vr == "OB") || (vr == "OW") || (vr == "SQ") ) {    
906             offset +=  4; // explicit VR AND OB, OW, SQ : 4 more bytes
907          }         
908          offset += 2 + 2 + 4 + (*it)->GetLength(); 
909       } else {
910          offset +=  4; // delimiters don't have a value.     
911       }            
912    }   
913    bool res=SetEntryLengthByNumber(offset, 0x0004, 0x1220); // Hope there is no dupps.
914    return;
915 }
916
917 //-----------------------------------------------------------------------------