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