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