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