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