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